Changeset 607


Ignore:
Timestamp:
Mar 12, 2015, 3:14:52 AM (3 years ago)
Author:
djay
Message:

Introduce the Process Profiles Registry with its documentation.

Location:
trunk
Files:
1 added
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/docs/services/index.txt

    r457 r607  
    1111   introduction
    1212   zcfg-reference
     13   process-profiles
    1314   howtos
    1415   status
  • trunk/docs/services/zcfg-reference.txt

    r529 r607  
    4848     title = Metadata title of your service
    4949   </MetaData>
     50
     51.. Note:: you may add an ``extend`` key in case you use the `Process
     52   Profile Registry <process-profiles.html>`__.
    5053
    5154List of Inputs
  • trunk/zoo-project/zoo-kernel/main_conf_read.y

    r490 r607  
    11%{
    2 //======================================================
    3 /**
    4    Zoo main configuration file parser
    5 **/
    6 //======================================================
    7 
     2/*
     3 * Zoo main configuration file parser
     4 */
    85#include <service.h>
    96
     
    285282%%
    286283
    287 // crerror
    288 //======================================================
    289 /* fonction qui affiche l erreur si il y en a une */
    290 //======================================================
     284/**
     285 * Print on stderr the message and the line number of the error which occured.
     286 *
     287 * @param s the error message
     288 */
    291289void crerror(const char *s)
    292290{
     
    295293}
    296294
    297 // main
    298 //======================================================
    299 /* fonction principale : entrée dans le programme */
    300 //======================================================
     295/**
     296 * Parse the main.cfg file and fill the maps structure.
     297 *
     298 * @param file the filename to parse
     299 * @param my_map the maps structure to fill
     300 */
    301301int conf_read(const char* file,maps* my_map){
    302302 
     
    326326}
    327327
    328 
    329 //======================================================
    330 // FIN //
    331 //======================================================
  • trunk/zoo-project/zoo-kernel/service.h

    r601 r607  
    160160 */
    161161#define SERVICE_SIZE (ELEMENTS_SIZE*2)+(MAP_SIZE*2)+sizeof(char*)
     162/**
     163 * The memory size to create a services
     164 */
     165#define SERVICES_SIZE SERVICE_SIZE+sizeof(services*)
     166/**
     167 * The memory size to create a registry
     168 */
     169#define REGISTRY_SIZE SERVICES_SIZE+sizeof(char*)
    162170
    163171#define SHMSZ     27
     
    174182  /**
    175183   * KVP linked list
    176    *
    177    * Deal with WPS KVP (name,value).
    178    * A map is defined as:
    179    *  - name : a key,
    180    *  - value: a value,
    181    *  - next : a pointer to the next map if any.
    182184   */
    183185  typedef struct map{
    184     char* name;
    185     char* value;
    186     struct map* next;
     186    char* name; //!< the key
     187    char* value; //!< the value
     188    struct map* next; //!< the pointer to the next map if any or NULL
    187189  } map;
    188190
     
    197199   *
    198200   * Small object to store WPS KVP set.
    199    * Maps is defined as:
    200    *  - a name,
    201    *  - a content map,
    202    *  - a pointer to the next maps if any.
    203201   */
    204202  typedef struct maps{
    205     char* name;          
    206     struct map* content;
    207     struct maps* next;  
     203    char* name; //!< the maps name
     204    struct map* content; //!< the content map
     205    struct maps* next; //!< the pointer to the next maps if any or NULL
    208206  } maps;
    209207
     
    455453   *
    456454   * Used to store informations about formats, such as mimeType, encoding ...
    457    *
    458    * An iotype is defined as :
    459    *  - a content map,
    460    *  - a pointer to the next iotype if any.
    461455   */
    462456  typedef struct iotype{
    463     struct map* content;
    464     struct iotype* next;
     457    struct map* content; //!< the content map
     458    struct iotype* next; //!< the pointer to the next iotype if any or NULL
    465459  } iotype;
    466460
     
    469463   *
    470464   * The elements are used to store metadata informations defined in the ZCFG.
    471    *
    472    * An elements is defined as:
    473    *  - a name,
    474    *  - a content map,
    475    *  - a metadata map,
    476    *  - a format (possible values are LiteralData, ComplexData or
    477    * BoundingBoxData),
    478    *  - a default iotype,
    479    *  - a pointer to the next elements id any.
    480465   */
    481466  typedef struct elements{
    482     char* name;
    483     struct map* content;
    484     struct map* metadata;
    485     char* format;
    486     struct iotype* defaults;
    487     struct iotype* supported;
    488     struct elements* next;
     467    char* name; //!< the name
     468    struct map* content; //!< the content map
     469    struct map* metadata; //!< the metadata map
     470    char* format; //!< the format: LiteralData or ComplexData or BoundingBoxData
     471    struct iotype* defaults; //!< the default iotype
     472    struct iotype* supported; //!< the supported iotype
     473    struct elements* next; //!< the pointer to the next element if any (or NULL)
    489474  } elements;
    490475
    491476  /**
    492477   * Metadata informations about a full Service.
    493    *
    494    * An element is defined as:
    495    *  - a name,
    496    *  - a content map,
    497    *  - a metadata map,
    498    *  - an inputs elements
    499    *  - an outputs elements
    500478   */
    501479  typedef struct service{
    502     char* name;
    503     struct map* content;
    504     struct map* metadata;
    505     struct elements* inputs;
    506     struct elements* outputs;
     480    char* name; //!< the name
     481    struct map* content; //!< the content map
     482    struct map* metadata; //!< the metadata map
     483    struct elements* inputs; //!< the inputs elements
     484    struct elements* outputs; //!< the outputs elements
    507485  } service;
    508486
    509487  /**
    510    * Multiple services chained list.
     488   * Services chained list.
    511489   */
    512490  typedef struct services{
    513     struct service* content;
    514     struct services* next;
     491    struct service* content; //!< the content service pointer
     492    struct services* next; //!< the pointer to the next services*
    515493  } services;
     494
     495  /**
     496   * Profile registry.
     497   */
     498  typedef struct registry{
     499    char *name; //!< the name
     500    struct services* content; //!< the content services pointer
     501    struct registry* next; //!< the next registry pointer
     502  } registry;
    516503
    517504  /**
     
    12211208      tmp->metadata=NULL;
    12221209      addMapToMap(&tmp->metadata,e->metadata);
    1223       tmp->format=zStrdup(e->format);
     1210      if(e->format!=NULL)
     1211        tmp->format=zStrdup(e->format);
     1212      else
     1213        tmp->format=NULL;
    12241214      if(e->defaults!=NULL){
    12251215        tmp->defaults=(iotype*)malloc(IOTYPE_SIZE);
     
    13241314      fprintf(stderr,"\noutputs:\n");
    13251315      dumpElementsAsYAML(s->outputs);
     1316    }
     1317  }
     1318
     1319  /**
     1320   * Duplicate a service
     1321   *
     1322   * @param s the service to clone
     1323   * @return the allocated service containing a copy of the serfvice s
     1324   */
     1325  static service* dupService(service* s){
     1326    service *res=(service*)malloc(SERVICE_SIZE);
     1327    res->name=zStrdup(s->name);
     1328    res->content=NULL;
     1329    addMapToMap(&res->content,s->content);
     1330    res->metadata=NULL;
     1331    addMapToMap(&res->metadata,s->metadata);
     1332    res->inputs=dupElements(s->inputs);
     1333    res->outputs=dupElements(s->outputs);
     1334    return res;
     1335  }
     1336
     1337  /**
     1338   * Print the registry on stderr.
     1339   *
     1340   * @param r the registry
     1341   */
     1342  static void dumpRegistry(registry* r){
     1343    registry* p=r;
     1344    while(p!=NULL){
     1345      fprintf(stderr,"%s \n",p->name);
     1346      services* s=p->content;
     1347      s=p->content;
     1348      while(s!=NULL){
     1349        dumpService(s->content);
     1350        s=s->next;
     1351      }
     1352      p=p->next;
     1353    }
     1354  }
     1355
     1356  /**
     1357   * Add a service to the registry
     1358   *
     1359   * @param reg the resgitry to add the service
     1360   * @param name the registry name to update
     1361   * @param content the service to add
     1362   */
     1363  static bool addServiceToRegistry(registry** reg,char* name,service* content){
     1364    registry *l=*reg;
     1365    int isInitial=-1;
     1366    if(l==NULL){
     1367      l=(registry*)malloc(REGISTRY_SIZE);
     1368      isInitial=1;
     1369    }
     1370    if(l!=NULL){
     1371      int hasLevel=-1;
     1372      while(isInitial<0 && l!=NULL){
     1373        if(l->name!=NULL && strcasecmp(name,l->name)==0){
     1374          hasLevel=1;
     1375          break;
     1376        }
     1377        l=l->next;
     1378      }
     1379      if(hasLevel<0){
     1380        if(isInitial<0)
     1381          l=(registry*)malloc(REGISTRY_SIZE);
     1382        l->name=zStrdup(name);
     1383        l->content=NULL;
     1384        l->next=NULL;
     1385      }
     1386      if(l->content==NULL){
     1387        l->content=(services*)malloc(SERVICES_SIZE);
     1388        l->content->content=dupService(content);
     1389        l->content->next=NULL;
     1390      }
     1391      else{
     1392        services* s=l->content;
     1393        while(s->next!=NULL)
     1394          s=s->next;
     1395        s->next=(services*)malloc(SERVICES_SIZE);
     1396        s->next->content=dupService(content);
     1397        s->next->next=NULL;
     1398      }
     1399      l->next=NULL;
     1400      if(isInitial>0)
     1401        *reg=l;
     1402      else{
     1403        registry *r=*reg;
     1404        while(r->next!=NULL)
     1405          r=r->next;
     1406        r->next=l;
     1407        r->next->next=NULL;
     1408      }
     1409      return true;
     1410    }
     1411    else
     1412      return false;
     1413  }
     1414
     1415  /**
     1416   * Free memory allocated for the registry
     1417   *
     1418   * @param r the registry
     1419   */
     1420  static void freeRegistry(registry** r){
     1421    registry* lr=*r;
     1422    while(lr!=NULL){
     1423      services* s=lr->content;
     1424      free(lr->name);
     1425      while(s!=NULL){
     1426        service* s1=s->content;
     1427        s=s->next;
     1428        if(s1!=NULL){
     1429          freeService(&s1);
     1430          free(s1);
     1431          s1=NULL;
     1432        }
     1433      }
     1434      lr=lr->next;
     1435    }   
     1436  }
     1437
     1438  /**
     1439   * Access a service in the registry
     1440   *
     1441   * @param r the registry
     1442   * @param level the regitry to search ("concept", "generic" or "implementation")
     1443   * @param sname the service name
     1444   * @return the service pointer if a corresponding service was found or NULL
     1445   */
     1446  static service* getServiceFromRegistry(registry* r,char  *level,char* sname){
     1447    registry *lr=r;
     1448    while(lr!=NULL){
     1449      if(strcasecmp(lr->name,level)==0){
     1450        services* s=lr->content;
     1451        while(s!=NULL){
     1452          if(s->content!=NULL && strcasecmp(s->content->name,sname)==0)
     1453            return s->content;
     1454          s=s->next;
     1455        }
     1456        break;
     1457      }
     1458      lr=lr->next;
     1459    }
     1460    return NULL;
     1461  }
     1462
     1463  /**
     1464   * Apply inheritance to an out map from a reference in map
     1465   *
     1466   * @param out the map to update
     1467   * @param in the reference map (containing inherited properties)
     1468   */
     1469  static void inheritMap(map** out,map* in){
     1470    map* content=in;
     1471    while(content!=NULL && *out!=NULL){
     1472      map* cmap=getMap(*out,content->name);
     1473      if(cmap==NULL)
     1474        addToMap(*out,content->name,content->value);
     1475      content=content->next;
     1476    }
     1477  }
     1478
     1479  /**
     1480   * Apply inheritance to an out iotype from a reference in iotype
     1481   *
     1482   * @param out the iotype to update
     1483   * @param in the reference iotype (containing inherited properties)
     1484   */
     1485  static void inheritIOType(iotype** out,iotype* in){
     1486    iotype* io=in;
     1487    iotype* oio=*out;
     1488    if(io!=NULL){
     1489      if(*out==NULL){
     1490        *out=(iotype*)malloc(IOTYPE_SIZE);
     1491        (*out)->content=NULL;
     1492        addMapToMap(&(*out)->content,io->content);
     1493        (*out)->next=NULL;
     1494        oio=*out;
     1495        inheritIOType(&oio->next,io->next);
     1496      }else{
     1497        inheritIOType(&oio->next,io->next);
     1498      }
     1499    }
     1500  }
     1501
     1502  /**
     1503   * Apply inheritance to an out elements from a reference in elements
     1504   *
     1505   * @param out the elements to update
     1506   * @param in the reference elements (containing inherited properties)
     1507   */
     1508  static void inheritElements(elements** out,elements* in){
     1509    elements* content=in;
     1510    while(content!=NULL && *out!=NULL){
     1511      elements* cmap=getElements(*out,content->name);
     1512      if(cmap==NULL)
     1513        addToElements(out,content);
     1514      else{
     1515        inheritMap(&cmap->content,content->content);
     1516        inheritMap(&cmap->metadata,content->metadata);
     1517        if(cmap->format==NULL && content->format!=NULL)
     1518          cmap->format=zStrdup(content->format);
     1519        inheritIOType(&cmap->defaults,content->defaults);
     1520        if(cmap->supported==NULL)
     1521          inheritIOType(&cmap->supported,content->supported);
     1522        else{
     1523          iotype* p=content->supported;
     1524          while(p!=NULL){
     1525            addMapToIoType(&cmap->supported,p->content);
     1526            p=p->next;
     1527          }
     1528        }
     1529      }
     1530      content=content->next;
     1531    }
     1532  }
     1533
     1534  /**
     1535   * Apply inheritance to a service based on a registry
     1536   *
     1537   * @param r the registry storing profiles hierarchy
     1538   * @param s the service to update depending on its inheritance
     1539   */
     1540  static void inheritance(registry *r,service** s){
     1541    if(r==NULL)
     1542      return;
     1543    service* ls=*s;
     1544    if(ls->content==NULL)
     1545      return;
     1546    map* profile=getMap(ls->content,"extend");
     1547    map* level=getMap(ls->content,"level");
     1548    if(profile!=NULL&&level!=NULL){
     1549      service* s1;
     1550      if(strncasecmp(level->value,"profile",7)==0)
     1551        s1=getServiceFromRegistry(r,"generic",profile->value);
     1552      else
     1553        s1=getServiceFromRegistry(r,level->value,profile->value);
     1554     
     1555      inheritMap(&ls->content,s1->content);
     1556      inheritMap(&ls->metadata,s1->metadata);
     1557      if(ls->inputs==NULL && s1->inputs!=NULL){
     1558        ls->inputs=dupElements(s1->inputs);
     1559      }else{
     1560        inheritElements(&ls->inputs,s1->inputs);
     1561      }
     1562      if(ls->outputs==NULL && s1->outputs!=NULL){
     1563        ls->outputs=dupElements(s1->outputs);
     1564      }else
     1565        inheritElements(&ls->outputs,s1->outputs);
    13261566    }
    13271567  }
  • trunk/zoo-project/zoo-kernel/service_conf.y

    r539 r607  
    1 %{
    2 //======================================================
    3 /**
     1/*
    42 * Thx to Jean-Marie CODOL and Naitan GROLLEMUND
    53 * copyright 2009 GeoLabs SARL
     
    75 *
    86 */
    9 //======================================================
     7%{
    108
    119#include <string>
     
    2220static bool wait_defaults=false;
    2321static bool wait_supporteds=false;
    24 static bool wait_outputs=false;
     22static bool wait_outputs=-1;
    2523static bool wait_data=false;
    2624static service* my_service=NULL;
     
    3432// namespace
    3533using namespace std;
    36 //======================================================
    3734
    3835// srerror
    3936void srerror(const char *s);
    40 //======================================================
    4137
    4238// usage ()
    4339void usage(void) ;
    44 //======================================================
    4540
    4641// srdebug
    4742extern int srdebug;
    48 //======================================================
    4943
    5044extern char srtext[];
     
    5246// srlineno
    5347extern int srlineno;
    54 //======================================================
    5548
    5649// srin
    5750extern FILE* srin;
    58 //======================================================
    5951
    6052// srlex
    6153extern int srlex(void);
    6254extern int srlex_destroy(void);
    63 
    64 //vector<char*> lattribute;
    6555
    6656%}
     
    7666/* STARTXMLDECL et ENDXMLDECL qui sont <?xml et ?>*/
    7767%token STARTXMLDECL ENDXMLDECL
    78 //======================================================
     68
    7969/* version="xxx" et encoding="xxx" */
    8070%token VERSIONDECL ENCODINGDECL SDDECL
    81 //======================================================
     71
    8272/* < et > */
    8373%token INFCAR SUPCAR
    84 //======================================================
     74
    8575/* / = a1  texte "texte" */
    8676%token SLASH Eq CHARDATA ATTVALUE PAIR SPAIR EPAIR ANID
     
    8878%type <chaine> EPAIR
    8979%type <chaine> SPAIR
    90 //======================================================
     80
    9181/* <!-- xxx -> <? xxx yyy ?> */
    9282%token PI PIERROR /** COMMENT **/
    93 //======================================================
     83
    9484/* <!-- xxx -> <? xxx yyy ?> */
    9585%token ERREURGENERALE CDATA WHITESPACE NEWLINE
     
    9787%type <s> ETag
    9888%type <s> ANID
    99 //======================================================
    100 // %start
    101 //======================================================
     89
     90// % start
    10291
    10392%%
    104 // document <//===
    105 //======================================================
     93// document
    10694// regle 1
    10795// on est a la racine du fichier xml
    108 //======================================================
    10996document
    11097 : miscetoile element miscetoile {}
     
    118105 ;
    119106// element
    120 //======================================================
    121107// regle 39
    122108// OUVRANTE CONTENU FERMANTE obligatoirement
     
    124110// on ne peut pas avoir Epsilon
    125111// un fichier xml ne peut pas etre vide ou seulement avec un prolog
    126 //======================================================
    127112element
    128113 : STag contentetoile ETag     
     
    136121 ;
    137122
    138 //======================================================
    139123// STag
    140 //======================================================
    141124// regle 40
    142125// BALISE OUVRANTE
    143126// on est obligé de faire appel a infcar et supcar
    144127// pour acceder aux start conditions DANSBALISE et INITIAL
    145 //======================================================
    146128STag
    147129: INFCAR ID Attributeetoile SUPCAR
     
    150132  fprintf(stderr,"(%s %d) %s\n",__FILE__,__LINE__,$2);
    151133  fflush(stderr);
     134  dumpMap(current_content);
    152135#endif
    153136  if(my_service->content==NULL){
     
    163146  }
    164147  if(strncasecmp($2,"DataInputs",10)==0){
    165     if(wait_mainmetadata==true){
     148    if(wait_mainmetadata==true && current_content!=NULL){
    166149      addMapToMap(&my_service->metadata,current_content);
    167150      freeMap(&current_content);
     
    238221        current_element->next=NULL;
    239222      }
    240       wait_outputs=true;
     223      wait_outputs=1;
    241224      current_data=2;
    242225      previous_data=2;
     
    323306 ;
    324307
    325 //======================================================
    326308// Attributeetoile
    327 //======================================================
    328309// regle 41
    329310// une liste qui peut etre vide d'attributs
    330311// utiliser la récursivité a gauche
    331 //======================================================
    332312Attributeetoile
    333313 : Attributeetoile attribute  {}
     
    335315 ;
    336316
    337 //======================================================
    338317// attribute
    339 //======================================================
    340318// regle 41
    341319// un attribut est compose d'un identifiant
     
    343321// et d'une définition de chaine de caractere
    344322// ( "xxx" ou 'xxx' )
    345 //======================================================
    346323attribute
    347324 : ID Eq ATTVALUE               
     
    353330 ;
    354331
    355 //======================================================
    356332// EmptyElemTag
    357 //======================================================
    358333// regle 44
    359334// ICI ON DEFINIT NEUTRE
     
    361336// parce qu'il n'y a pas de comparaisons a faire
    362337// avec un identifiant d'une balise jumelle
    363 //======================================================
    364338EmptyElemTag
    365339 : INFCAR ID Attributeetoile SLASH SUPCAR       {
     
    386360 ;
    387361
    388 //======================================================
    389362// ETag
    390 //======================================================
    391 // regle 42
    392363// BALISE FERMANTE
    393364// les separateurs après ID sont filtrés
    394 //======================================================
    395365ETag
    396366 : INFCAR SLASH ID SUPCAR
     
    401371  if(strcmp($3,"DataInputs")==0){
    402372    current_data=1;
     373    if(current_content!=NULL){
     374      if(current_element->content==NULL){
     375        addMapToMap(&current_element->content,current_content);
     376      }
     377      freeMap(&current_content);
     378      free(current_content);
     379      current_content=NULL;
     380    }
     381    if(current_element!=NULL){
     382      if(my_service->content!=NULL && current_element->name!=NULL){
     383        if(my_service->inputs==NULL){
     384          my_service->inputs=dupElements(current_element);
     385          my_service->inputs->next=NULL;
     386          tmp_count++;
     387        }
     388        else{
     389          addToElements(&my_service->inputs,current_element);
     390        }
     391        freeElements(&current_element);
     392        free(current_element);
     393        current_element=NULL;
     394      }
     395    }
    403396  }
    404397  if(strcmp($3,"DataOutputs")==0){
     
    489482 ;
    490483
    491 //======================================================
    492484// texteinterbalise
    493 //======================================================
    494485// regle 14
    495486// DU TEXTE quelconque
     
    499490// maintenant on croise les ID dans les dbalises
    500491// et des CHARDATA hors des balises
    501 //======================================================
    502492texteinterbalise
    503493 : CHARDATA             {}
    504494 ;
    505 //======================================================
    506495
    507496pair: PAIR { if(debug) fprintf(stderr,"PAIR FOUND !!\n");if(curr_key!=NULL){free(curr_key);curr_key=NULL;} }
     
    637626    else
    638627      if(current_data==2){
    639         wait_outputs=true;
     628        wait_outputs=1;
    640629        if(wait_inputs){
    641630          if(current_element!=NULL && current_element->name!=NULL){
     
    746735          }
    747736        wait_inputs=false;
    748         wait_outputs=true;
     737        wait_outputs=1;
    749738        //wait_outputs=true;
    750739      }
     
    755744%%
    756745
    757 // srerror
    758 //======================================================
    759 /* fonction qui affiche l erreur si il y en a une */
    760 //======================================================
     746/**
     747 * Print on stderr the message and the line number of the error which occured.
     748 *
     749 * @param s the error message
     750 */
    761751void srerror(const char *s)
    762752{
     
    766756
    767757/**
    768  * getServiceFromFile :
    769  * set service given as second parameter with informations extracted from the
    770  * definition file.
     758 * Parse a ZCFG file and fill the service structure.
     759 *
     760 * @param conf the conf maps containing the main.cfg settings
     761 * @param file the fullpath to the ZCFG file
     762 * @param service the service structure to fill
     763 * @return 0 on success, -1 on failure
    771764 */
    772765int getServiceFromFile(maps* conf,const char* file,service** service){
     
    792785  wait_defaults=false;
    793786  wait_supporteds=false;
    794   wait_outputs=false;
     787  wait_outputs=-1;
    795788  wait_data=false;
    796789  data=-1;
     
    810803#ifdef DEBUG_SERVICE_CONF
    811804  fprintf(stderr,"RESULT: %d %d\n",resultatYYParse,wait_outputs);
    812 #endif
    813   if(wait_outputs && current_element!=NULL && current_element->name!=NULL){
    814     if(my_service->outputs==NULL){     
     805  dumpElements(current_element);
     806#endif
     807  if(wait_outputs>0 && current_element!=NULL && current_element->name!=NULL){
     808    if(my_service->outputs==NULL){ 
    815809#ifdef DEBUG_SERVICE_CONF
    816810      fprintf(stderr,"(DATAOUTPUTS - %d) DUP current_element\n",__LINE__);
     
    840834    current_element=NULL;
    841835  }
     836  int contentOnly=-1;
    842837  if(current_content!=NULL){
     838    if(my_service->content==NULL){
     839      addMapToMap(&my_service->content,current_content);
     840      contentOnly=1;
     841    }
    843842    freeMap(&current_content);
    844843    free(current_content);
     
    849848  dumpService(my_service);
    850849#endif
    851   if(wait_outputs<0 || my_service==NULL || my_service->name==NULL || my_service->content==NULL || my_service->outputs==NULL){
    852     fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
     850  if(contentOnly<0 && ((wait_outputs<0 && current_data==2 && my_service->outputs==NULL) || my_service==NULL || my_service->name==NULL || my_service->content==NULL)){
    853851    setMapInMaps(conf,"lenv","message",srlval.chaine);
    854852#ifndef WIN32
  • trunk/zoo-project/zoo-kernel/service_internal.c

    r605 r607  
    12261226 *
    12271227 * @param m the conf maps containing the main.cfg settings
     1228 * @param registry the profile registry if any
    12281229 * @param nc the XML node to add the Process node
    12291230 * @param serv the service structure created from the zcfg file
  • trunk/zoo-project/zoo-kernel/service_internal_ms.c

    r586 r607  
    131131  outputMapfile(m,tmpI);
    132132  map *msUrl=getMapFromMaps(m,"main","mapserverAddress");
     133  if(msUrl==NULL){
     134    errorException (m, _("Unable to find any mapserverAddress defined in the main.cfg file"),
     135                    "InternalError", NULL);
     136    exit(-1);
     137  }
    133138  map *msOgcVersion=getMapFromMaps(m,"main","msOgcVersion");
    134139  map *dataPath=getMapFromMaps(m,"main","dataPath");
     
    794799    char *pszProjection;
    795800    pszProjection = (char *) GDALGetProjectionRef( hDataset );
    796     //#ifdef DEBUGMS
     801#ifdef DEBUGMS
    797802    fprintf(stderr,"Accessing the DataSource %s\n",GDALGetProjectionRef( hDataset ));
    798     //#endif
     803#endif
    799804    setSrsInformations(output,m,myLayer,pszProjection);
    800805  }else{
  • trunk/zoo-project/zoo-kernel/service_internal_php.c

    r605 r607  
    247247      HashTable* t=HASH_OF(iargs[2]);
    248248      HashTable* t1=HASH_OF(iargs[0]);
     249      freeMaps(real_outputs);
     250      free(*real_outputs);
     251      freeMaps(main_conf);
     252      free(*main_conf);
    249253      *real_outputs=php_maps_from_Array(t);
    250254      *main_conf=php_maps_from_Array(t1);
  • trunk/zoo-project/zoo-kernel/ulinet.c

    r579 r607  
    329329#endif
    330330    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_POSTFIELDS,lpszHeaders);
    331     //curl_easy_setopt(hInternet->handle,CURLOPT_POSTFIELDSIZE,dwHeadersLength+1);
    332     if(hInternet->ihandle[hInternet->nb].header!=NULL)
    333       curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_HTTPHEADER,hInternet->ihandle[hInternet->nb].header);
    334   }
     331    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_POSTFIELDSIZE,dwHeadersLength+1);
     332  }
     333  if(hInternet->ihandle[hInternet->nb].header!=NULL)
     334    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_HTTPHEADER,hInternet->ihandle[hInternet->nb].header);
    335335
    336336  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_URL,lpszUrl);
     
    366366    if(tmp!=NULL)
    367367      hInternet->ihandle[i].mimeType=strdup(tmp);
     368    curl_easy_getinfo(hInternet->ihandle[i].handle,CURLINFO_RESPONSE_CODE,&hInternet->ihandle[i].code);
    368369    curl_multi_remove_handle(hInternet->handle, hInternet->ihandle[i].handle);
    369370    curl_easy_cleanup(hInternet->ihandle[i].handle);
     
    437438}
    438439
     440
     441/**
     442 * Use basic authentication for accessing a ressource
     443 *
     444 * @param hInternet the _HINTERNET structure
     445 * @param login the login to use to authenticate
     446 * @param passwd the password to use to authenticate
     447 */
     448int setBasicAuth(HINTERNET hInternet,char* login,char* passwd){
     449  char *tmp;
     450  tmp=(char*)malloc((strlen(login)+strlen(passwd)+2)*sizeof(char));
     451  sprintf(tmp,"%s:%s",login,passwd);
     452  if(curl_easy_setopt(hInternet.ihandle[hInternet.nb].handle,CURLOPT_USERPWD,tmp)==CURLE_OUT_OF_MEMORY){
     453    free(tmp);
     454    return -1;
     455  }
     456  curl_easy_setopt(hInternet.ihandle[hInternet.nb].handle, CURLOPT_HTTPAUTH,CURLAUTH_ANY);
     457  free(tmp);
     458  return 0;
     459}
  • trunk/zoo-project/zoo-kernel/ulinet.h

    r579 r607  
    6666#endif
    6767
    68 struct MemoryStruct {
    69   char *memory; //!< the memory space to store data
    70   size_t size; //!< side of the memory space
    71 };
     68  struct MemoryStruct {
     69    char *memory; //!< the memory space to store data
     70    size_t size; //!< size of the memory space
     71  };
    7272
    7373  /**
    7474   * Individual CURL handler
    7575   */
    76 typedef struct {
    77   CURL *handle; //!< the CURL handler
    78   struct curl_slist *header; //!< the headers to send
    79   char* filename; //!< the cached file name
    80   FILE* file; //!< the file pointer
    81   unsigned char *pabyData; //!< the downloaded content
    82   char *mimeType; //!< the mimeType returned by the server
    83   int hasCacheFile; //!< 1 if we used a cache file
    84   int nDataLen; //!< the length of the downloaded content
    85   int nDataAlloc; //!<
    86   int id; //!< The position of the element in the queue
    87 } _HINTERNET;
     76  typedef struct {
     77    CURL *handle; //!< the CURL handler
     78    struct curl_slist *header; //!< the headers to send
     79    char* filename; //!< the cached file name
     80    FILE* file; //!< the file pointer
     81    unsigned char *pabyData; //!< the downloaded content
     82    char *mimeType; //!< the mimeType returned by the server
     83    int hasCacheFile; //!< 1 if we used a cache file
     84    int nDataLen; //!< the length of the downloaded content
     85    int nDataAlloc; //!<
     86    long code; //!< the last received response code
     87    int id; //!< The position of the element in the queue
     88  } _HINTERNET;
    8889
    8990  /**
    9091   * Multiple CURL handlers
    9192   */
    92 typedef struct {
    93   CURLM *handle; //!< the CURLM handler
    94   _HINTERNET ihandle[MAX_REQ]; //!< individual handlers in the queue
    95   char *waitingRequests[MAX_REQ]; //!< request in the queue
    96   char *agent; //!< The User-Agent to use for HTTP request
    97   int nb; //!< number of element in the queue
    98 } HINTERNET;
     93  typedef struct {
     94    CURLM *handle; //!< the CURLM handler
     95    _HINTERNET ihandle[MAX_REQ]; //!< individual handlers in the queue
     96    char *waitingRequests[MAX_REQ]; //!< request in the queue
     97    char *agent; //!< The User-Agent to use for HTTP request
     98    int nb; //!< number of element in the queue
     99  } HINTERNET;
    99100
    100 size_t write_data_into(void *buffer, size_t size, size_t nmemb, void *data);
     101  size_t write_data_into(void*,size_t,size_t,void*);
    101102
    102 size_t header_write_data(void *buffer, size_t size, size_t nmemb, void *data);
     103  size_t header_write_data(void*,size_t,size_t,void*);
    103104
    104 void setProxy(CURL* handle,char* host,long port);
     105  void setProxy(CURL*,char*,long);
    105106
    106107#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
     
    108109#include <CoreServices/CoreServices.h>
    109110#include <SystemConfiguration/SystemConfiguration.h>
    110 char* CFStringToCString(CFStringRef dest,char * buffer);
    111 OSStatus setProxiesForProtcol(CURL* handle,const char *proto);
     111  char* CFStringToCString(CFStringRef,char*);
     112  OSStatus setProxiesForProtcol(CURL*,const char*);
    112113
    113114#else
    114115
    115116//#include <gconf/gconf-client.h>
    116 int setProxiesForProtcol(CURL* handle,const char *proto);
     117  int setProxiesForProtcol(CURL*,const char*);
    117118
    118119#endif
     
    126127typedef char* LPCTSTR;
    127128#endif
    128 HINTERNET InternetOpen(char* lpszAgent,int dwAccessType,char* lpszProxyName,char* lpszProxyBypass,int dwFlags);
     129  HINTERNET InternetOpen(char*,int,char*,char*,int);
    129130
    130 void InternetCloseHandle(HINTERNET* handle);
     131  void InternetCloseHandle(HINTERNET*);
    131132
    132133#define INTERNET_FLAG_EXISTING_CONNECT         0
     
    143144//typedef char* LPVOID;
    144145#ifndef WIN32
    145 typedef void* LPVOID;
    146 typedef void* LPTSTR;
    147 typedef size_t* LPDWORD;
     146  typedef void* LPVOID;
     147  typedef void* LPTSTR;
     148  typedef size_t* LPDWORD;
    148149#endif
    149150#ifndef bool
     
    153154#  define CHECK_INET_HANDLE(h) (h.handle != 0)
    154155
    155 HINTERNET InternetOpenUrl(HINTERNET* hInternet,LPCTSTR lpszUrl,LPCTSTR lpszHeaders,size_t dwHeadersLength,size_t dwFlags,size_t dwContext);
     156  HINTERNET InternetOpenUrl(HINTERNET*,LPCTSTR,LPCTSTR,size_t,size_t,size_t);
    156157
    157 int processDownloads(HINTERNET* hInternet);
     158  int processDownloads(HINTERNET*);
    158159
    159 int freeCookieList(HINTERNET hInternet);
     160  int freeCookieList(HINTERNET);
    160161
    161 int InternetReadFile(_HINTERNET hInternet,LPVOID lpBuffer,int dwNumberOfBytesToRead,size_t *lpdwNumberOfBytesRead);
     162  int InternetReadFile(_HINTERNET,LPVOID,int,size_t*);
     163
     164  int setBasicAuth(HINTERNET,char*,char*);
    162165
    163166#ifdef __cplusplus
  • trunk/zoo-project/zoo-kernel/zoo_loader.c

    r605 r607  
    1 /**
     1/*
    22 * Author : Gérald FENOY
    33 *
     
    6767#endif
    6868
     69/**
     70 * Main entry point for cgic.
     71 * @return 0 on sucess.
     72 */
    6973int cgiMain(){
    7074  /**
  • trunk/zoo-project/zoo-kernel/zoo_service_loader.c

    r605 r607  
    1 /**
     1/*
    22 * Author : Gérald FENOY
    33 *
     
    120120#endif
    121121
     122/**
     123 * Translation function for zoo-kernel
     124 */
    122125#define _(String) dgettext ("zoo-kernel",String)
     126/**
     127 * Translation function for zoo-service
     128 */
    123129#define __(String) dgettext ("zoo-service",String)
    124130
     
    131137extern int getServiceFromFile (maps *, const char *, service **);
    132138
     139/**
     140 * Parse the service file using getServiceFromFile or use getServiceFromYAML
     141 * if YAML support was activated.
     142 *
     143 * @param conf the conf maps containing the main.cfg settings
     144 * @param file the file name to parse
     145 * @param service the service to update witht the file content
     146 * @param name the service name
     147 * @return true if the file can be parsed or false
     148 * @see getServiceFromFile, getServiceFromYAML
     149 */
    133150int
    134151readServiceFile (maps * conf, char *file, service ** service, char *name)
     
    144161}
    145162
     163/**
     164 * Replace a char by another one in a string
     165 *
     166 * @param str the string to update
     167 * @param toReplace the char to replace
     168 * @param toReplaceBy the char that will be used
     169 */
    146170void
    147171translateChar (char *str, char toReplace, char toReplaceBy)
     
    156180
    157181/**
    158  * Create (or append to) an array valued maps
    159  * value = "["",""]"
     182 * Create (or append to) an array valued maps value = "["",""]"
     183 *
     184 * @param m the conf maps containing the main.cfg settings
     185 * @param mo the map to update
     186 * @param mi the map to append
     187 * @param elem the elements containing default definitions
     188 * @return 0 on success, -1 on failure
    160189 */
    161190int
     
    237266}
    238267
     268/**
     269 * Create the profile registry.
     270 *
     271 * The profile registry is optional (created only if the registry key is
     272 * available in the [main] section of the main.cfg file) and can be used to
     273 * store the profiles hierarchy. The registry is a directory which should
     274 * contain the following sub-directories:
     275 *  * concept: direcotry containing .html files describing concept
     276 *  * generic: directory containing .zcfg files for wps:GenericProcess
     277 *  * implementation: directory containing .zcfg files for wps:Process
     278 *
     279 * @param m the conf maps containing the main.cfg settings
     280 * @param r the registry to update
     281 * @param reg_dir the resgitry
     282 * @param saved_stdout the saved stdout identifier
     283 * @return 0 if the resgitry is null or was correctly updated, -1 on failure
     284 */
    239285int
    240 recursReaddirF (maps * m, xmlNodePtr n, char *conf_dir, char *prefix,
     286createRegistry (maps* m,registry ** r, char *reg_dir, int saved_stdout)
     287{
     288  struct dirent *dp;
     289  int scount = 0;
     290
     291  if (reg_dir == NULL)
     292    return 0;
     293  DIR *dirp = opendir (reg_dir);
     294  if (dirp == NULL)
     295    {
     296      return -1;
     297    }
     298  while ((dp = readdir (dirp)) != NULL){
     299    if ((dp->d_type == DT_DIR || dp->d_type == DT_LNK) && dp->d_name[0] != '.')
     300      {
     301
     302        char * tmpName =
     303          (char *) malloc ((strlen (reg_dir) + strlen (dp->d_name) + 2) *
     304                           sizeof (char));
     305        sprintf (tmpName, "%s/%s", reg_dir, dp->d_name);
     306       
     307        DIR *dirp1 = opendir (tmpName);
     308        struct dirent *dp1;
     309        while ((dp1 = readdir (dirp1)) != NULL){
     310          char* extn = strstr(dp1->d_name, ".zcfg");
     311          if(dp1->d_name[0] != '.' && extn != NULL && strlen(extn) == 5)
     312            {
     313              int t;
     314              char *tmps1=
     315                (char *) malloc ((strlen (tmpName) + strlen (dp1->d_name) + 2) *
     316                                 sizeof (char));
     317              sprintf (tmps1, "%s/%s", tmpName, dp1->d_name);
     318              char *tmpsn = zStrdup (dp1->d_name);
     319              tmpsn[strlen (tmpsn) - 5] = 0;
     320              service* s1 = (service *) malloc (SERVICE_SIZE);
     321              if (s1 == NULL)
     322                {
     323                  dup2 (saved_stdout, fileno (stdout));
     324                  errorException (m, _("Unable to allocate memory."),
     325                                  "InternalError", NULL);
     326                  return -1;
     327                }
     328              t = readServiceFile (m, tmps1, &s1, tmpsn);
     329              free (tmpsn);
     330              if (t < 0)
     331                {
     332                  map *tmp00 = getMapFromMaps (m, "lenv", "message");
     333                  char tmp01[1024];
     334                  if (tmp00 != NULL)
     335                    sprintf (tmp01, _("Unable to parse the ZCFG file: %s (%s)"),
     336                             dp1->d_name, tmp00->value);
     337                  else
     338                    sprintf (tmp01, _("Unable to parse the ZCFG file: %s."),
     339                             dp1->d_name);
     340                  dup2 (saved_stdout, fileno (stdout));
     341                  errorException (m, tmp01, "InternalError", NULL);
     342                  return -1;
     343                }
     344#ifdef DEBUG
     345              dumpService (s1);
     346              fflush (stdout);
     347              fflush (stderr);
     348#endif
     349              if(strncasecmp(dp->d_name,"implementation",14)==0){
     350                inheritance(*r,&s1);
     351              }
     352              addServiceToRegistry(r,dp->d_name,s1);
     353              freeService (&s1);
     354              free (s1);
     355              scount++;
     356            }
     357        }
     358        (void) closedir (dirp1);
     359      }
     360  }
     361  (void) closedir (dirp);
     362  return 0;
     363}
     364
     365/**
     366 * Recursivelly parse zcfg starting from the ZOO-Kernel cwd.
     367 * Call the func function given in arguments after parsing the ZCFG file.
     368 *
     369 * @param m the conf maps containing the main.cfg settings
     370 * @param r the registry containing profiles hierarchy
     371 * @param n the root XML Node to add the sub-elements
     372 * @param conf_dir the location of the main.cfg file (basically cwd)
     373 * @param prefix the current prefix if any, or NULL
     374 * @param saved_stdout the saved stdout identifier
     375 * @param level the current level (number of sub-directories to reach the
     376 * current path)
     377 * @see inheritance, readServiceFile
     378 */
     379int
     380recursReaddirF (maps * m, registry *r, xmlNodePtr n, char *conf_dir, char *prefix,
    241381                int saved_stdout, int level, void (func) (maps *, xmlNodePtr,
    242382                                                          service *))
     
    287427            setMapInMaps (m, "lenv", "level", levels1);
    288428            res =
    289               recursReaddirF (m, n, tmp, prefix, saved_stdout, level + 1,
     429              recursReaddirF (m, r, n, tmp, prefix, saved_stdout, level + 1,
    290430                              func);
    291431            sprintf (levels1, "%d", level);
     
    346486            fflush (stderr);
    347487#endif
     488            inheritance(r,&s1);
    348489            func (m, n, s1);
    349490            freeService (&s1);
     
    356497}
    357498
     499/**
     500 * Apply XPath Expression on XML document.
     501 *
     502 * @param doc the XML Document
     503 * @param search the XPath expression
     504 * @return xmlXPathObjectPtr containing the resulting nodes set
     505 */
    358506xmlXPathObjectPtr
    359507extractFromDoc (xmlDocPtr doc, const char *search)
     
    367515}
    368516
     517/**
     518 * Signal handling function which simply call exit(0).
     519 *
     520 * @param sig the signal number
     521 */
    369522void
    370523donothing (int sig)
     
    376529}
    377530
     531/**
     532 * Signal handling function which create an ExceptionReport node containing the
     533 * information message corresponding to the signal number.
     534 *
     535 * @param sig the signal number
     536 */
    378537void
    379538sig_handler (int sig)
     
    416575}
    417576
     577/**
     578 * Load a service provider and run the service function.
     579 *
     580 * @param myMap the conf maps containing the main.cfg settings
     581 * @param s1 the service structure
     582 * @param request_inputs map storing all the request parameters
     583 * @param inputs the inputs maps
     584 * @param ioutputs the outputs maps
     585 * @param eres the result returned by the service execution
     586 */
    418587void
    419588loadServiceAndRun (maps ** myMap, service * s1, map * request_inputs,
     
    8761045#endif
    8771046
     1047/**
     1048 * Process the request.
     1049 *
     1050 * @param inputs the request parameters map
     1051 * @return 0 on sucess, other value on failure
     1052 * @see conf_read,recursReaddirF
     1053 */
    8781054int
    8791055runRequest (map ** inputs)
     
    11131289    SERVICE_URL = zStrdup (DEFAULT_SERVICE_URL);
    11141290
     1291
     1292
    11151293  service *s1;
    11161294  int scount = 0;
     
    11291307  else
    11301308    snprintf (conf_dir, 1024, "%s", ntmp);
     1309
     1310  map* reg = getMapFromMaps (m, "main", "registry");
     1311  registry* zooRegistry=NULL;
     1312  if(reg!=NULL){
     1313    int saved_stdout = dup (fileno (stdout));
     1314    dup2 (fileno (stderr), fileno (stdout));
     1315    createRegistry (m,&zooRegistry,reg->value,saved_stdout);
     1316    dup2 (saved_stdout, fileno (stdout));
     1317  }
    11311318
    11321319  if (strncasecmp (REQUEST, "GetCapabilities", 15) == 0)
     
    11461333      dup2 (fileno (stderr), fileno (stdout));
    11471334      if (int res =               
    1148           recursReaddirF (m, n, conf_dir, NULL, saved_stdout, 0,
     1335          recursReaddirF (m, zooRegistry, n, conf_dir, NULL, saved_stdout, 0,
    11491336                          printGetCapabilitiesForProcess) < 0)
    11501337        {
    11511338          freeMaps (&m);
    11521339          free (m);
     1340          if(zooRegistry!=NULL){
     1341            freeRegistry(&zooRegistry);
     1342            free(zooRegistry);
     1343          }
    11531344          free (REQUEST);
    11541345          free (SERVICE_URL);
     
    11601351      freeMaps (&m);
    11611352      free (m);
     1353      if(zooRegistry!=NULL){
     1354        freeRegistry(&zooRegistry);
     1355        free(zooRegistry);
     1356      }
    11621357      free (REQUEST);
    11631358      free (SERVICE_URL);
     
    11771372          freeMaps (&m);
    11781373          free (m);
     1374          if(zooRegistry!=NULL){
     1375            freeRegistry(&zooRegistry);
     1376            free(zooRegistry);
     1377          }
    11791378          free (REQUEST);
    11801379          free (SERVICE_URL);
     
    12001399            {
    12011400              if (int res =
    1202                   recursReaddirF (m, n, conf_dir, NULL, saved_stdout, 0,
     1401                  recursReaddirF (m, zooRegistry, n, conf_dir, NULL, saved_stdout, 0,
    12031402                                  printDescribeProcessForProcess) < 0)
    12041403                return res;
     
    12451444                          freeMaps (&m);
    12461445                          free (m);
     1446                          if(zooRegistry!=NULL){
     1447                            freeRegistry(&zooRegistry);
     1448                            free(zooRegistry);
     1449                          }
    12471450                          free (REQUEST);
    12481451                          free (corig);
     
    12591462                      dumpService (s1);
    12601463#endif
     1464                      inheritance(zooRegistry,&s1);
    12611465                      printDescribeProcessForProcess (m, n, s1);
    12621466                      freeService (&s1);
     
    13211525                                  freeMaps (&m);
    13221526                                  free (m);
     1527                                  if(zooRegistry!=NULL){
     1528                                    freeRegistry(&zooRegistry);
     1529                                    free(zooRegistry);
     1530                                  }
    13231531                                  free (orig);
    13241532                                  free (REQUEST);
     
    13321540                              dumpService (s1);
    13331541#endif
     1542                              inheritance(zooRegistry,&s1);
    13341543                              printDescribeProcessForProcess (m, n, s1);
    13351544                              freeService (&s1);
     
    13581567                      freeMaps (&m);
    13591568                      free (m);
     1569                      if(zooRegistry!=NULL){
     1570                        freeRegistry(&zooRegistry);
     1571                        free(zooRegistry);
     1572                      }
    13601573                      free (orig);
    13611574                      free (REQUEST);
     
    13791592          freeMaps (&m);
    13801593          free (m);
     1594          if(zooRegistry!=NULL){
     1595            freeRegistry(&zooRegistry);
     1596            free(zooRegistry);
     1597          }
    13811598          free (REQUEST);
    13821599          free (SERVICE_URL);
     
    13961613          freeMaps (&m);
    13971614          free (m);
     1615          if(zooRegistry!=NULL){
     1616            freeRegistry(&zooRegistry);
     1617            free(zooRegistry);
     1618          }
    13981619          free (REQUEST);
    13991620          free (SERVICE_URL);
     
    14101631      freeMaps (&m);
    14111632      free (m);
     1633      if(zooRegistry!=NULL){
     1634        freeRegistry(&zooRegistry);
     1635        free(zooRegistry);
     1636      }
    14121637      free (REQUEST);
    14131638      free (SERVICE_URL);
     
    14471672  dup2 (fileno (stderr), fileno (stdout));
    14481673  t = readServiceFile (m, tmps1, &s1, r_inputs->value);
     1674  inheritance(zooRegistry,&s1);
     1675  if(zooRegistry!=NULL){
     1676    freeRegistry(&zooRegistry);
     1677    free(zooRegistry);
     1678  }
    14491679  fflush (stdout);
    14501680  dup2 (saved_stdout, fileno (stdout));
Note: See TracChangeset for help on using the changeset viewer.

Search

Context Navigation

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