source: trunk/zoo-project/zoo-kernel/service_json.c @ 951

Last change on this file since 951 was 949, checked in by djay, 5 years ago

Prototype implementation of the OGC API - Processing and other simplifications

  • Property svn:keywords set to Id
File size: 60.4 KB
Line 
1/*
2 * Author : Gérald FENOY
3 *
4 *  Copyright 2017-2019 GeoLabs SARL. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include "service_json.h"
26#include "json.h"
27#include <errno.h>
28#include "json_tokener.h"
29#include "stdlib.h"
30#include "mimetypes.h"
31#include "server_internal.h"
32#include "service_internal.h"
33#include <dirent.h>
34
35#ifdef __cplusplus
36extern "C" {
37#endif
38  /**
39   * Equivalent range keywords for WPS version 1 and 2
40   */
41  const char* rangeCorrespondances[4][2]={
42    { "rangeMin", "minimumValue" },
43    { "rangeMax", "maximumValue"},
44    { "rangeSpacing", "spacing" }, 
45    { "rangeClosure", "rangeClosure" }
46  };
47 
48
49  /**
50   * Convert a map to a json object
51   * @param myMap the map to be converted into json object
52   * @return a json_object pointer to the created json_object
53   */
54  json_object* mapToJson(map* myMap){
55    json_object *res=json_object_new_object();
56    map* cursor=myMap;
57    map* sizeMap=getMap(myMap,"size");
58    map* length=getMap(myMap,"length");
59    while(cursor!=NULL){
60      json_object *val=NULL;
61      if(length==NULL && sizeMap==NULL)
62        val=json_object_new_string(cursor->value);
63      else{
64        if(length==NULL && sizeMap!=NULL){
65          if(strncasecmp(cursor->name,"value",5)==0)
66            val=json_object_new_string_len(cursor->value,atoi(sizeMap->value));
67          else
68            val=json_object_new_string(cursor->value);
69        }
70        else{
71          // In other case we should consider array with potential sizes
72          int limit=atoi(length->value);
73          int i=0;
74          val=json_object_new_array();
75          for(i=0;i<limit;i++){
76            map* lsizeMap=getMapArray(myMap,"size",i);
77            if(lsizeMap!=NULL && strncasecmp(cursor->name,"value",5)==0){
78              json_object_array_add(val,json_object_new_string_len(cursor->value,atoi(sizeMap->value)));
79            }else{
80              json_object_array_add(val,json_object_new_string(cursor->value));
81            }
82          }
83        }
84      }
85      if(val!=NULL)
86        json_object_object_add(res,cursor->name,val);
87      cursor=cursor->next;
88    }
89    return res;
90  }
91
92  /**
93   * Convert a maps to a json object
94   * @param myMap the maps to be converted into json object
95   * @return a json_object pointer to the created json_object
96   */
97  json_object* mapsToJson(maps* myMap){
98    json_object *res=json_object_new_object();
99    maps* cursor=myMap;
100    while(cursor!=NULL){
101      json_object *obj=NULL;
102      if(cursor->content!=NULL){
103        obj=mapToJson(cursor->content);
104      }else
105        obj=json_object_new_object();
106      if(cursor->child!=NULL){
107        json_object *child=NULL;
108        child=mapsToJson(cursor->child);
109        json_object_object_add(obj,"child",child);
110      }
111      json_object_object_add(res,cursor->name,obj);
112      cursor=cursor->next;
113    }
114    return res;
115  }
116
117  /**
118   * Convert an elements to a json object
119   * @param myElements the elements pointer to be converted into a json object
120   * @return a json_object pointer to the created json_object
121   */
122  json_object* elementsToJson(elements* myElements){
123    json_object *res=json_object_new_object();
124    elements* cur=myElements;
125    while(cur!=NULL){
126      json_object *cres=json_object_new_object();
127      json_object_object_add(cres,"content",mapToJson(cur->content));
128      json_object_object_add(cres,"metadata",mapToJson(cur->metadata));
129      json_object_object_add(cres,"additional_parameters",mapToJson(cur->additional_parameters));
130      if(cur->format!=NULL){
131        json_object_object_add(cres,"format",json_object_new_string(cur->format));
132      }
133      if(cur->child==NULL){
134        if(cur->defaults!=NULL)
135          json_object_object_add(cres,"defaults",mapToJson(cur->defaults->content));
136        else
137          json_object_object_add(cres,"defaults",mapToJson(NULL));
138        iotype* scur=cur->supported;
139        json_object *resi=json_object_new_array();
140        while(scur!=NULL){
141          json_object_array_add(resi,mapToJson(scur->content));
142          scur=scur->next;
143        }
144        json_object_object_add(cres,"supported",resi);
145      }
146     
147      json_object_object_add(cres,"child",elementsToJson(cur->child));
148
149      json_object_object_add(res,cur->name,cres);
150      cur=cur->next;
151    }
152    return res;
153  }
154 
155  /**
156   * Convert an service to a json object
157   * @param myService the service pointer to be converted into a json object
158   * @return a json_object pointer to the created json_object
159   */
160  json_object* serviceToJson(service* myService){
161    json_object *res=json_object_new_object();
162    json_object_object_add(res,"name",json_object_new_string(myService->name));
163    json_object_object_add(res,"content",mapToJson(myService->content));
164    json_object_object_add(res,"metadata",mapToJson(myService->metadata));
165    json_object_object_add(res,"additional_parameters",mapToJson(myService->additional_parameters));
166    json_object_object_add(res,"inputs",elementsToJson(myService->inputs));
167    json_object_object_add(res,"outputs",elementsToJson(myService->outputs));
168    return res;
169  }
170
171  /**
172   * Add Allowed Range properties to a json_object
173   * @param m the main configuration maps pointer
174   * @param iot the iotype pointer
175   * @param prop the json_object pointer to add the allowed range properties
176   * @return a json_object pointer to the created json_object
177   */
178  void printAllowedRangesJ(maps* m,iotype* iot,json_object* prop){
179    map* tmpMap1;
180    json_object* prop4=json_object_new_object();
181    for(int i=0;i<4;i++){
182      tmpMap1=getMap(iot->content,rangeCorrespondances[i][0]);
183      if(tmpMap1!=NULL){
184        if(i<3)
185          json_object_object_add(prop4,rangeCorrespondances[i][1],json_object_new_string(tmpMap1->value));
186        else{
187          char* currentValue=NULL;
188          int limit=strlen(tmpMap1->value);
189          for(int j=0;j<limit;j++){
190            const char* tmpS="closed";
191            if(tmpMap1->value[j]=='o'){
192              tmpS="open";
193            }
194            if(currentValue==NULL){
195              currentValue=(char*)malloc((strlen(tmpS)+1)*sizeof(char));
196              sprintf(currentValue,"%s",tmpS);
197            }else{
198              char* tmpS1=zStrdup(currentValue);
199              currentValue=(char*)realloc(currentValue,(strlen(tmpS1)+strlen(tmpS)+2)*sizeof(char));
200              sprintf(currentValue,"%s-%s",tmpS1,tmpS);
201            }
202          }           
203          json_object_object_add(prop4,rangeCorrespondances[i][1],json_object_new_string(currentValue));
204        }
205      }
206    }
207    json_object_array_add(prop,prop4);
208  }
209 
210  /**
211   * Add literalDataDomains property to a json_object
212   * @param m the main configuration maps pointer
213   * @param in the elements pointer
214   * @param input the json_object pointer to add the literalDataDomains property
215   * @return a json_object pointer to the created json_object
216   */
217  void printLiteralDataJ(maps* m,elements* in,json_object* input){
218    json_object* prop0=json_object_new_array();
219    json_object* prop1=json_object_new_object();
220    json_object* prop2=json_object_new_object();
221    if(in->defaults!=NULL){
222      map* tmpMap1=getMap(in->defaults->content,"DataType");
223      if(tmpMap1!=NULL){
224        json_object_object_add(prop2,"name",json_object_new_string(tmpMap1->value));
225        json_object_object_add(prop1,"dataType",prop2);
226      }
227      tmpMap1=getMap(in->defaults->content,"value");
228      if(tmpMap1!=NULL)
229        json_object_object_add(prop1,"defaultValue",json_object_new_string(tmpMap1->value));
230      json_object* prop3=json_object_new_object();
231      tmpMap1=getMap(in->defaults->content,"rangeMin");
232      if(tmpMap1!=NULL){
233        json_object* prop5=json_object_new_array();
234        printAllowedRangesJ(m,in->defaults,prop5);
235        if(in->supported!=NULL){
236          iotype* iot=in->supported;
237          while(iot!=NULL){
238            printAllowedRangesJ(m,iot,prop5);
239            iot=iot->next;
240          }
241        }
242        json_object_object_add(prop3,"allowedRanges",prop5);
243      }
244      else{
245        tmpMap1=getMap(in->defaults->content,"range");
246        if(tmpMap1!=NULL){
247          // TODO: parse range = [rangeMin,rangeMax]
248        }else{ 
249          // AllowedValues
250          tmpMap1=getMap(in->defaults->content,"AllowedValues");
251          if(tmpMap1!=NULL){
252            char* saveptr;
253            json_object* prop5=json_object_new_array();
254            char *tmps = strtok_r (tmpMap1->value, ",", &saveptr);
255            while(tmps!=NULL){
256              json_object_array_add(prop5,json_object_new_string(tmps));
257              tmps = strtok_r (NULL, ",", &saveptr);
258            }
259            json_object_object_add(prop3,"allowedValues",prop5);
260           
261          }else{
262            json_object_object_add(prop3,"anyValue",json_object_new_boolean(true));
263          }
264        }
265      }
266      json_object_object_add(prop1,"valueDefinition",prop3);
267      json_object_array_add(prop0,prop1);
268    }
269    json_object_object_add(input,"literalDataDomains",prop0);
270  }
271
272  /**
273   * Add Format properties to a json_object
274   * @param m the main configuration maps pointer
275   * @param iot the current iotype pointer
276   * @param res the json_object pointer to add the properties to
277   * @param isDefault boolean specifying if the currrent iotype is default
278   * @param maxSize a map pointer to the maximumMegabytes param defined in the zcfg file for this input/output
279   */
280  void printFormatJ(maps* m,iotype* iot,json_object* res,bool isDefault,map* maxSize){
281    if(iot!=NULL){
282      map* tmpMap1=getMap(iot->content,"mimeType");
283      json_object* prop1=json_object_new_object();
284      json_object_object_add(prop1,"default",json_object_new_boolean(isDefault));
285      json_object_object_add(prop1,"mimeType",json_object_new_string(tmpMap1->value));
286      tmpMap1=getMap(iot->content,"encoding");
287      if(tmpMap1!=NULL)
288        json_object_object_add(prop1,"encoding",json_object_new_string(tmpMap1->value));
289      tmpMap1=getMap(iot->content,"schema");
290      if(tmpMap1!=NULL)
291        json_object_object_add(prop1,"schema",json_object_new_string(tmpMap1->value));
292      if(maxSize!=NULL)
293        json_object_object_add(prop1,"maximumMegabytes",json_object_new_int64(atoll(maxSize->value)));
294      json_object_array_add(res,prop1);
295    }
296  }
297
298  /**
299   * Add additionalParameters property to a json_object
300   * @param conf the main configuration maps pointer
301   * @param meta a map pointer to the current metadata informations
302   * @param doc the json_object pointer to add the property to
303   */
304  void printJAdditionalParameters(maps* conf,map* meta,json_object* doc){
305    map* cmeta=meta;
306    json_object* carr=json_object_new_array();
307    int hasElement=-1;
308    json_object* jcaps=json_object_new_object();
309    while(cmeta!=NULL){
310      json_object* jcmeta=json_object_new_object();
311      if(strcasecmp(cmeta->name,"role")!=0 &&
312         strcasecmp(cmeta->name,"href")!=0 &&
313         strcasecmp(cmeta->name,"title")!=0 &&
314         strcasecmp(cmeta->name,"length")!=0 ){
315        json_object_object_add(jcmeta,"name",json_object_new_string(cmeta->name));
316        json_object_object_add(jcmeta,"value",json_object_new_string(cmeta->value));
317        json_object_array_add(carr,jcmeta);
318        hasElement++;
319      }else{
320        if(strcasecmp(cmeta->name,"length")!=0)
321          json_object_object_add(jcaps,cmeta->name,json_object_new_string(cmeta->value));
322      }
323      cmeta=cmeta->next;
324    }
325    if(hasElement>=0){
326      json_object_object_add(jcaps,"additionalParameter",carr);
327      json_object_object_add(doc,"additionalParameters",jcaps);
328    }
329  }
330
331  /**
332   * Add metadata property to a json_object
333   * @param conf the main configuration maps pointer
334   * @param meta a map pointer to the current metadata informations
335   * @param doc the json_object pointer to add the property to
336   */
337  void printJMetadata(maps* conf,map* meta,json_object* doc){
338    map* cmeta=meta;
339    json_object* carr=json_object_new_array();
340    int hasElement=-1;
341    while(cmeta!=NULL){
342      json_object* jcmeta=json_object_new_object();
343      if(strcasecmp(cmeta->name,"role")==0 ||
344         strcasecmp(cmeta->name,"href")==0 ||
345         strcasecmp(cmeta->name,"title")==0 ){
346        json_object_object_add(jcmeta,cmeta->name,json_object_new_string(cmeta->value));
347        hasElement++;
348      }
349      json_object_array_add(carr,jcmeta);
350      cmeta=cmeta->next;
351    }
352    if(hasElement>=0)
353      json_object_object_add(doc,"metadata",carr);
354  }
355
356  /**
357   * Add metadata properties to a json_object
358   * @param m the main configuration maps pointer
359   * @param io a string
360   * @param in an elements pointer to the current input/output
361   * @param inputs the json_object pointer to add the property to
362   * @param serv the service pointer to extract the metadata from
363   */
364  void printIOTypeJ(maps* m, const char *io, elements* in,json_object* inputs,service* serv){
365    while(in!=NULL){
366      json_object* input=json_object_new_object();
367      json_object_object_add(input,"id",json_object_new_string(in->name));
368      map* tmpMap=getMap(in->content,"title");
369      if(tmpMap!=NULL)
370        json_object_object_add(input,"title",json_object_new_string(tmpMap->value));
371      tmpMap=getMap(in->content,"abstract");
372      if(tmpMap!=NULL)
373        json_object_object_add(input,"abstract",json_object_new_string(tmpMap->value));
374      if(strcmp(io,"input")==0){
375        tmpMap=getMap(in->content,"minOccurs");
376        if(tmpMap!=NULL)
377          json_object_object_add(input,"minOccurs",json_object_new_string(tmpMap->value));
378        tmpMap=getMap(in->content,"maxOccurs");
379        if(tmpMap!=NULL)
380          json_object_object_add(input,"maxOccurs",json_object_new_string(tmpMap->value));
381      }
382      if(in->format!=NULL){
383        json_object* input1=json_object_new_object();
384        json_object* prop0=json_object_new_array();
385        if(strcasecmp(in->format,"LiteralData")==0 ||
386           strcasecmp(in->format,"LiteralOutput")==0){
387          printLiteralDataJ(m,in,input1);
388        }else{
389          if(strcasecmp(in->format,"ComplexData")==0 ||
390             strcasecmp(in->format,"ComplexOutput")==0){
391            map* sizeMap=getMap(in->content,"maximumMegabytes");
392            printFormatJ(m,in->defaults,prop0,true,sizeMap);
393            iotype* sup=in->supported;
394            while(sup!=NULL){
395              printFormatJ(m,sup,prop0,false,sizeMap);
396              sup=sup->next;
397            }
398            json_object_object_add(input1,"formats",prop0);
399          }
400          else{
401            json_object* prop1=json_object_new_object();
402            json_object_object_add(prop1,"default",json_object_new_boolean(true));
403            map* tmpMap1=getMap(in->defaults->content,"crs");
404            if(tmpMap1==NULL)
405              return;
406            json_object_object_add(prop1,"crs",json_object_new_string(tmpMap1->value));
407            json_object_array_add(prop0,prop1);
408            iotype* sup=in->supported;
409            while(sup!=NULL){
410              json_object* prop1=json_object_new_object();
411              json_object_object_add(prop1,"default",json_object_new_boolean(false));
412              tmpMap1=getMap(sup->content,"crs");
413              json_object_object_add(prop1,"crs",json_object_new_string(tmpMap1->value));
414              json_object_array_add(prop0,prop1);
415              sup=sup->next;
416            }         
417            json_object_object_add(input1,"supportedCRS",prop0);
418          }
419        }
420        json_object_object_add(input,io,input1);
421      }
422      printJMetadata(m,in->metadata,input);
423      printJAdditionalParameters(m,in->additional_parameters,input);
424      json_object_array_add(inputs,input);     
425      in=in->next;
426    }
427   
428  }
429
430  /**
431   * Add all the capabilities properties to a json_object
432   * @param ref the registry pointer
433   * @param m the main configuration maps pointer
434   * @param doc0 the void (json_object) pointer to add the property to
435   * @param nc0 the void (json_object) pointer to add the property to
436   * @param serv the service pointer to extract the metadata from
437   */
438  void printGetCapabilitiesForProcessJ(registry *reg, maps* m,void* doc0,void* nc0,service* serv){
439    json_object* doc=(json_object*) doc0;
440    json_object* nc=(json_object*) nc0;
441    json_object *res=json_object_new_object();
442    map* tmpMap0=getMapFromMaps(m,"lenv","level");
443    char* rUrl=serv->name;
444    if(tmpMap0!=NULL && atoi(tmpMap0->value)>0){
445      int i=0;
446      maps* tmpMaps=getMaps(m,"lenv");
447      char* tmpName=NULL;
448      for(i=0;i<atoi(tmpMap0->value);i++){
449        char* key=(char*)malloc(15*sizeof(char));
450        sprintf(key,"sprefix_%d",i);
451        map* tmpMap1=getMap(tmpMaps->content,key);
452        if(i+1==atoi(tmpMap0->value))
453          if(tmpName==NULL){
454            tmpName=(char*) malloc((strlen(serv->name)+strlen(tmpMap1->value)+1)*sizeof(char));
455            sprintf(tmpName,"%s%s",tmpMap1->value,serv->name);
456          }else{
457            char* tmpStr=zStrdup(tmpName);
458            tmpName=(char*) realloc(tmpName,(strlen(tmpStr)+strlen(tmpMap1->value)+strlen(serv->name)+1)*sizeof(char));
459            sprintf(tmpName,"%s%s%s",tmpStr,tmpMap1->value,serv->name);
460            free(tmpStr);
461          }
462        else
463          if(tmpName==NULL){
464            tmpName=(char*) malloc((strlen(tmpMap1->value)+1)*sizeof(char));
465            sprintf(tmpName,"%s",tmpMap1->value);
466          }else{
467            char* tmpStr=zStrdup(tmpName);
468            tmpName=(char*) realloc(tmpName,(strlen(tmpStr)+strlen(tmpMap1->value)+1)*sizeof(char));
469            sprintf(tmpName,"%s%s",tmpStr,tmpMap1->value);
470            free(tmpStr);
471          }
472      }
473      json_object_object_add(res,"id",json_object_new_string(tmpName));
474      if(tmpName!=NULL){
475        rUrl=zStrdup(tmpName);
476        free(tmpName);
477      }
478    }
479    else
480      json_object_object_add(res,"id",json_object_new_string(serv->name));
481    if(serv->content!=NULL){
482      map* tmpMap=getMap(serv->content,"title");
483      if(tmpMap!=NULL){
484        json_object_object_add(res,"title",json_object_new_string(tmpMap->value));
485      }
486      tmpMap=getMap(serv->content,"abstract");
487      if(tmpMap!=NULL){
488        json_object_object_add(res,"abstract",json_object_new_string(tmpMap->value));
489      }
490      tmpMap=getMap(serv->content,"processVersion");
491      if(tmpMap!=NULL){
492        if(strlen(tmpMap->value)<5){
493          char *val=(char*)malloc((strlen(tmpMap->value)+5)*sizeof(char));
494          sprintf(val,"%s.0.0",tmpMap->value);
495          json_object_object_add(res,"version",json_object_new_string(val));
496          free(val);
497        }
498        else
499          json_object_object_add(res,"version",json_object_new_string(tmpMap->value));
500      }
501      int limit=4;
502      int i=0;
503      map* sType=getMap(serv->content,"serviceType");
504      for(;i<limit;i+=2){
505        json_object *res1=json_object_new_object();
506        json_object *res2=json_object_new_array();
507        char *saveptr;
508        char* dupStr=strdup(jcapabilities[i+1]);
509        char *tmps = strtok_r (dupStr, " ", &saveptr);
510        while(tmps!=NULL){
511          json_object_array_add(res2,json_object_new_string(tmps));
512          tmps = strtok_r (NULL, " ", &saveptr);
513        }
514        free(dupStr);
515        json_object_object_add(res,jcapabilities[i],res2);
516      }
517      json_object *res1=json_object_new_array();
518      json_object *res2=json_object_new_object();
519      json_object_object_add(res2,"rel",json_object_new_string("canonical"));
520      json_object_object_add(res2,"type",json_object_new_string("application/json"));
521      json_object_object_add(res2,"title",json_object_new_string("Process Description"));
522      map* tmpUrl=getMapFromMaps(m,"main","serverAddress");
523      char* tmpStr=(char*) malloc((strlen(tmpUrl->value)+strlen(rUrl)+13)*sizeof(char));
524      sprintf(tmpStr,"%s/processes/%s/",tmpUrl->value,rUrl);
525      if(doc==NULL){
526        json_object_object_add(res2,"title",json_object_new_string("Execute End Point"));
527        char* tmpStr1=zStrdup(tmpStr);
528        tmpStr=(char*) realloc(tmpStr,(strlen(tmpStr)+6)*sizeof(char));
529        sprintf(tmpStr,"%sjobs/",tmpStr1);
530        free(tmpStr1);
531      }
532      json_object_object_add(res2,"href",json_object_new_string(tmpStr));
533      free(tmpStr);
534      json_object_array_add(res1,res2);
535      json_object_object_add(res,"links",res1);
536    }
537    if(doc==NULL){
538      elements* in=serv->inputs;
539      json_object* inputs=json_object_new_array();
540      printIOTypeJ(m,"input",in,inputs,serv);
541      json_object_object_add(res,"inputs",inputs);
542
543      in=serv->outputs;
544      json_object* outputs=json_object_new_array();
545      printIOTypeJ(m,"output",in,outputs,serv);
546      json_object_object_add(res,"outputs",outputs);
547
548    }
549    if(strcmp(rUrl,serv->name)!=0)
550      free(rUrl);
551    if(doc!=NULL)
552      json_object_array_add(doc,res);
553    else
554      json_object_object_add(nc,"process",json_object_get(res));
555
556  }
557
558  /**
559   * Print an OWS ExceptionReport Document and HTTP headers (when required)
560   * depending on the code.
561   * Set hasPrinted value to true in the [lenv] section.
562   *
563   * @param m the maps containing the settings of the main.cfg file
564   * @param s the map containing the text,code,locator keys (or a map array of the same keys)
565   */
566  void printExceptionReportResponseJ(maps* m,map* s){
567    if(getMapFromMaps(m,"lenv","hasPrinted")!=NULL)
568      return;
569    int buffersize;
570    json_object *res=json_object_new_object();
571
572    maps* tmpMap=getMaps(m,"main");
573    const char *exceptionCode;
574   
575    map* tmp=getMap(s,"code");
576    if(tmp!=NULL){
577      if(strcmp(tmp->value,"OperationNotSupported")==0 ||
578         strcmp(tmp->value,"NoApplicableCode")==0)
579        exceptionCode="501 Not Implemented";
580      else
581        if(strcmp(tmp->value,"MissingParameterValue")==0 ||
582           strcmp(tmp->value,"InvalidUpdateSequence")==0 ||
583           strcmp(tmp->value,"OptionNotSupported")==0 ||
584           strcmp(tmp->value,"VersionNegotiationFailed")==0 ||
585           strcmp(tmp->value,"InvalidParameterValue")==0)
586          exceptionCode="400 Bad request";
587        else
588          if(strcmp(tmp->value,"NotFound")==0)
589            exceptionCode="404 Not Found";
590          else
591            exceptionCode="501 Internal Server Error";
592      json_object_object_add(res,"code",json_object_new_string(tmp->value));
593    }
594    else
595      exceptionCode="501 Internal Server Error";
596    printHeaders(m);
597
598    tmp=getMapFromMaps(m,"lenv","status_code");
599    if(tmp!=NULL)
600      exceptionCode=tmp->value;
601    if(m!=NULL){
602      map *tmpSid=getMapFromMaps(m,"lenv","sid");
603      if(tmpSid!=NULL){
604        if( getpid()==atoi(tmpSid->value) ){
605          printf("Status: %s\r\n\r\n",exceptionCode);
606        }
607      }
608      else{
609        printf("Status: %s\r\n\r\n",exceptionCode);
610      }
611    }else{
612      printf("Status: %s\r\n\r\n",exceptionCode);
613    }
614    tmp=getMap(s,"text");
615    if(tmp==NULL)
616      tmp=getMap(s,"message");
617    if(tmp==NULL)
618      tmp=getMapFromMaps(m,"lenv","message");
619    if(tmp!=NULL)
620      json_object_object_add(res,"description",json_object_new_string(tmp->value));
621    const char* jsonStr=json_object_to_json_string_ext(res,JSON_C_TO_STRING_PLAIN);
622    printf(jsonStr);
623    if(m!=NULL)
624      setMapInMaps(m,"lenv","hasPrinted","true");
625  }
626
627  /**
628   * Parse LiteralData value
629   * @param conf the maps containing the settings of the main.cfg file
630   * @param req json_object pointing to the input/output
631   * @param element
632   * @param output the maps to set current json structure
633   */
634  void parseJLiteral(maps* conf,json_object* req,elements* element,maps* output){
635    json_object* json_cinput=NULL;
636    if(json_object_object_get_ex(req,"value",&json_cinput)!=FALSE){
637      output->content=createMap("value",json_object_get_string(json_cinput));
638    }
639    const char* tmpStrs[2]={
640      "dataType",
641      "uom"
642    };
643    for(int i=0;i<2;i++)
644      if(json_object_object_get_ex(req,tmpStrs[i],&json_cinput)!=FALSE){
645        json_object* json_cinput1;
646        if(json_object_object_get_ex(json_cinput,"name",&json_cinput1)!=FALSE){
647          if(output->content==NULL)
648            output->content=createMap(tmpStrs[i],json_object_get_string(json_cinput1));
649          else
650            addToMap(output->content,tmpStrs[i],json_object_get_string(json_cinput1));
651        }
652        if(json_object_object_get_ex(json_cinput,"reference",&json_cinput1)!=FALSE){
653          if(output->content==NULL)
654            output->content=createMap(tmpStrs[i],json_object_get_string(json_cinput1));
655          else
656            addToMap(output->content,tmpStrs[i],json_object_get_string(json_cinput1));
657        }
658      }
659    if(json_object_object_get_ex(req,"transmissionMode",&json_cinput)!=FALSE){
660      if(output->content==NULL)
661        output->content=createMap("transmissionMode",json_object_get_string(json_cinput));
662      else
663        addToMap(output->content,"transmissionMode",json_object_get_string(json_cinput));
664    }
665  }
666
667  /**
668   * Parse ComplexData value
669   * @param conf the maps containing the settings of the main.cfg file
670   * @param req json_object pointing to the input/output
671   * @param element
672   * @param output the maps to set current json structure
673   * @param name the name of the request from http_requests
674   */
675  void parseJComplex(maps* conf,json_object* req,elements* element,maps* output,const char* name){
676    json_object* json_cinput=NULL;
677    if(json_object_object_get_ex(req,"value",&json_cinput)!=FALSE){
678      json_object* json_value=NULL;
679      if(json_object_object_get_ex(json_cinput,"inlineValue",&json_value)!=FALSE)
680        output->content=createMap("value",json_object_get_string(json_value));
681      else{
682        if(json_object_object_get_ex(json_cinput,"href",&json_value)!=FALSE){
683          output->content=createMap("xlink:href",json_object_get_string(json_value));
684          int len=0;
685          int createdStr=0;
686          char *tmpStr="url";
687          char *tmpStr1="input";
688          if(getMaps(conf,"http_requests")==NULL){
689            maps* tmpMaps=createMaps("http_requests");
690            tmpMaps->content=createMap("length","1");
691            addMapsToMaps(&conf,tmpMaps);
692            freeMaps(&tmpMaps);
693            free(tmpMaps);
694          }else{
695            map* tmpMap=getMapFromMaps(conf,"http_requests","length");
696            int len=atoi(tmpMap->value);
697            createdStr=1;
698            tmpStr=(char*) malloc((12)*sizeof(char));
699            sprintf(tmpStr,"%d",len+1);
700            setMapInMaps(conf,"http_requests","length",tmpStr);
701            sprintf(tmpStr,"url_%d",len);
702            tmpStr1=(char*) malloc((14)*sizeof(char));
703            sprintf(tmpStr1,"input_%d",len);
704          }
705          setMapInMaps(conf,"http_requests",tmpStr,json_object_get_string(json_value));
706          setMapInMaps(conf,"http_requests",tmpStr1,name);
707          if(createdStr>0){
708            free(tmpStr);
709            free(tmpStr1);
710          }
711        }
712      }
713    }
714    if(json_object_object_get_ex(req,"format",&json_cinput)!=FALSE){
715      json_object_object_foreach(json_cinput, key, val) {
716        if(output->content==NULL)
717          output->content=createMap(key,json_object_get_string(val));
718        else
719          addToMap(output->content,key,json_object_get_string(val));
720       
721      }
722    }
723    if(json_object_object_get_ex(req,"transmissionMode",&json_cinput)!=FALSE){
724      if(output->content==NULL)
725        output->content=createMap("transmissionMode",json_object_get_string(json_cinput));
726      else
727        addToMap(output->content,"transmissionMode",json_object_get_string(json_cinput));
728    }
729  }
730
731  /**
732   * Parse BoundingBox value
733   * @param conf the maps containing the settings of the main.cfg file
734   * @param req json_object pointing to the input/output
735   * @param element
736   * @param output the maps to set current json structure
737   */
738  void parseJBoundingBox(maps* conf,json_object* req,elements* element,maps* output){
739    json_object* json_cinput=NULL;
740    if(json_object_object_get_ex(req,"bbox",&json_cinput)!=FALSE){
741      output->content=createMap("value",json_object_get_string(json_cinput));
742    }
743    if(json_object_object_get_ex(req,"crs",&json_cinput)!=FALSE){
744      if(output->content==NULL)
745        output->content=createMap("crs",json_object_get_string(json_cinput));
746      else
747        addToMap(output->content,"crs","http://www.opengis.net/def/crs/OGC/1.3/CRS84");
748    }
749    char* tmpStrs[2]={
750      "lowerCorner",
751      "upperCorner"
752    };
753    for(int i=0;i<2;i++)
754      if(json_object_object_get_ex(req,tmpStrs[i],&json_cinput)!=FALSE){
755        if(output->content==NULL)
756          output->content=createMap(tmpStrs[i],json_object_get_string(json_cinput));
757        else
758          addToMap(output->content,tmpStrs[i],json_object_get_string(json_cinput));
759      }
760    if(json_object_object_get_ex(req,"transmissionMode",&json_cinput)!=FALSE){
761      if(output->content==NULL)
762        output->content=createMap("transmissionMode",json_object_get_string(json_cinput));
763      else
764        addToMap(output->content,"transmissionMode",json_object_get_string(json_cinput));
765    }
766  }
767
768  /**
769   * Parse inputs / outputs
770   * @param conf the maps containing the settings of the main.cfg file
771   * @param req json_object pointing to the input/output
772   * @param ioElements the elements extracted from the zcfg
773   * @param ioMaps the produced maps containing inputs (or outputs)
774   * @param ioType the char* set to inputs or outputs
775   */
776  void parseJIO(maps* conf, json_object* req, elements* ioElements, maps** ioMaps,const char* ioType){
777    json_object* json_io=NULL;
778    if(json_object_object_get_ex(req,ioType,&json_io)!=FALSE){     
779      json_object* json_current_io=NULL;
780      size_t len=json_object_array_length(json_io);
781      for(int i=0;i<len;i++){
782        maps *cMaps=NULL;
783        json_current_io=json_object_array_get_idx(json_io,i);
784        json_object* cname=NULL;
785        if(json_object_object_get_ex(json_current_io,"id",&cname)!=FALSE){
786          cMaps=createMaps(json_object_get_string(cname));
787          elements* cio=getElements(ioElements,json_object_get_string(cname));
788          json_object* json_input;
789          json_object* json_cinput;
790          if(json_object_object_get_ex(json_current_io,"input",&json_input)!=FALSE){
791            if(json_object_object_get_ex(json_input,"dataType",&json_cinput)!=FALSE){
792              parseJLiteral(conf,json_input,cio,cMaps);
793            } else if(json_object_object_get_ex(json_input,"format",&json_cinput)!=FALSE){
794              parseJComplex(conf,json_input,cio,cMaps,json_object_get_string(cname));
795            } else if(json_object_object_get_ex(json_input,"bbox",&json_cinput)!=FALSE){
796              parseJBoundingBox(conf,json_input,cio,cMaps);
797            }// else error!
798            else{
799              if(json_object_object_get_ex(json_input,"value",&json_cinput)!=FALSE){
800                map* error=createMap("code","BadRequest");
801                char tmpS[1024];
802                sprintf(tmpS,_("Missing input for %s"),ioElements->name);
803                addToMap(error,"message",tmpS);
804                setMapInMaps(conf,"lenv","status_code","400 Bad Request");
805                printExceptionReportResponseJ(conf,error);
806                return;
807              }else{
808                if(json_object_get_type(json_cinput)==json_type_string){
809                  parseJLiteral(conf,json_input,cio,cMaps);
810                }else if(json_object_get_type(json_cinput)==json_type_object){
811                  json_object* json_ccinput=NULL;
812                  if(json_object_object_get_ex(json_cinput,"bbox",&json_ccinput)!=FALSE){
813                    parseJComplex(conf,json_input,cio,cMaps,json_object_get_string(cname));
814                  }
815                  else{
816                    parseJBoundingBox(conf,json_input,cio,cMaps);
817                  }
818                }else{
819                  if(strcmp(ioType,"input")==0){
820                    map* error=createMap("code","BadRequest");
821                    char tmpS1[1024];
822                    sprintf(tmpS1,_("Issue with input %s"),ioElements->name);
823                    addToMap(error,"message",tmpS1);
824                    setMapInMaps(conf,"lenv","status_code","400 Bad Request");
825                    printExceptionReportResponseJ(conf,error);
826                    return;
827                  }
828                }
829              }
830            }
831          }else{
832            if(strcmp(ioType,"input")==0){
833              map* error=createMap("code","BadRequest");
834              char tmpS1[1024];
835              sprintf(tmpS1,_("Missing input for %s"),ioElements->name);
836              addToMap(error,"message",tmpS1);
837              setMapInMaps(conf,"lenv","status_code","400 Bad Request");
838              printExceptionReportResponseJ(conf,error);
839              return;
840            }else{
841              // Outputs
842              if(json_object_object_get_ex(json_current_io,"transmissionMode",&json_cinput)!=FALSE){
843                if(cMaps->content==NULL)
844                  cMaps->content=createMap("transmissionMode",json_object_get_string(json_cinput));
845                else
846                  addToMap(cMaps->content,"transmissionMode",json_object_get_string(json_cinput));
847              }
848              if(json_object_object_get_ex(json_current_io,"format",&json_cinput)!=FALSE){
849                json_object_object_foreach(json_cinput, key, val) {
850                  if(cMaps->content==NULL)
851                    cMaps->content=createMap(key,json_object_get_string(val));
852                  else
853                    addToMap(cMaps->content,key,json_object_get_string(val));
854                }
855              }       
856            }
857          }
858        }
859        addToMap(cMaps->content,"inRequest","true");
860        if (ioMaps == NULL)
861          *ioMaps = dupMaps(&cMaps);
862        else
863          addMapsToMaps (ioMaps, cMaps);
864      }
865    }
866  }
867   
868     
869 
870  /**
871   * Parse Json Request
872   * @param conf the maps containing the settings of the main.cfg file
873   * @param s the current service metadata
874   * @param req the JSON object of the request body
875   * @param inputs the produced maps
876   * @param outputs the produced maps
877   */
878  void parseJRequest(maps* conf, service* s,json_object* req,maps** inputs,maps** outputs){
879    elements* io=s->inputs;
880
881    json_object* json_io=NULL;
882    int parsed=0;
883    char* tmpS="input";
884    maps* in=*inputs;
885    parseJIO(conf,req,s->inputs,inputs,"inputs");
886
887    if(parsed==0){
888      json_io=NULL;
889      if(json_object_object_get_ex(req,"outputs",&json_io)!=FALSE){
890        parseJIO(conf,req,s->outputs,outputs,"outputs");
891      }
892    }     
893  }
894
895  /**
896   * Print the jobs list
897   *
898   * @param conf the maps containing the settings of the main.cfg file
899   * @return the JSON object pointer to the jobs list
900   */
901  json_object* printJobList(maps* conf){
902    json_object* res=json_object_new_array();
903    map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
904    map* oIdentifier=getMapFromMaps(conf,"lenv","oIdentifier");
905    char* cpath=(char*)malloc((strlen(tmpPath->value)+strlen(oIdentifier->value)+14)*sizeof(char));
906    sprintf(cpath,"%s/statusInfos/%s",tmpPath->value,oIdentifier->value);
907    struct dirent *dp;
908    DIR *dirp = opendir (cpath);
909    if(dirp!=NULL){
910      while ((dp = readdir (dirp)) != NULL){
911        char* extn = strstr(dp->d_name, ".json");
912        if(extn!=NULL){
913          json_object* cjob=json_object_new_object();
914          char* tmpStr=zStrdup(dp->d_name);
915          tmpStr[strlen(dp->d_name)-5]=0;
916          json_object_object_add(cjob,"id",json_object_new_string(tmpStr));
917          char *tmps1=(char*)malloc((strlen(cpath)+strlen(dp->d_name)+2)*sizeof(char));
918          sprintf (tmps1, "%s/%s", cpath, dp->d_name);
919          FILE* cdat=fopen(tmps1,"rb");
920          if(cdat!=NULL){
921            zStatStruct f_status;
922            int s=zStat(tmps1, &f_status);
923            char* mystring=(char*)malloc((f_status.st_size+1)*sizeof(char));
924            fread(mystring,1,f_status.st_size,cdat);
925            mystring[f_status.st_size]=0;           
926            json_object *jobj = NULL;
927            int slen = 0;
928            enum json_tokener_error jerr;
929            struct json_tokener* tok=json_tokener_new();
930            do {
931              slen = strlen(mystring);
932              jobj = json_tokener_parse_ex(tok, mystring, slen);
933            } while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue);
934            if (jerr != json_tokener_success) {
935              fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr));
936              return res;
937            }
938            if (tok->char_offset < slen){
939              return res;
940            }
941            json_object_object_add(cjob,"infos",jobj);
942            free(mystring);
943            fclose(cdat);
944          }
945          free(tmpStr);
946          json_object_array_add(res,cjob);
947        }
948      }
949      closedir (dirp);
950    }
951    return res;
952  }
953
954  /**
955   * Print the result of an execution
956   *
957   * @param conf the maps containing the settings of the main.cfg file
958   * @param s service pointer to metadata
959   * @param result outputs of the service
960   * @param res the status of executino SERVICE_FAILED/SERVICE_SUCCEEDED
961   * @return the JSON object pointer to the result
962   */
963  json_object* printJResult(maps* conf,service* s,maps* result,int res){
964    printHeaders(conf);
965    json_object* eres1=json_object_new_object();
966    json_object* eres=json_object_new_array();
967    maps* resu=result;
968    int itn=0;
969    while(resu!=NULL){
970      json_object* res1=json_object_new_object();
971      json_object_object_add(res1,"id",json_object_new_string(resu->name));
972      map* tmpMap=NULL;
973      if((tmpMap=getMap(resu->content,"value"))!=NULL ||
974         (getMap(resu->content,"generated_file"))!=NULL){
975        json_object* res2=json_object_new_object();
976        map* tmpMap1=NULL;
977        if((tmpMap1=getMap(resu->content,"transmissionMode"))!=NULL) {
978          if(strcmp(tmpMap1->value,"value")==0) {
979            map* tmpMap2=getMap(resu->content,"mimeType");
980            if(tmpMap2!=NULL && strstr(tmpMap2->value,"json")!=NULL){
981              json_object *jobj = NULL;
982              int slen = 0;
983              enum json_tokener_error jerr;
984              struct json_tokener* tok=json_tokener_new();
985              do {
986                slen = strlen(tmpMap->value);
987                jobj = json_tokener_parse_ex(tok, tmpMap->value, slen);
988              } while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue);
989              if (jerr != json_tokener_success) {
990                fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr));
991                return eres1;
992              }
993              if (tok->char_offset < slen){
994                return eres1;           
995              }
996              json_object_object_add(res2,"inlineValue",jobj);
997            }else
998              json_object_object_add(res2,"inlineValue",json_object_new_string(tmpMap->value));
999          }
1000          else{
1001            // Create file for reference data if not existing
1002            map *gfile=getMap(resu->content,"generated_file");
1003            char *file_name=NULL;
1004            char *file_path=NULL;
1005            char *file_url=NULL;
1006            map *tmp1=getMapFromMaps(conf,"main","tmpPath");
1007            if(gfile!=NULL){
1008              gfile=getMap(resu->content,"expected_generated_file");
1009              if(gfile==NULL){
1010                gfile=getMap(resu->content,"generated_file");
1011              }
1012              if(strstr(gfile->value,tmp1->value)!=NULL)
1013                file_name=zStrdup(strstr(gfile->value,tmp1->value)+strlen(tmp1->value));
1014            }/*else*/
1015            {
1016              // Create file for reference data
1017              map *tmpUrl=getMapFromMaps(conf,"main","tmpUrl");
1018              map *usid=getMapFromMaps(conf,"lenv","usid");
1019              map *ext=getMap(resu->content,"extension");
1020              if(gfile==NULL){
1021                char file_ext[32];         
1022                if( ext != NULL && ext->value != NULL) {
1023                  strncpy(file_ext, ext->value, 32);
1024                }
1025                else {
1026                  // Obtain default file extension (see mimetypes.h).         
1027                  // If the MIME type is not recognized, txt is used as the default extension
1028                  map* mtype=getMap(resu->content,"mimeType");
1029                  getFileExtension(mtype != NULL ? mtype->value : NULL, file_ext, 32);
1030                }
1031                if(file_name!=NULL)
1032                  free(file_name);
1033             
1034                file_name=(char*)malloc((strlen(s->name)+strlen(usid->value)+strlen(file_ext)+strlen(resu->name)+45)*sizeof(char));
1035                sprintf(file_name,"ZOO_DATA_%s_%s_%s_%d.%s",s->name,resu->name,usid->value,itn,file_ext);
1036
1037                file_path=(char*)malloc((strlen(tmp1->value)+strlen(file_name)+2)*sizeof(char));
1038                sprintf(file_path,"%s/%s",tmp1->value,file_name);
1039              }else{
1040                file_path=(char*)malloc((strlen(gfile->value)+1)*sizeof(char));
1041                sprintf(file_path,"%s",gfile->value);
1042              }
1043               
1044             
1045              itn++;
1046             
1047              file_url=(char*)malloc((strlen(tmpUrl->value)+
1048                                      strlen(file_name)+2)*sizeof(char));
1049              sprintf(file_url,"%s/%s",tmpUrl->value,file_name);
1050
1051              if(gfile==NULL){
1052                FILE *ofile=fopen(file_path,"wb");
1053                if(ofile==NULL){
1054                  char tmpMsg[1024];
1055                  sprintf(tmpMsg,
1056                          _("Unable to create the file \"%s\" for storing the %s final result."),
1057                          file_name,resu->name);
1058                  map* error=createMap("code","InternalError");
1059                  addToMap(error,"message",tmpMsg);
1060                  printExceptionReportResponseJ(conf,error);
1061                  free(file_name);
1062                  free(file_path);
1063                  return NULL;
1064                }
1065
1066                map* toto=getMap(resu->content,"value");
1067                if(toto==NULL){
1068                  char tmpMsg[1024];
1069                  sprintf(tmpMsg,
1070                          _("No value found for the requested output %s."),
1071                          resu->name);
1072                  map* error=createMap("code","InternalError");
1073                  addToMap(error,"message",tmpMsg);
1074                  printExceptionReportResponseJ(conf,error);
1075                  fclose(ofile);
1076                  free(file_name);
1077                  free(file_path);
1078                  return NULL;
1079                }
1080                map* size=getMap(resu->content,"size");
1081                if(size!=NULL && toto!=NULL)
1082                  fwrite(toto->value,1,(atoi(size->value))*sizeof(char),ofile);
1083                else
1084                  if(toto!=NULL && toto->value!=NULL)
1085                    fwrite(toto->value,1,
1086                           strlen(toto->value)*sizeof(char),ofile);
1087                fclose(ofile);
1088              }
1089              json_object_object_add(res2,"href",
1090                                     json_object_new_string(file_url));
1091              free(file_url);
1092              free(file_name);
1093              free(file_path);
1094             
1095            }
1096           
1097          }
1098        }
1099        json_object_object_add(res1,"value",res2);     
1100        json_object_array_add(eres,res1);
1101      }
1102      resu=resu->next;
1103    }
1104    json_object_object_add(eres1,"outputs",eres);
1105    const char* jsonStr =
1106      json_object_to_json_string_ext(eres1,JSON_C_TO_STRING_PLAIN);
1107    map *tmpPath = getMapFromMaps (conf, "main", "tmpPath");
1108    map *cIdentifier = getMapFromMaps (conf, "lenv", "oIdentifier");
1109    map *sessId = getMapFromMaps (conf, "lenv", "usid");
1110    char tmp[1024];
1111    sprintf(tmp,"%s/%s_%s.json",
1112            tmpPath->value,cIdentifier->value,sessId->value);
1113    FILE* foutput=fopen(tmp,"w+");
1114    if(foutput!=NULL){
1115      fclose(foutput);
1116      char tmpUrl[1024];
1117      map* tmpPath1 = getMapFromMaps (conf, "main", "tmpUrl");
1118      sprintf(tmpUrl,"%s/%s_%s.json",tmpPath1->value,
1119              cIdentifier->value,sessId->value);
1120      setMapInMaps(conf,"headers","Location",tmpUrl);
1121    }
1122    if(res==3){
1123      setMapInMaps(conf,"headers","Status","201 Created");
1124    }
1125    else{
1126      setMapInMaps(conf,"headers","Status","500 Issue running your service");
1127    }
1128
1129    return eres1;
1130  }
1131
1132
1133  /**
1134   * Create the status links
1135   *
1136   * @param conf the maps containing the settings of the main.cfg file
1137   * @param result an integer (>0 for adding the /result link)
1138   * @param obj the JSON object pointer to add the links to
1139   * @return 0
1140   */
1141  int createStatusLinks(maps* conf,int result,json_object* obj){
1142    json_object* res=json_object_new_array();
1143    map *tmpPath = getMapFromMaps (conf, "main", "serverAddress");
1144    map *cIdentifier = getMapFromMaps (conf, "lenv", "oIdentifier");
1145    map *sessId = getMapFromMaps (conf, "lenv", "usid");
1146    char *Url0=(char*) malloc((strlen(tmpPath->value)+
1147                               strlen(cIdentifier->value)+
1148                               strlen(sessId->value)+18)*sizeof(char));
1149    int needResult=-1;
1150    char *message, *status;
1151    sprintf(Url0,"%s/processes/%s/jobs/%s",
1152            tmpPath->value,
1153            cIdentifier->value,
1154            sessId->value);
1155    setMapInMaps(conf,"headers","Location",Url0);
1156    json_object* val=json_object_new_object();
1157    json_object_object_add(val,"Title",
1158                           json_object_new_string(_("Status location")));
1159    json_object_object_add(val,"href",json_object_new_string(Url0));
1160    json_object_array_add(res,val);
1161    if(result>0){
1162      free(Url0);
1163      Url0=(char*) malloc((strlen(tmpPath->value)+
1164                           strlen(cIdentifier->value)+strlen(sessId->value)+
1165                           25)*sizeof(char));
1166      sprintf(Url0,"%s/processes/%s/jobs/%s/result",
1167              tmpPath->value,
1168              cIdentifier->value,
1169              sessId->value);
1170      json_object* val1=json_object_new_object();
1171      json_object_object_add(val1,"Title",
1172                             json_object_new_string(_("Result location")));
1173      json_object_object_add(val1,"href",json_object_new_string(Url0));
1174      json_object_array_add(res,val1);
1175    }
1176    json_object_object_add(obj,"links",res);
1177    free(Url0);
1178    return 0;
1179  }
1180
1181  /**
1182   * Get the status file path
1183   *
1184   * @param conf the maps containing the settings of the main.cfg file
1185   * @return a char* containing the full status file path
1186   */
1187  char* json_getStatusFilePath(maps* conf){
1188    map *tmpPath = getMapFromMaps (conf, "main", "tmpPath");
1189    map *cIdentifier = getMapFromMaps (conf, "lenv", "oIdentifier");
1190    map *sessId = getMapFromMaps (conf, "lenv", "usid");
1191    if(sessId!=NULL){
1192      sessId = getMapFromMaps (conf, "lenv", "gs_usid");
1193      if(sessId==NULL)
1194        sessId = getMapFromMaps (conf, "lenv", "usid");
1195    }else
1196      sessId = getMapFromMaps (conf, "lenv", "gs_usid");
1197    char *tmp1=(char*) malloc((strlen(tmpPath->value)+
1198                               strlen(cIdentifier->value)+14)*sizeof(char));
1199    sprintf(tmp1,"%s/statusInfos/%s",
1200            tmpPath->value,
1201            cIdentifier->value);
1202    if(mkdir(tmp1,0777) != 0 && errno != EEXIST){
1203      fprintf(stderr,"Issue creating directory %s\n",tmp1);
1204      return NULL;
1205    }
1206    free(tmp1);
1207    tmp1=(char*) malloc((strlen(tmpPath->value)+
1208                         strlen(cIdentifier->value)+
1209                         strlen(sessId->value)+20)*sizeof(char));
1210    int needResult=0;
1211    char *message, *rstatus;
1212    sprintf(tmp1,"%s/statusInfos/%s/%s.json",
1213            tmpPath->value,
1214            cIdentifier->value,
1215            sessId->value);
1216   
1217    return tmp1;
1218  }
1219 
1220  /**
1221   * Create the status file
1222   *
1223   * @param conf the maps containing the settings of the main.cfg file
1224   * @param status an integer (SERVICE_ACCEPTED,SERVICE_STARTED...)
1225   * @return an integer (0 in case of success, 1 in case of failure)
1226   */
1227  int createStatusFile(maps* conf,int status){
1228    int needResult=0;
1229    const char *message, *rstatus;
1230    char* tmp1=json_getStatusFilePath(conf);
1231    // Create statusInfo JSON object
1232    // cf. https://github.com/opengeospatial/wps-rest-binding/blob/master/core/
1233    //     openapi/schemas/statusInfo.yaml
1234    json_object* res=json_object_new_object();
1235    json_object_object_add(res,"status",json_object_new_string("successful"));
1236    switch(status){
1237    case SERVICE_ACCEPTED:
1238      {
1239        message=_("ZOO-Kernel accepted to run your service!");
1240        rstatus="accepted";
1241        break;
1242      }
1243    case SERVICE_STARTED:
1244      {
1245        message=_("ZOO-Kernel is currently running your service!");
1246        rstatus="running";
1247        break;
1248      }
1249    case SERVICE_PAUSED:
1250      {
1251        message=_("ZOO-Kernel pause your service!");
1252        rstatus="paused";
1253        break;
1254      }
1255    case SERVICE_SUCCEEDED:
1256      {
1257        message=_("ZOO-Kernel successfully run your service!");
1258        rstatus="successful";
1259        needResult=1;
1260        break;
1261      }
1262    default:
1263      {
1264        message=_("ZOO-Kernel failed to run your service!");
1265        rstatus="failed";
1266        break;
1267      }
1268    }
1269    setMapInMaps(conf,"lenv","message",message);
1270    setMapInMaps(conf,"lenv","status",rstatus);
1271       
1272    map* mess=getMapFromMaps(conf,"lenv","message");
1273    if(mess!=NULL)
1274      json_object_object_add(res,"message",json_object_new_string(mess->value));
1275
1276    createStatusLinks(conf,needResult,res);
1277   
1278    FILE* foutput1=fopen(tmp1,"w+");
1279    if(foutput1!=NULL){
1280      const char* jsonStr1=json_object_to_json_string_ext(res,JSON_C_TO_STRING_PLAIN);
1281      fprintf(foutput1,"%s",jsonStr1);
1282      fclose(foutput1);
1283    }else{
1284      // Failure
1285      setMapInMaps(conf,"lenv","message",_("Unable to store the statusInfo!"));
1286      free(tmp1);
1287      return 1;
1288    }
1289    free(tmp1);
1290    return 0;
1291  }
1292
1293  /**
1294   * Create the status file
1295   *
1296   * @param conf the maps containing the settings of the main.cfg file
1297   * @return an integer (0 in case of success, 1 in case of failure)
1298   */
1299  int json_getStatusFile(maps* conf){
1300    char* tmp1=json_getStatusFilePath(conf);
1301    FILE* statusFile=fopen(tmp1,"rb");
1302
1303    map* tmpMap=getMapFromMaps(conf,"lenv","gs_usid");
1304    if(tmpMap!=NULL){
1305        char* tmpStr=_getStatus(conf,tmpMap->value);
1306        if(tmpStr!=NULL && strncmp(tmpStr,"-1",2)!=0){
1307          char *tmpStr1=zStrdup(tmpStr);
1308          char *tmpStr0=zStrdup(strstr(tmpStr,"|")+1);
1309          free(tmpStr);
1310          tmpStr1[strlen(tmpStr1)-strlen(tmpStr0)-1]='\0';
1311          setMapInMaps(conf,"lenv","PercentCompleted",tmpStr1);
1312          setMapInMaps(conf,"lenv","gs_message",tmpStr0);
1313          free(tmpStr0);
1314          free(tmpStr1);
1315        }
1316      }
1317  }
1318
1319  /**
1320   * Produce the JSON object for api info object
1321   *
1322   * @param conf the maps containing the settings of the main.cfg file
1323   * @param res the JSON object for the api info
1324   */
1325  void produceApiInfo(maps* conf,json_object* res,json_object* res5){
1326    json_object *res1=json_object_new_object();
1327    map* tmpMap=getMapFromMaps(conf,"provider","providerName");
1328    if(tmpMap!=NULL){
1329      json_object *res2=json_object_new_object();
1330      json_object_object_add(res2,"name",json_object_new_string(tmpMap->value));
1331      tmpMap=getMapFromMaps(conf,"provider","addressElectronicMailAddress");
1332      if(tmpMap!=NULL)
1333        json_object_object_add(res2,"email",json_object_new_string(tmpMap->value));
1334      tmpMap=getMapFromMaps(conf,"provider","providerSite");
1335      if(tmpMap!=NULL)
1336        json_object_object_add(res2,"url",json_object_new_string(tmpMap->value));
1337      json_object_object_add(res1,"contact",res2);
1338    }
1339    tmpMap=getMapFromMaps(conf,"identification","abstract");
1340    if(tmpMap!=NULL){
1341      json_object_object_add(res1,"description",json_object_new_string(tmpMap->value));
1342      json_object_object_add(res5,"description",json_object_new_string(tmpMap->value));
1343      tmpMap=getMapFromMaps(conf,"main","serverAddress");
1344      json_object_object_add(res5,"url",json_object_new_string(tmpMap->value));
1345    }
1346    tmpMap=getMapFromMaps(conf,"identification","title");
1347    if(tmpMap!=NULL)
1348      json_object_object_add(res1,"title",json_object_new_string(tmpMap->value));
1349    json_object_object_add(res1,"version",json_object_new_string(ZOO_VERSION));
1350    tmpMap=getMapFromMaps(conf,"identification","keywords");
1351    if(tmpMap!=NULL){
1352      char *saveptr;
1353      char *tmps = strtok_r (tmpMap->value, ",", &saveptr);
1354      json_object *res3=json_object_new_array();
1355      while (tmps != NULL){
1356        json_object_array_add(res3,json_object_new_string(tmps));
1357        tmps = strtok_r (NULL, ",", &saveptr);
1358      }
1359      json_object_object_add(res1,"x-keywords",res3);
1360    }
1361    maps* tmpMaps=getMaps(conf,"provider");
1362    if(tmpMaps!=NULL){
1363      json_object *res4=json_object_new_object();
1364      map* cItem=tmpMaps->content;
1365      while(cItem!=NULL){
1366        json_object_object_add(res4,cItem->name,json_object_new_string(cItem->value));
1367        cItem=cItem->next;
1368      }
1369      json_object_object_add(res1,"x-ows-servicecontact",res4);
1370    }
1371
1372    json_object *res4=json_object_new_object();
1373    tmpMap=getMapFromMaps(conf,"main","license_name");
1374    if(tmpMap!=NULL){
1375      json_object_object_add(res4,"name",json_object_new_string(tmpMap->value));
1376      tmpMap=getMapFromMaps(conf,"main","license_url");
1377      if(tmpMap!=NULL){
1378        json_object_object_add(res4,"url",json_object_new_string(tmpMap->value));     
1379      }
1380    }
1381    json_object_object_add(res1,"license",res4);
1382
1383    json_object_object_add(res,"info",res1);   
1384  }
1385
1386  /**
1387   * Produce the JSON object for api parameter
1388   *
1389   * @param conf the maps containing the settings of the main.cfg file
1390   * @param res the JSON object to populate with the parameters
1391   */
1392  void produceApiParameters(maps* conf,json_object* res){
1393    json_object *res9=json_object_new_object();
1394    maps* tmpMaps1=getMaps(conf,"{id}");
1395    map* tmpMap2=getMapFromMaps(conf,"openapi","parameters");
1396    char *saveptr12;
1397    char *tmps12 = strtok_r (tmpMap2->value, ",", &saveptr12);
1398    while(tmps12!=NULL){
1399      char* tmpId=(char*) malloc((strlen(tmps12)+3)*sizeof(char));
1400      sprintf(tmpId,"{%s}",tmps12);
1401      tmpMaps1=getMaps(conf,tmpId);
1402      json_object *res8=json_object_new_object();
1403      if(tmpMaps1!=NULL){
1404        map* tmpMap=getMap(tmpMaps1->content,"title");
1405        if(tmpMap!=NULL)
1406          json_object_object_add(res8,"x-internal-summary",json_object_new_string(tmpMap->value));
1407        tmpMap=getMap(tmpMaps1->content,"abstract");
1408        if(tmpMap!=NULL)
1409          json_object_object_add(res8,"description",json_object_new_string(tmpMap->value));
1410        tmpMap=getMap(tmpMaps1->content,"example");
1411        if(tmpMap!=NULL)
1412          json_object_object_add(res8,"example",json_object_new_string(tmpMap->value));
1413        tmpMap=getMap(tmpMaps1->content,"required");
1414        if(tmpMap!=NULL){
1415          if(strcmp(tmpMap->value,"true")==0)
1416            json_object_object_add(res8,"required",json_object_new_boolean(TRUE));
1417          else
1418            json_object_object_add(res8,"required",json_object_new_boolean(FALSE));
1419        }
1420        else
1421          json_object_object_add(res8,"required",json_object_new_boolean(FALSE));
1422        json_object_object_add(res8,"in",json_object_new_string("path"));
1423        json_object_object_add(res8,"name",json_object_new_string(tmps12));
1424        json_object *res6=json_object_new_object();
1425        json_object *res7=json_object_new_object();
1426        tmpMap=getMap(tmpMaps1->content,"type");
1427        if(tmpMap!=NULL)
1428          json_object_object_add(res6,"type",json_object_new_string(tmpMap->value));
1429        else
1430          json_object_object_add(res6,"type",json_object_new_string("string"));
1431       
1432        json_object_object_add(res8,"schema",res6);
1433       
1434      }
1435       
1436      json_object_object_add(res9,tmps12,res8);
1437      tmps12 = strtok_r (NULL, ",", &saveptr12);
1438    }   
1439    tmpMap2=getMapFromMaps(conf,"openapi","header_parameters");
1440    char *saveptr13;
1441    char *tmps13 = strtok_r (tmpMap2->value, ",", &saveptr13);
1442    while(tmps13!=NULL){
1443      char* tmpId=zStrdup(tmps13);
1444      maps *tmpMaps2=getMaps(conf,tmpId);
1445      json_object *res8=json_object_new_object();
1446      if(tmpMaps2!=NULL){
1447        map* tmpMap=getMap(tmpMaps2->content,"title");
1448        if(tmpMap!=NULL)
1449          json_object_object_add(res8,"x-internal-summary",json_object_new_string(tmpMap->value));
1450        tmpMap=getMap(tmpMaps2->content,"abstract");
1451        if(tmpMap!=NULL)
1452          json_object_object_add(res8,"description",json_object_new_string(tmpMap->value));
1453        tmpMap=getMap(tmpMaps2->content,"example");
1454        if(tmpMap!=NULL)
1455          json_object_object_add(res8,"example",json_object_new_string(tmpMap->value));
1456        tmpMap=getMap(tmpMaps2->content,"required");
1457        if(tmpMap!=NULL){
1458          if(strcmp(tmpMap->value,"true")==0)
1459            json_object_object_add(res8,"required",json_object_new_boolean(TRUE));
1460          else
1461            json_object_object_add(res8,"required",json_object_new_boolean(FALSE));
1462        }
1463        else
1464          json_object_object_add(res8,"required",json_object_new_boolean(FALSE));
1465        json_object_object_add(res8,"in",json_object_new_string("header"));
1466        tmpMap=getMap(tmpMaps2->content,"name");
1467        if(tmpMap!=NULL)
1468          json_object_object_add(res8,"name",json_object_new_string(tmpMap->value));
1469        json_object *res6=json_object_new_object();
1470        json_object *res7=json_object_new_object();
1471        tmpMap=getMap(tmpMaps2->content,"type");
1472        if(tmpMap!=NULL)
1473          json_object_object_add(res6,"type",json_object_new_string(tmpMap->value));
1474        else
1475          json_object_object_add(res6,"type",json_object_new_string("string"));
1476
1477        {
1478          tmpMap=getMap(tmpMaps2->content,"enum");
1479          if(tmpMap!=NULL){
1480            char *saveptr11;
1481            char *tmps11 = strtok_r (tmpMap->value, ",", &saveptr11);
1482            json_object *res71=json_object_new_array();
1483            while(tmps11!=NULL){               
1484              json_object_array_add(res71,json_object_new_string(tmps11));
1485              tmps11 = strtok_r (NULL, ",", &saveptr11);
1486            }
1487            json_object_object_add(res6,"enum",res71);                           
1488          }
1489        }
1490       
1491        json_object_object_add(res8,"schema",res6);
1492       
1493      }
1494       
1495      json_object_object_add(res9,tmpId,res8);
1496      tmps13 = strtok_r (NULL, ",", &saveptr13);
1497    } 
1498    json_object_object_add(res,"parameters",res9);   
1499  }
1500
1501  void produceApiComponents(maps*conf,json_object* res){
1502    json_object* res1=json_object_new_object();
1503    produceApiParameters(conf,res1);
1504    json_object_object_add(res,"components",res1);
1505  }
1506
1507  /**
1508   * Produce the JSON object for /api
1509   *
1510   * @param conf the maps containing the settings of the main.cfg file
1511   * @param res the JSON object to populate
1512   */
1513  void produceApi(maps* conf,json_object* res){
1514    json_object *res9=json_object_new_object();
1515    json_object *res10=json_object_new_object();
1516    maps* tmpMaps1=getMaps(conf,"{id}");
1517
1518    produceApiComponents(conf,res);
1519    json_object *res4=json_object_new_object();
1520    setMapInMaps(conf,"headers","Content-Type","application/openapi+json; version=3.0;charset=UTF-8");
1521
1522    produceApiInfo(conf,res,res4);
1523    map* tmpMap=getMapFromMaps(conf,"provider","providerName");
1524
1525    tmpMap=getMapFromMaps(conf,"openapi","version");
1526    if(tmpMap!=NULL)
1527      json_object_object_add(res,"openapi",json_object_new_string(tmpMap->value));
1528    else
1529      json_object_object_add(res,"openapi",json_object_new_string("3.0.2"));
1530
1531    tmpMap=getMapFromMaps(conf,"openapi","paths");
1532    if(tmpMap!=NULL){
1533      json_object *res5=json_object_new_object();
1534      char *saveptr;
1535      char *tmps = strtok_r (tmpMap->value, ",", &saveptr);
1536      int cnt=0;
1537      maps* tmpMaps;
1538      json_object *paths=json_object_new_object();
1539      while (tmps != NULL){
1540        tmpMaps=getMaps(conf,tmps+1);
1541        json_object *method=json_object_new_object();
1542        if(tmpMaps!=NULL){
1543          if(getMap(tmpMaps->content,"length")==NULL)
1544            addToMap(tmpMaps->content,"length","1");
1545          map* len=getMap(tmpMaps->content,"length");
1546           
1547          for(int i=0;i<atoi(len->value);i++){
1548            json_object *methodc=json_object_new_object();
1549            map* cMap=getMapArray(tmpMaps->content,"method",i);
1550            map* vMap=getMapArray(tmpMaps->content,"title",i);
1551            if(vMap!=NULL)
1552              json_object_object_add(methodc,"summary",json_object_new_string(vMap->value));
1553            vMap=getMapArray(tmpMaps->content,"abstract",i);
1554            if(vMap!=NULL)
1555              json_object_object_add(methodc,"description",json_object_new_string(vMap->value));
1556            vMap=getMapArray(tmpMaps->content,"tags",i);
1557            if(vMap!=NULL){
1558              json_object *cc=json_object_new_array();
1559              json_object_array_add(cc,json_object_new_string(vMap->value));
1560              json_object_object_add(methodc,"tags",cc);
1561            }
1562            json_object *responses=json_object_new_object();
1563            json_object *cc3=json_object_new_object();
1564            vMap=getMapArray(tmpMaps->content,"schema",i);
1565            if(vMap!=NULL){
1566              json_object *cc=json_object_new_object();
1567              json_object_object_add(cc,"$ref",json_object_new_string(vMap->value));
1568              json_object *cc0=json_object_new_object();
1569              json_object_object_add(cc0,"schema",cc);
1570              json_object *cc1=json_object_new_object();
1571              map* tmpMap3=getMapFromMaps(conf,tmps,"type");
1572              if(tmpMap3!=NULL)
1573                json_object_object_add(cc1,tmpMap3->value,cc0);
1574              else
1575                json_object_object_add(cc1,"application/json",cc0);
1576              json_object *cc2=json_object_new_object();
1577              json_object_object_add(cc2,"content",cc1);
1578              json_object_object_add(cc2,"description",json_object_new_string("successful operation"));
1579              if(i==1)
1580                json_object_object_add(cc3,"201",cc2);
1581              else
1582                json_object_object_add(cc3,"200",cc2);
1583            }else{
1584              json_object *cc1=json_object_new_object();
1585              map* tmpMap3=getMapFromMaps(conf,tmps,"type");
1586              if(tmpMap3!=NULL)
1587                json_object_object_add(cc1,tmpMap3->value,json_object_new_object());
1588              else
1589                json_object_object_add(cc1,"application/json",json_object_new_object());
1590              json_object *cc2=json_object_new_object();
1591              json_object_object_add(cc2,"content",cc1);
1592              json_object_object_add(cc2,"description",json_object_new_string("successful operation"));
1593              if(i==1)
1594                json_object_object_add(cc3,"201",cc2);
1595              else
1596                json_object_object_add(cc3,"200",cc2);
1597            }
1598            if(strstr(tmps,"{id}")!=NULL){
1599              vMap=getMapFromMaps(conf,"exception","schema");
1600              json_object *cc=json_object_new_object();
1601              json_object_object_add(cc,"$ref",json_object_new_string(vMap->value));
1602              json_object *cc01=json_object_new_array();
1603              json_object_array_add(cc01,cc);
1604
1605              json_object *cc0=json_object_new_object();
1606              json_object_object_add(cc0,"schema",cc);
1607              json_object *cc1=json_object_new_object();
1608              map* tmpMap3=getMapFromMaps(conf,"exception","type");
1609              if(tmpMap3!=NULL)
1610                json_object_object_add(cc1,tmpMap3->value,cc0);
1611              else
1612                json_object_object_add(cc1,"application/json",cc0);
1613
1614              json_object *cc2=json_object_new_object();
1615              json_object_object_add(cc2,"content",cc1);
1616              if(strstr(tmps,"{jobID}")==NULL)
1617                json_object_object_add(cc2,"description",json_object_new_string("The process with id {id} does not exist."));
1618              else
1619                json_object_object_add(cc2,"description",json_object_new_string("The process with id {id} or job with id {jobID} does not exist."));
1620              json_object_object_add(cc3,"404",cc2);
1621              json_object_object_add(cc3,"default",cc2);
1622            }
1623            json_object_object_add(methodc,"responses",cc3);
1624            vMap=getMapArray(tmpMaps->content,"parameters",i);
1625            if(vMap!=NULL){
1626              char *saveptr0;
1627              char *tmps1 = strtok_r (vMap->value, ",", &saveptr0);
1628              json_object *cc2=json_object_new_array();
1629              int cnt=0;
1630              while(tmps1!=NULL){
1631                char* tmpStr=(char*)malloc((strlen(tmps1)+2)*sizeof(char));
1632                sprintf(tmpStr,"#%s",tmps1);
1633                json_object *cc1=json_object_new_object();
1634                json_object_object_add(cc1,"$ref",json_object_new_string(tmpStr));
1635                json_object_array_add(cc2,cc1);
1636                free(tmpStr);
1637                cnt++;
1638                tmps1 = strtok_r (NULL, ",", &saveptr0);
1639              }
1640              json_object_object_add(methodc,"parameters",cc2);
1641            }
1642            if(i==1){
1643              maps* tmpMaps1=getMaps(conf,"requestBody");
1644              if(tmpMaps1!=NULL){
1645                vMap=getMap(tmpMaps1->content,"schema");
1646                if(vMap!=NULL){
1647                  json_object *cc=json_object_new_object();
1648                  json_object_object_add(cc,"$ref",json_object_new_string(vMap->value));
1649                  json_object *cc0=json_object_new_object();
1650                  json_object_object_add(cc0,"schema",cc);
1651                  json_object *cc1=json_object_new_object();
1652                  map* tmpMap3=getMap(tmpMaps->content,"type");
1653                  if(tmpMap3!=NULL)
1654                    json_object_object_add(cc1,tmpMap3->value,cc0);
1655                  else
1656                    json_object_object_add(cc1,"application/json",cc0);
1657                  json_object *cc2=json_object_new_object();
1658                  json_object_object_add(cc2,"content",cc1);
1659                  vMap=getMap(tmpMaps1->content,"abstract");
1660                  if(vMap!=NULL)
1661                    json_object_object_add(cc2,"description",json_object_new_string(vMap->value));
1662                  json_object_object_add(cc2,"required",json_object_new_boolean(true));
1663                  json_object_object_add(methodc,"requestBody",cc2);
1664
1665                }
1666              }
1667            }
1668            map* mMap=getMapArray(tmpMaps->content,"method",i);
1669            if(mMap!=NULL)
1670              json_object_object_add(method,mMap->value,methodc);
1671            else
1672              json_object_object_add(method,"get",methodc);
1673
1674          }
1675
1676          tmpMap=getMapFromMaps(conf,"openapi","version");
1677          if(tmpMap!=NULL)
1678            json_object_object_add(res,"openapi",json_object_new_string(tmpMap->value));
1679          else
1680            json_object_object_add(res,"openapi",json_object_new_string("3.0.2"));
1681          if(strstr(tmps,"/root")!=NULL)
1682            json_object_object_add(paths,"/",method);
1683          else
1684            json_object_object_add(paths,tmps,method);
1685        }
1686        tmps = strtok_r (NULL, ",", &saveptr);
1687        cnt++;
1688      }
1689      json_object_object_add(res,"paths",paths);
1690    }
1691     
1692    tmpMap=getMapFromMaps(conf,"openapi","links");
1693    if(tmpMap!=NULL){
1694       
1695    }
1696   
1697    json_object *res3=json_object_new_array();
1698    json_object_array_add(res3,res4);
1699    json_object_object_add(res,"servers",res3);
1700  }
1701 
1702#ifdef __cplusplus
1703}
1704#endif
Note: See TracBrowser for help on using the repository browser.

Search

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png