source: trunk/zoo-kernel/service.h @ 253

Last change on this file since 253 was 253, checked in by djay, 13 years ago

Fix FastCGI support. Small fix to store mapon disk and manage session. Fix typo in main.cfg.

File size: 17.3 KB
Line 
1/**
2 * Author : Gérald FENOY
3 *
4 * Copyright (c) 2009-2010 GeoLabs SARL
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#ifndef ZOO_SERVICE_H
26#define ZOO_SERVICE_H 1
27
28#pragma once
29
30#ifdef WIN32
31#define strncasecmp strnicmp
32#define strcasecmp stricmp
33#define snprintf sprintf_s
34#endif
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40#include <stdlib.h>
41#include <ctype.h>
42#include <stdio.h>
43#include <string.h>
44
45#define bool int
46#define true 1
47#define false -1
48
49#define SERVICE_ACCEPTED 0
50#define SERVICE_STARTED 1
51#define SERVICE_PAUSED 2
52#define SERVICE_SUCCEEDED 3
53#define SERVICE_FAILED 4
54
55#define ELEMENTS_SIZE (sizeof(char*)+(((2*sizeof(char*))+sizeof(maps*))*2)+sizeof(char*)+(((2*sizeof(char*))+sizeof(iotype*))*2)+sizeof(elements*))
56#define MAP_SIZE (2*sizeof(char*))+sizeof(NULL)
57#define IOTYPE_SIZE MAP_SIZE+sizeof(NULL)
58#define MAPS_SIZE (2*sizeof(char*))+sizeof(map*)+MAP_SIZE
59#define SERVICE_SIZE (ELEMENTS_SIZE*2)+(MAP_SIZE*2)+sizeof(char*)
60
61#define SHMSZ     27
62
63
64  /**
65   * \struct map
66   * \brief KVP linked list
67   *
68   * Deal with WPS KVP (name,value).
69   * A map is defined as:
70   *  - name : a key,
71   *  - value: a value,
72   *  - next : a pointer to the next map if any.
73   */
74  typedef struct map{
75    char* name;
76    char* value;
77    struct map* next;
78  } map;
79
80#ifdef WIN32
81#define NULLMAP ((map*) 0)
82#else
83#define NULLMAP NULL
84#endif
85
86  /**
87   * \struct maps
88   * \brief linked list of map pointer
89   *
90   * Small object to store WPS KVP set.
91   * Maps is defined as:
92   *  - a name,
93   *  - a content map,
94   *  - a pointer to the next maps if any.
95   */
96  typedef struct maps{
97    char* name;         
98    struct map* content; 
99    struct maps* next;   
100  } maps;
101
102  /**
103   * \brief Dump a map on stderr
104   */
105  static void _dumpMap(map* t){
106    if(t!=NULL){
107      fprintf(stderr,"[%s] => [%s] \n",t->name,t->value);
108      fflush(stderr);
109    }else{
110      fprintf(stderr,"NULL\n");
111      fflush(stderr);
112    }
113  }
114
115  static void dumpMap(map* t){
116    map* tmp=t;
117    while(tmp!=NULL){
118      _dumpMap(tmp);
119      tmp=tmp->next;
120    }
121  }
122
123  static void dumpMapToFile(map* t,FILE* file){
124    map* tmp=t;
125    while(tmp!=NULL){
126      fprintf(file,"%s = %s\n",tmp->name,tmp->value);
127      tmp=tmp->next;
128    }
129  }
130
131  static void dumpMaps(maps* m){
132    maps* tmp=m;
133    while(tmp!=NULL){
134      fprintf(stderr,"MAP => [%s] \n",tmp->name);
135      dumpMap(tmp->content);
136      tmp=tmp->next;
137    }
138  }
139
140  static void dumpMapsToFile(maps* m,FILE* file){
141    maps* tmp=m;
142    if(tmp!=NULL){
143      fprintf(file,"[%s]\n",tmp->name);
144      dumpMapToFile(tmp->content,file);
145    }
146  }
147
148  static map* createMap(const char* name,const char* value){
149    map* tmp=(map *)malloc(MAP_SIZE);
150    tmp->name=strdup(name);
151    tmp->value=strdup(value);
152    tmp->next=NULL;
153    return tmp;
154  }
155
156  static int count(map* m){
157    map* tmp=m;
158    int c=0;
159    while(tmp!=NULL){
160      c++;
161      tmp=tmp->next;
162    }
163    return c;
164  }
165   
166  static bool hasKey(map* m,const char *key){
167    map* tmp=m;
168    while(tmp!=NULL){
169      if(strcasecmp(tmp->name,key)==0)
170        return true;
171      tmp=tmp->next;
172    }
173#ifdef DEBUG_MAP
174    fprintf(stderr,"NOT FOUND \n");
175#endif
176    return false;
177  }
178
179  static maps* getMaps(maps* m,const char *key){
180    maps* tmp=m;
181    while(tmp!=NULL){
182      if(strcasecmp(tmp->name,key)==0){
183        return tmp;
184      }
185      tmp=tmp->next;
186    }
187    return NULL;
188  }
189
190  static map* getMap(map* m,const char *key){
191    map* tmp=m;
192    while(tmp!=NULL){
193      if(strcasecmp(tmp->name,key)==0){
194        return tmp;
195      }
196      tmp=tmp->next;
197    }
198    return NULL;
199  }
200
201  static map* getLastMap(map* m){
202    map* tmp=m;
203    while(tmp!=NULL){
204      if(tmp->next==NULL){
205        return tmp;
206      }
207      tmp=tmp->next;
208    }
209    return NULL;
210  }
211
212  static map* getMapFromMaps(maps* m,const char* key,const char* subkey){
213    maps* _tmpm=getMaps(m,key);
214    if(_tmpm!=NULL){
215      map* _ztmpm=getMap(_tmpm->content,subkey);
216      return _ztmpm;
217    }
218    else return NULL;
219  }
220
221  static char* getMapsAsKVP(maps* m,int length,int type){
222    char *dataInputsKVP=(char*) malloc(length*sizeof(char));
223    maps* curs=m;
224    int i=0;
225    while(curs!=NULL){
226      if(i==0)
227        if(type==0)
228          sprintf(dataInputsKVP,"%s=",curs->name);
229        else
230          sprintf(dataInputsKVP,"%s",curs->name);
231      else{
232        char *temp=strdup(dataInputsKVP);
233        if(type==0)
234          sprintf(dataInputsKVP,"%s;%s=",temp,curs->name);
235        else
236          sprintf(dataInputsKVP,"%s;%s",temp,curs->name);
237        free(temp);
238      }
239      map* icurs=curs->content;
240      if(type==0){
241        map* tmp=getMap(curs->content,"value");
242        char *temp=strdup(dataInputsKVP);
243        if(getMap(m->content,"xlink:href")!=NULL)
244          sprintf(dataInputsKVP,"%sReference",temp);
245        else
246          sprintf(dataInputsKVP,"%s%s",temp,icurs->value);
247        free(temp);
248      }
249      int j=0;
250      while(icurs!=NULL){
251        if(strcasecmp(icurs->name,"value")!=0 &&
252           strcasecmp(icurs->name,"Reference")!=0 &&
253           strcasecmp(icurs->name,"minOccurs")!=0 &&
254           strcasecmp(icurs->name,"maxOccurs")!=0 &&
255           strcasecmp(icurs->name,"inRequest")!=0){
256          char *itemp=strdup(dataInputsKVP);
257          sprintf(dataInputsKVP,"%s@%s=%s",itemp,icurs->name,icurs->value);
258          free(itemp);
259        }
260        icurs=icurs->next;
261      }
262      curs=curs->next;
263      i++;
264    }
265    return dataInputsKVP;
266  }
267
268
269  static void freeMap(map** mo){
270    map* _cursor=*mo;
271    if(_cursor!=NULL){
272#ifdef DEBUG
273      fprintf(stderr,"freeMap\n");
274#endif
275      free(_cursor->name);
276      free(_cursor->value);
277      if(_cursor->next!=NULL){
278        freeMap(&_cursor->next);
279        free(_cursor->next);
280      }
281    }
282  }
283
284  static void freeMaps(maps** mo){
285    maps* _cursor=*mo;
286    fflush(stderr);
287    if(_cursor && _cursor!=NULL){
288#ifdef DEBUG
289      fprintf(stderr,"freeMaps\n");
290#endif
291      free(_cursor->name);
292      if(_cursor->content!=NULL){
293        freeMap(&_cursor->content);
294        free(_cursor->content);
295      }
296      if(_cursor->next!=NULL){
297        freeMaps(&_cursor->next);
298        free(_cursor->next);
299      }
300    }
301  }
302
303  /**
304   * \brief Not named linked list
305   *
306   * Used to store informations about formats, such as mimeType, encoding ...
307   *
308   * An iotype is defined as :
309   *  - a content map,
310   *  - a pointer to the next iotype if any.
311   */
312  typedef struct iotype{
313    struct map* content;
314    struct iotype* next;
315  } iotype;
316
317  /**
318   * \brief Metadata information about input or output.
319   *
320   * The elements are used to store metadata informations defined in the ZCFG.
321   *
322   * An elements is defined as :
323   *  - a name,
324   *  - a content map,
325   *  - a metadata map,
326   *  - a format (possible values are LiteralData, ComplexData or
327   * BoundingBoxData),
328   *  - a default iotype,
329   *  - a pointer to the next elements id any.
330   */
331  typedef struct elements{
332    char* name;
333    struct map* content;
334    struct map* metadata;
335    char* format;
336    struct iotype* defaults;
337    struct iotype* supported;
338    struct elements* next;
339  } elements;
340
341  typedef struct service{
342    char* name;
343    struct map* content;
344    struct map* metadata;
345    struct elements* inputs;
346    struct elements* outputs; 
347  } service;
348
349  typedef struct services{
350    struct service* content; 
351    struct services* next; 
352  } services;
353
354  static bool hasElement(elements* e,const char* key){
355    elements* tmp=e;
356    while(tmp!=NULL){
357      if(strcasecmp(key,tmp->name)==0)
358        return true;
359      tmp=tmp->next;
360    }
361    return false;
362  }
363
364  static elements* getElements(elements* m,char *key){
365    elements* tmp=m;
366    while(tmp!=NULL){
367      if(strcasecmp(tmp->name,key)==0)
368        return tmp;
369      tmp=tmp->next;
370    }
371    return NULL;
372  }
373
374
375  static void freeIOType(iotype** i){
376    iotype* _cursor=*i;
377    if(_cursor!=NULL){
378      if(_cursor->next!=NULL){
379        freeIOType(&_cursor->next);
380        free(_cursor->next);
381      }
382      freeMap(&_cursor->content);
383      free(_cursor->content);
384    }
385  }
386
387  static void freeElements(elements** e){
388    elements* tmp=*e;
389    if(tmp!=NULL){
390      if(tmp->name!=NULL)
391        free(tmp->name);
392      freeMap(&tmp->content);
393      if(tmp->content!=NULL)
394        free(tmp->content);
395      freeMap(&tmp->metadata);
396      if(tmp->metadata!=NULL)
397        free(tmp->metadata);
398      if(tmp->format!=NULL)
399        free(tmp->format);
400      freeIOType(&tmp->defaults);
401      if(tmp->defaults!=NULL)
402        free(tmp->defaults);
403      freeIOType(&tmp->supported);
404      if(tmp->supported!=NULL){
405        free(tmp->supported);
406      }
407      freeElements(&tmp->next);
408      if(tmp->next!=NULL)
409        free(tmp->next);
410    }
411  }
412
413  static void freeService(service** s){
414    service* tmp=*s;
415    if(tmp!=NULL){
416      if(tmp->name!=NULL)
417        free(tmp->name);
418      freeMap(&tmp->content);
419      if(tmp->content!=NULL)
420        free(tmp->content);
421      freeMap(&tmp->metadata);
422      if(tmp->metadata!=NULL)
423        free(tmp->metadata);
424      freeElements(&tmp->inputs);
425      if(tmp->inputs!=NULL)
426        free(tmp->inputs);
427      freeElements(&tmp->outputs);
428      if(tmp->outputs!=NULL)
429        free(tmp->outputs);
430    }
431  }
432
433  static void addToMap(map* m,const char* n,const char* v){
434    if(hasKey(m,n)==false){
435      map* _cursor=m;
436      while(_cursor->next!=NULL)
437        _cursor=_cursor->next;
438      _cursor->next=createMap(n,v);
439    }
440    else{
441      map *tmp=getMap(m,n);
442      if(tmp->value!=NULL)
443        free(tmp->value);
444      tmp->value=strdup(v);
445    }
446  }
447
448  static void addMapToMap(map** mo,map* mi){
449    map* tmp=mi;
450    map* _cursor=*mo;
451    if(tmp==NULL){
452      if(_cursor!=NULL){
453        while(_cursor!=NULL)
454          _cursor=_cursor->next;
455        _cursor=NULL;
456      }else
457        *mo=NULL;
458    }
459    while(tmp!=NULL){
460      if(_cursor==NULL){
461        if(*mo==NULL)
462          *mo=createMap(tmp->name,tmp->value);
463        else
464          addToMap(*mo,tmp->name,tmp->value);
465      }
466      else{
467#ifdef DEBUG
468        fprintf(stderr,"_CURSOR\n");
469        dumpMap(_cursor);
470#endif
471        while(_cursor!=NULL)
472          _cursor=_cursor->next;
473        _cursor=createMap(tmp->name,tmp->value);
474        _cursor->next=NULL;
475      }
476      tmp=tmp->next;
477#ifdef DEBUG
478      fprintf(stderr,"MO\n");
479      dumpMap(*mo);
480#endif
481    }
482  }
483
484  static void addMapToIoType(iotype** io,map* mi){
485    iotype* tmp=*io;
486    while(tmp->next!=NULL){
487      tmp=tmp->next;
488    }
489    tmp->next=(iotype*)malloc(IOTYPE_SIZE);
490    tmp->next->content=NULL;
491    addMapToMap(&tmp->next->content,mi);
492    tmp->next->next=NULL;
493  }
494
495  static bool contains(map* m,map* i){
496    while(i!=NULL){     
497      if(strcasecmp(i->name,"value")!=0 &&
498         strcasecmp(i->name,"xlink:href")!=0){
499        map *tmp;
500        if(hasKey(m,i->name) && (tmp=getMap(m,i->name))!=NULL && 
501           strcasecmp(i->value,tmp->value)!=0)
502          return false;
503      }
504      i=i->next;
505    }
506    return true;
507  }
508
509  static iotype* getIoTypeFromElement(elements* e,char *name, map* values){
510    elements* cursor=e;
511    while(cursor!=NULL){
512      if(strcasecmp(cursor->name,name)==0){
513        if(contains(cursor->defaults->content,values)==true)
514          return cursor->defaults;
515        else{
516          iotype* tmp=cursor->supported;
517          while(tmp!=NULL){
518            if(contains(tmp->content,values)==true)
519              return tmp;           
520            tmp=tmp->next;
521          }
522        }
523      }
524      cursor=cursor->next;
525    }
526    return NULL;
527  }
528
529  static maps* dupMaps(maps** mo){
530    maps* _cursor=*mo;
531    maps* res=NULL;
532    if(_cursor!=NULL){
533      res=(maps*)malloc(MAPS_SIZE);
534      res->name=strdup(_cursor->name);
535      res->content=NULL;
536      res->next=NULL;
537      map* mc=_cursor->content;
538      map* tmp=getMap(mc,"size");
539      char* tmpSized=NULL;
540      if(tmp!=NULL){
541        map* tmpV=getMap(mc,"value");
542        tmpSized=(char*)malloc((atoi(tmp->value)+1)*sizeof(char));
543        memmove(tmpSized,tmpV->value,atoi(tmp->value)*sizeof(char));
544      }
545      if(mc!=NULL){
546        addMapToMap(&res->content,mc);
547      }
548      if(tmp!=NULL){
549        map* tmpV=getMap(res->content,"value");
550        free(tmpV->value);
551        tmpV->value=(char*)malloc((atoi(tmp->value)+1)*sizeof(char));
552        memmove(tmpV->value,tmpSized,atoi(tmp->value)*sizeof(char));
553        tmpV->value[atoi(tmp->value)]=0;
554        free(tmpSized);
555      }
556      res->next=dupMaps(&_cursor->next);
557    }
558    return res;
559  }
560
561  static void addMapsToMaps(maps** mo,maps* mi){
562    maps* tmp=mi;
563    maps* _cursor=*mo;
564    while(tmp!=NULL){
565      if(_cursor==NULL){
566        *mo=dupMaps(&mi);
567        (*mo)->next=NULL;
568      }
569      else{
570        while(_cursor->next!=NULL)
571          _cursor=_cursor->next;
572        _cursor->next=dupMaps(&tmp);
573      }
574      tmp=tmp->next;
575    }
576  }
577
578
579  static void setMapInMaps(maps* m,const char* key,const char* subkey,const char *value){
580    maps* _tmpm=getMaps(m,key);
581    if(_tmpm!=NULL){
582      map* _ztmpm=getMap(_tmpm->content,subkey);
583      if(_ztmpm!=NULL){
584        if(_ztmpm->value!=NULL)
585          free(_ztmpm->value);
586        _ztmpm->value=strdup(value);
587      }else{
588        addToMap(_tmpm->content,subkey,value);
589      }
590    }
591  }
592
593
594  static void dumpElements(elements* e){
595    elements* tmp=e;
596    while(tmp!=NULL){
597      fprintf(stderr,"ELEMENT [%s]\n",tmp->name);
598      fprintf(stderr," > CONTENT [%s]\n",tmp->name);
599      dumpMap(tmp->content);
600      fprintf(stderr," > METADATA [%s]\n",tmp->name);
601      dumpMap(tmp->metadata);
602      fprintf(stderr," > FORMAT [%s]\n",tmp->format);
603      iotype* tmpio=tmp->defaults;
604      int ioc=0;
605      while(tmpio!=NULL){
606        fprintf(stderr," > DEFAULTS [%s] (%i)\n",tmp->name,ioc);
607        dumpMap(tmpio->content);
608        tmpio=tmpio->next;
609        ioc++;
610      }
611      tmpio=tmp->supported;
612      ioc=0;
613      while(tmpio!=NULL){
614        fprintf(stderr," > SUPPORTED [%s] (%i)\n",tmp->name,ioc);
615        dumpMap(tmpio->content);
616        tmpio=tmpio->next;
617        ioc++;
618      }
619      fprintf(stderr,"------------------\n");
620      tmp=tmp->next;
621    }
622  }
623
624  static elements* dupElements(elements* e){
625    elements* cursor=e;
626    elements* tmp=NULL;
627    if(cursor!=NULL){
628#ifdef DEBUG
629      fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
630      dumpElements(e);
631      fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
632#endif
633      tmp=(elements*)malloc(ELEMENTS_SIZE);
634      tmp->name=strdup(e->name);
635      tmp->content=NULL;
636      addMapToMap(&tmp->content,e->content);
637      tmp->metadata=NULL;
638      addMapToMap(&tmp->metadata,e->metadata);
639      tmp->format=strdup(e->format);
640      if(e->defaults!=NULL){
641        tmp->defaults=(iotype*)malloc(IOTYPE_SIZE);
642        tmp->defaults->content=NULL;
643        addMapToMap(&tmp->defaults->content,e->defaults->content);
644        tmp->defaults->next=NULL;
645#ifdef DEBUG
646        fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
647        dumpMap(tmp->defaults->content);
648#endif
649      }else
650        tmp->defaults=NULL;
651      if(e->supported!=NULL){
652        tmp->supported=(iotype*)malloc(IOTYPE_SIZE);
653        tmp->supported->content=NULL;
654        addMapToMap(&tmp->supported->content,e->supported->content);
655        tmp->supported->next=NULL;
656        iotype *tmp2=e->supported->next;
657        while(tmp2!=NULL){
658          addMapToIoType(&tmp->supported,tmp2->content);
659#ifdef DEBUG
660          fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
661          dumpMap(tmp->defaults->content);
662#endif
663          tmp2=tmp2->next;
664        }
665      }
666      else
667        tmp->supported=NULL;
668      tmp->next=dupElements(cursor->next);
669    }
670    return tmp;
671  }
672
673  static void addToElements(elements** m,elements* e){
674    elements* tmp=e;
675    if(*m==NULL){
676      *m=dupElements(tmp);
677    }else{
678      addToElements(&(*m)->next,tmp);
679    }
680  }
681
682  static void dumpService(service* s){
683    fprintf(stderr,"++++++++++++++++++\nSERVICE [%s]\n++++++++++++++++++\n",s->name);
684    if(s->content!=NULL){
685      fprintf(stderr,"CONTENT MAP\n");
686      dumpMap(s->content);
687      fprintf(stderr,"CONTENT METADATA\n");
688      dumpMap(s->metadata);
689    }
690    if(s->inputs!=NULL){
691      fprintf(stderr,"INPUT ELEMENTS [%s]\n------------------\n",s->name);
692      dumpElements(s->inputs);
693    }
694    if(s->outputs!=NULL){
695      fprintf(stderr,"OUTPUT ELEMENTS [%s]\n------------------\n",s->name);
696      dumpElements(s->outputs);
697    }
698    fprintf(stderr,"++++++++++++++++++\n");
699  }
700
701  static void mapsToCharXXX(maps* m,char*** c){
702    maps* tm=m;
703    int i=0;
704    int j=0;
705    char tmp[10][30][1024];
706    memset(tmp,0,1024*10*10);
707    while(tm!=NULL){
708      if(i>=10)
709        break;
710      strcpy(tmp[i][j],"name");
711      j++;
712      strcpy(tmp[i][j],tm->name);
713      j++;
714      map* tc=tm->content;
715      while(tc!=NULL){
716        if(j>=30)
717          break;
718        strcpy(tmp[i][j],tc->name);
719        j++;
720        strcpy(tmp[i][j],tc->value);
721        j++;
722        tc=tc->next;
723      }
724      tm=tm->next;
725      j=0;
726      i++;
727    }
728    memcpy(c,tmp,10*10*1024);
729  }
730
731  static void charxxxToMaps(char*** c,maps**m){
732    maps* trorf=*m;
733    int i,j;
734    char tmp[10][30][1024];
735    memcpy(tmp,c,10*30*1024);
736    for(i=0;i<10;i++){
737      if(strlen(tmp[i][1])==0)
738        break;
739      trorf->name=tmp[i][1];
740      trorf->content=NULL;
741      trorf->next=NULL;
742      for(j=2;j<29;j+=2){
743        if(strlen(tmp[i][j+1])==0)
744          break;
745        if(trorf->content==NULL)
746          trorf->content=createMap(tmp[i][j],tmp[i][j+1]);
747        else
748          addToMap(trorf->content,tmp[i][j],tmp[i][j+1]);
749      }
750      trorf=trorf->next;
751    }
752    m=&trorf;
753  }
754
755#ifdef __cplusplus
756}
757#endif
758
759#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