Créer votre premier service ZOO

Introduction

Dans cette partie, nous allons créer et publier un service ZOO simple appelé Hello qui retournera simplement un message hello contenant la valeur d’entrée fournie. Il sera utile pour présenter plus en détails les concepts généraux de fonctionnement du ZOO-Kernel et du traitement des demandes.

Service et vue d’ensemble du processus de publication

Avant de commencer à développer un service ZOO, vous devriez vous rappeler que dans le ZOO-projet, un service est un couple composé de:

  • un fichier de métadonnées : un fichier de configuration de service ZOO (ZCFG) contenant des informations de métadonnées sur un service (fournissant des informations sur les entrées et sorties par défaut / supportées pour un service)
  • un fournisseur de services: il dépend du langage de programmation utilisé, mais pour Python c’est un module et pour JavaScript un fichier de script.

Pour publier votre service, ce qui signifie rendre votre Kernel ZOO conscient de sa présence, vous devez copier un fichier ZCFG dans le répertoire où zoo_loader.cgi est situé (dans ce workshop, /usr/lib/cgi-bin) ou dans un sous-répertoire.

Warning

seul le fichier ZCFG est requis pour que le service soit considéré comme disponible. Donc, si vous n’avez pas le fournisseur de services, ce qui est le cas ici, une requête Execute échouerait comme nous le verrons plus tard.

Avant la publication, vous devriez stocker votre travail en cours, ainsi, nous allons commencer par créer un répertoire pour stocker les fichiers de votre fournisseur de services :

mkdir -p /home/user/ws_sp/

Une fois que le ZCFG et le module Python sont tous deux prêts, vous pouvez publier simplement en copiant les fichiers correspondants dans le même répertoire que le ZOO-Kernel ou un sous-répertoire.

Créons notre premier fichier ZCFG

Nous allons commencer par créer le fichier ZCFG pour le service Hello. Créez le fichier /home/user/ws_sp/Hello.zcfg et ajoutez-y le contenu suivant:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[Hello]
 Title = Return a hello message.
 Abstract = Create a welcome string.
 processVersion = 2
 storeSupported = true
 statusSupported = true
 serviceProvider = test_service
 serviceType = Python
 <DataInputs>
  [name]
   Title = Input string
   Abstract = The string to insert in the hello message.
   minOccurs = 1
   maxOccurs = 1
   <LiteralData>
       dataType = string
       <Default />
   </LiteralData>
 </DataInputs>
 <DataOutputs>
  [Result]
   Title = The resulting string
   Abstract = The hello message containing the input string
   <LiteralData>
       dataType = string
       <Default />
   </LiteralData>
 </DataOutputs>

Note

le nom du fichier ZCFG et le nom entre crochets (ici [Hello]) doivent être les mêmes et correspondre au nom de la fonction que nous avons définie dans notre fournisseur de services.

Comme vous pouvez le voir dans le fichier de configuration du service ZOO présenté ci-dessus, il est divisé en trois sections distinctes:

  1. Information de métadonnée principale (de la ligne 2 à 8)
  2. Liste des Informations de métadonnée en entrée (de la ligne 9 à 19)
  3. Liste des Informations de métadonnée en sortie (de la ligne 20 à 28)

Vous pouvez obtenir plus d’informations sur le ZCFG depuis la documentation de référence.

Si vous copiez le fichier Hello.zcfg dans le même répertoire que votre ZOO-Kernel alors vous serez en mesure d’interroger DescribeProcess en utilisant l’Identifier de Hello. Le service Hello devrait également être listé dans le document de “Capabilities”.

Tester les requêtes

Dans cette section, vous testerez chaque requête WPS: GetCapabilities, DescribeProcess et Execute. Notez que seuls les GetCapabilities et DescribeProcess devraient fonctionner à cette étape.

Tester la requête GetCapabilities

Si vous lancez la requête GetCapabilities :

http://localhost/cgi-bin/zoo_loader.cgi?request=GetCapabilities&service=WPS

Maintenant, vous devriez trouver votre service dans un noeud Process dans ProcessOfferings:

<wps:Process wps:processVersion="2">
 <ows:Identifier>Hello</ows:Identifier>
 <ows:Title>Return a hello message.</ows:Title>
 <ows:Abstract>Create a welcome string.</ows:Abstract>
</wps:Process>

Tester la requête DescribeProcess

Vous pouvez accéder au ProcessDescription du service Hello en utilisant la requête DescribeProcess ci-dessous :

http://localhost/cgi-bin/zoo_loader.cgi?request=DescribeProcess&service=WPS&version=1.0.0&Identifier=Hello

Vous devriez obtenir la réponse suivante :

<wps:ProcessDescriptions xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsDescribeProcess_response.xsd" service="WPS" version="1.0.0" xml:lang="en-US">
  <ProcessDescription wps:processVersion="2" storeSupported="true" statusSupported="true">
    <ows:Identifier>Hello</ows:Identifier>
    <ows:Title>Return a hello message.</ows:Title>
    <ows:Abstract>Create a welcome string.</ows:Abstract>
    <DataInputs>
      <Input minOccurs="1" maxOccurs="1">
        <ows:Identifier>name</ows:Identifier>
        <ows:Title>Input string</ows:Title>
        <ows:Abstract>The string to insert in the hello message.</ows:Abstract>
        <LiteralData>
          <ows:DataType ows:reference="http://www.w3.org/TR/xmlschema-2/#string">string</ows:DataType>
          <ows:AnyValue/>
        </LiteralData>
      </Input>
    </DataInputs>
    <ProcessOutputs>
      <Output>
        <ows:Identifier>Result</ows:Identifier>
        <ows:Title>The resulting string</ows:Title>
        <ows:Abstract>The hello message containing the input string</ows:Abstract>
        <LiteralOutput>
          <ows:DataType ows:reference="http://www.w3.org/TR/xmlschema-2/#string">string</ows:DataType>
        </LiteralOutput>
      </Output>
    </ProcessOutputs>
  </ProcessDescription>
</wps:ProcessDescriptions>

Tester la requête Execute

Bien entendu, vous ne pouvez pas encore exécuter votre service car le fichier Python n’a pas été publié. Si vous essayez la requête Execute suivante:

http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto

Vous devriez obtenir un ExceptionReport comme présenté ci-dessous, ce qui est un comportement normal:

<ows:ExceptionReport xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/owsExceptionReport.xsd" xml:lang="en-US" version="1.1.0">
  <ows:Exception exceptionCode="NoApplicableCode">
    <ows:ExceptionText>Python module test_service cannot be loaded.</ows:ExceptionText>
  </ows:Exception>
</ows:ExceptionReport>

Implémentez le Service Python

Principes généraux

La chose la plus importante que vous devez savoir quand vous implémentez un nouveau ZOO-Services en utilisant le langage Python est que la fonction correspondant à votre service retourne une valeur entière qui représente l’état d’exécution (SERVICE_FAILED [1] ou SERVICE_SUCCEEDED [2]) et prend trois arguments (dictionnaires Python):

  • conf : la configuration de l’environnement principal (correspondant au contenu de main.cfg)
  • inputs : les entrées demandées / par défaut (utilisées pour accéder aux valeurs d’entrée)
  • outputs : les sorties demandées / par défaut (utilisées pour stocker le résultat de traitement)

Note

quand votre service retourne SERVICE_FAILED` vous pouvez définir conf[“lenv”][“message”] pour ajouter un message personnalisé dans l’ExceptionReport retourné par le ZOO-Kernel dans ce cas.

Dans ce qui suit, vous trouverez la structure conf exemple basée sur le fichier main.cfg que vous avez vu précédemment.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
  "main": {
    language: "en-US",
    lang: "fr-FR,ja-JP",
    version: "1.0.0",
    encoding: "utf-8",
    serverAddress: "http://localhost/cgi-bin/zoo_loader.cgi",
    dataPath: "/var/www/zoows-demo/map/data",
    tmpPath: "/var/www/temp",
    tmpUrl: "../temp",
    cacheDir: "/var/www/cache/"
  },
  "identification": {
    title: "Atelier ZOO-Project - FOSS4G-FR 2014",
    keywords: "WPS,GIS,buffer",
    abstract: "Création d'une application web de recherche de plus courts chemins basée sur la norme WPS",
    accessConstraints: "none",
    fees: "None"
  },
  "provider": {
    positionName: "Developer",
    providerName: "ZOO-Project",
    addressAdministrativeArea: "Lattes",
    addressCountry: "fr",
    phoneVoice: "False",
    addressPostalCode: "34970",
    role: "Dev",
    providerSite: "http://www.zoo-project.org",
    phoneFacsimile: "False",
    addressElectronicMailAddress: "gerald.fenoy@geolabs.fr",
    addressCity: "Denver",
    individualName: "Gérald FENOY"
  }

Dans ce qui suit, vous obtenez une valeur de sortie exemple passée à un service Python ou JavaScript:

1
2
3
4
5
6
7
{
  'Result': {
    'mimeType': 'application/json',
    'inRequest': 'true',
    'encoding': 'UTF-8'
  }
}

Note

la valeur inRequest est définie en interne par le ZOO-Kernel et peut être utilisée pour déterminer depuis le service si la clé a été fournie dans la requête.

Le ZOO-project fournit une API ZOO qui était à l’origine uniquement disponible pour les services en JavaScript, mais grâce au travail de la communauté ZOO-project, maintenant vous avez aussi accès à une ZOO-API utilisant le langage Python. Grâce à l’API ZOO Python, vous n’avez plus à retenir la valeur de SERVICE_SUCCEDED et SERVICE_FAILED, vous avez la capacité de traduire n’importe quelle chaîne depuis votre service Python en appelant la fonction _ (ex: zoo._('Ma chaine a traduire')) ou de mettre à jour le statut actuel d’un service en cours d’exécution, en utilisant la fonction update_status de la même manière que vous l’utilisez depuis des services C ou JavaScript.

Le Service Hello

Vous pouvez copier / coller ce qui suit dans le fichier /home/user/ws_sp/test_service.py.

import zoo
def Hello(conf,inputs,outputs):
    outputs["Result"]["value"]=\
            "Hello "+inputs["name"]["value"]+" from the ZOO-Project Python world !"
    return zoo.SERVICE_SUCCEEDED

Une fois que vous aurez fini l’édition du fichier, vous devriez le copier dans le répertoire /usr/lib/cgi-bin :

sudo cp /home/user/ws_sp/* /usr/lib/cgi-bin

Interagir avec votre service en utilisant des requêtes Execute

Maintenant, vous pouvez utiliser une requête Execute en utilisant l’url de base suivante:

http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto

Vous pouvez interroger le serveur WPS pour retourner une réponse WPS XML contenant le résultat de votre calcul, en demandant un ResponseDocument (le cas par défaut) ou vous pouvez accéder aux données directement en demandant un RawDataOutput.

  • Requête exemple utilisant le paramètre RawDataOutput:
http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto&RawDataOutput=Result
  • Requête exemple utilisant le paramètre par défaut ResponseDocument:
http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto&ResponseDocument=Result

Lorsque vous utilisez ResponseDocument, il y a un attribut spécifique que vous pouvez utiliser pour demander au ZOO-Kernel de stocker le résultat : asReference. Vous pouvez l’utiliser come ceci :

http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto&ResponseDocument=Result@asReference=true

Lorsque le traitement prend du temps, le client doit demander l’exécution d’un service en mettant à la fois les paramètres storeExecuteResponse et status à true pour forcer une exécution asynchrone. Cela fera retourner au ZOO-Kernel, sans attendre l’achèvement de l’exécution du service, mais après le début d’un autre processus ZOO-Kernel responsable de l’exécution du service, un ResponseDocument contenant un attribut statusLocation qui peut être utilisé pour accéder au statut d’un service en cours ou le résultat lorsque le processus a pris fin [3].

http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Hello&DataInputs=name=toto&ResponseDocument=Result&storeExecuteResponse=true&status=true

Vous pouvez invoquer l’exécution du service longProcess de la même manière (exécution asynchrone) afin de constater ce qu’il se passe lors de l’exécution de service réellement long à s’exécuter. Vous constaterez l’évolution du poucentage de complétude de l’exécution d’un service ainsi que le message associé.

Conclusion

Bien que ce premier service soit vraiment simple, il a été utilisé afin d’illustrer comment le ZOO-Kernel remplit les paramètres conf, inputs et outputs avant de charger et d’exécuter la fonction de votre service, comment écrire un fichier ZCFG, comment publier un fournisseur de services en plaçant le ZCFG et les fichiers Python dans le même répertoire que le ZOO-Kernel, et ensuite comment interragir avec votre service en utilisant à la fois les requêtes GetCapabilities, DescribeProcess et Execute. Nous verrons dans la section suivante comment écrire des requêtes similaires en utilisant la syntaxe XML.

Footnotes

[1]SERVICE_FAILED=4
[2]SERVICE_SUCCEEDED=3
[3]Pour obtenir l’url de statut en cours dans statusLocation, vous aurez besoin d’installer le service utils/status. Si vous n’avez pas ce service disponible, le ZOO-Kernel donnera simplement l’URL d’un fichier XML plat stockée sur le serveur qui contiendra, à la fin de l’exécution, le résultat de l’exécution du service.