Changes between Version 24 and Version 25 of ZooWorkshop/FOSS4GJapan/CreatingOGRBasedWebServices
- Timestamp:
- Oct 15, 2010, 11:48:45 PM (14 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
ZooWorkshop/FOSS4GJapan/CreatingOGRBasedWebServices
v24 v25 163 163 As explained before, ZOO Kernel will pass the parameters to your Service function in a specific datatype called maps. In order to code your Service in C language, you also need to learn how to access this datatype in read/write mode. 164 164 165 The maps are simple map named linked list containing a name, a content map and a pointer to the next map in the list (or NULLif there is no more map in the list). Here is the datatype definition as you can find in the zoo-kernel/service.h file :165 The maps are simple map named linked list containing a name, a content map and a pointer to the next map in the list (or {{{NULL}}} if there is no more map in the list). Here is the datatype definition as you can find in the zoo-kernel/service.h file : 166 166 167 167 {{{ … … 174 174 }}} 175 175 176 The map included in the maps is also a simple linked list and is used to store Key Value Pair values. A map is thus a couple of name and value and a pointer to the next element in the list. Here is the datatype definition you can find in the zoo-kernel/service.hfile :176 The map included in the maps is also a simple linked list and is used to store Key Value Pair values. A map is thus a couple of name and value and a pointer to the next element in the list. Here is the datatype definition you can find in the {{{zoo-kernel/service.h}}} file : 177 177 178 178 {{{ 179 179 #!c 180 180 typedef struct map{ 181 char* name; 182 char* value; 181 char* name; /* The key */ 182 char* value; /* The value */ 183 183 struct map* next; /* Next couple */ 184 184 } map; 185 185 }}} 186 186 187 As partially or fully filled datastructures will be passed by the ZOO Kernel to your Services, this means that you do not need to deal with maps creation but directly with existing map, in other words the content of each maps. The first function you need to know is getMapFromMaps (defined in the zoo-kernel/service.hfile) which let you access to a specific map of a maps.187 As partially or fully filled datastructures will be passed by the ZOO Kernel to your Services, this means that you do not need to deal with maps creation but directly with existing map, in other words the content of each maps. The first function you need to know is {{{getMapFromMaps}}} (defined in the {{{zoo-kernel/service.h}}} file) which let you access to a specific map of a maps. 188 188 189 189 This function takes three parameters listed bellow : 190 190 191 * m: a maps pointer representing the maps used to search the specific map192 * name: a char* representing the name of the map you are searching for193 * key: a specific key in the map named name191 * {{{m}}} : a maps pointer representing the maps used to search the specific map 192 * {{{name}}} : a char* representing the name of the map you are searching for 193 * {{{key}}} : a specific key in the map named name 194 194 195 195 For example, the following syntax will be used to access the InputPolygon value map of a maps named inputs, your C code should be : … … 208 208 }}} 209 209 210 As you know how to read and access the map fields from a maps, you can now learn how to write in such a datastructure. This is done by using the simple addToMap function once again defined in zoo- kernel/service.h. The addToMapfunction also takes three parameters :211 212 * m: a map pointer you want to update,213 * n: the name of the map you want to add or update the value,214 * v: the value you want to set for this map.215 216 Here is an example of how to add or edit the content map of a maps called outputs:210 As you know how to read and access the map fields from a maps, you can now learn how to write in such a datastructure. This is done by using the simple addToMap function once again defined in {{{zoo- kernel/service.h}}}. The {{{addToMap}}} function also takes three parameters : 211 212 * {{{m}}} : a map pointer you want to update, 213 * {{{n}}} : the name of the map you want to add or update the value, 214 * {{{v}}} : the value you want to set for this map. 215 216 Here is an example of how to add or edit the content {{{map}}} of a {{{maps}}} called {{{outputs}}} : 217 217 218 218 {{{ … … 223 223 }}} 224 224 225 Please note that the addToMapfunction is able to create or update an existing map. Indeed, if a map called « value » allready exists, then its value will be updated automatically.225 Please note that the {{{addToMap}}} function is able to create or update an existing map. Indeed, if a map called « value » allready exists, then its value will be updated automatically. 226 226 227 227 This datatype is really important cause it is used in every C based ZOO Services. It is also the same representation used in other languages but using their respectives datatypes. For Example in Python, the dictionaries datatype is used, so manipulation is much easier. … … 249 249 As you know how to deal with maps and map, you are ready to code the first ZOO Service by using the OGR Boundary function. 250 250 251 As already said in introduction we will use the Geoserver WFS server available on OSGeoLive, so full WFS Response will be used as inputs values. As we will use the simple OGR Geometry functions like OGR_G_GetBoundary, only the Geometry object will be used rather than a full WFS Response. The first thing to do is to write a function which will extract the geometry definition from the full WFS Response. We will call it createGeometryFromWFS.251 As already said in introduction we will use the Geoserver WFS server available on OSGeoLive, so full WFS Response will be used as inputs values. As we will use the simple OGR Geometry functions like [http://www.gdal.org/ogr/ogr__api_8h.html#a797af4266c02846d52b9cf3207ef958 OGR_G_GetBoundary], only the Geometry object will be used rather than a full WFS Response. The first thing to do is to write a function which will extract the geometry definition from the full WFS Response. We will call it {{{createGeometryFromWFS}}}. 252 252 253 253 Here is the code of such a function : … … 292 292 }}} 293 293 294 The only thing we will focus on is the call to the errorException function used in the function body. This function is declared in the zoo-kernel/service_internal.h and defined in zoo- kernel/service_internal.cfile. It takes three parameters as follow :295 296 * the main environment maps,297 * a char*representing the error message to display,298 * a char*representing the error code (as defined in the WPS specification – Table 62).299 300 In other words, if the WFS response cannot be parsed properly, then you will return an ExceptionReportdocument informing the client that a problem occured.294 The only thing we will focus on is the call to the errorException function used in the function body. This function is declared in the {{{zoo-kernel/service_internal.h}}} and defined in {{{zoo- kernel/service_internal.c}}} file. It takes three parameters as follow : 295 296 * the main environment {{{maps}}}, 297 * a {{{char*}}} representing the error message to display, 298 * a {{{char*}}} representing the error code (as defined in the WPS specification – Table 62). 299 300 In other words, if the WFS response cannot be parsed properly, then you will return an {{{ExceptionReport}}} document informing the client that a problem occured. 301 301 302 302 The function to extract the geometry object from a WFS Response is written, so you can now start defining the Boundary Service. Here is the full code for the Boundary Service : … … 307 307 OGRGeometryH geometry,res; 308 308 map* tmp=getMapFromMaps(inputs,"InputPolygon","value"); 309 if(tmp==NULL) 309 if(tmp==NULL){ 310 setMapInMaps(m,"lenv","message","Unable to parse InputPolygon"); 310 311 return SERVICE_FAILED; 312 } 311 313 map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType"); 312 314 if(strncmp(tmp1->value,"application/json",16)==0) … … 314 316 else 315 317 geometry=createGeometryFromWFS(conf,tmp->value); 318 if(geometry==NULL){ 319 setMapInMaps(m,"lenv","message","Unable to parse InputPolygon"); 320 return SERVICE_FAILED; 321 } 316 322 res=OGR_G_GetBoundary(geometry); 317 323 tmp1=getMapFromMaps(outputs,"Result","mimeType"); … … 341 347 }}} 342 348 343 Basicaly, if we get an input with a mimeType set to application/json, then we will use our OGR_G_CreateGeometryFromJson in other case, our createGeometryFromGML local function.349 Basicaly, if we get an input with a {{{mimeType}}} set to {{{application/json}}}, then we will use our OGR_G_CreateGeometryFromJson in other case, our createGeometryFromGML local function. 344 350 345 351 Please note that in some sense the data inputs are not really of the same kind. Indeed as we used directly OGR_G_CreateGeometryFromJson it means that the JSON string include only the geometry object and not the full GeoJSON string. Nevertheless, you can easily change this code to be able to use a full GeoJSON string, simply by creating a function which will extract the geometry object from the GeoJSON string (using the json-c library for instance, which is also used by the OGR GeoJSON Driver). 346 352 347 Once you can access the input geometry object, you can use the OGR_G_GetBoundaryfunction and store the result in the res geometry variable. Then, you only have to store the value in the right format : GeoJSON per default or GML as we declared it as a supported output format.348 349 Please note that ZOO Kernel will give you pre-filled outputs values, so you will only have to fill the value for the key named value, even if in our example we override the mimeType using the text/plain value rather than the application/json(to show that we can also edit other fields of a map). Indeed, depending on the format requested by the client (or the default one) we will provide JSON or GML representation of the geometry.353 Once you can access the input geometry object, you can use the [http://www.gdal.org/ogr/ogr__api_8h.html#a797af4266c02846d52b9cf3207ef958 OGR_G_GetBoundary] function and store the result in the res geometry variable. Then, you only have to store the value in the right format : GeoJSON per default or GML as we declared it as a supported output format. 354 355 Please note that ZOO Kernel will give you pre-filled outputs values, so you will only have to fill the value for the key named value, even if in our example we override the mimeType using the {{{text/plain}}} value rather than the {{{application/json}}} (to show that we can also edit other fields of a map). Indeed, depending on the format requested by the client (or the default one) we will provide JSON or GML representation of the geometry. 350 356 351 357 {{{ … … 361 367 }}} 362 368 363 The Boundary ZOO Service is now implemented and you need to compile it to produce a Shared Library. As you just used functions defined in service.h ( getMapFromMaps and addToMap), you must include this file in your C code. The same requirement is needed to be able to use the errorException function declared in zoo-kernel/service_internal.h, you also must link your service object file to the zoo- kernel/service_internal.o in order to use errorExceptionon runtime. You must then include the required files to access the libxml2 and OGR C-API.364 365 For the need of the Shared Library, you have to put your code in a block declared asextern "C". The final Service code should be stored in a service.c file located in the root of the Services Provider directory (so in /home/zoows/sources/zoo-services/ws_sp). It should look like this :369 The Boundary ZOO Service is now implemented and you need to compile it to produce a Shared Library. As you just used functions defined in service.h ({{{getMapFromMaps}}} and {{{addToMap}}}), you must include this file in your C code. The same requirement is needed to be able to use the errorException function declared in {{{zoo-kernel/service_internal.h}}}, you also must link your service object file to the {{{zoo- kernel/service_internal.o}}} in order to use {{{errorException}}} on runtime. You must then include the required files to access the libxml2 and OGR C-API. 370 371 For the need of the Shared Library, you have to put your code in a block declared asextern "C". The final Service code should be stored in a service.c file located in the root of the Services Provider directory (so in {{{/home/zoows/sources/zoo-services/ws_sp}}}). It should look like this : 366 372 367 373 {{{ … … 385 391 }}} 386 392 387 Please note that the CLFAGS and LDFLAGS environment variables values must be set before. 388 389 The CFLAGS must contain all the requested paths to find included headers, so the path to the directories where the ogr_api.h, libxml2 directory, service.h and service_internal.h files are located. Thanks to the OSGeoLive environment, some of the provided tools can be used to retrieve those values : xml2-config and gdal-config, both used with the --cflags argument. They will produce the desired paths for you. 390 391 If you follow the instructions to create your ZOO Services Provider main directory inzoo-services, then you should find the ZOO Kernel headers and source tree which is located in the../../zoo-kernel directory relatively to your current path (/home/user/zoows/sources/zoo-services/ws_sp). Note that you can also use a full path to the zoo-kernel directory but using relative path will let you move your sources tree somewhere else and keep your code compiling using exactly the same command line. So you must add a -I../../zoo-kernel to your CFLAGS to make the compiler able to find the service.h and service_internal.h files. 392 393 The full CFLAGS definition should look like this : 394 395 {{{ 393 Please note that the {{{CFLAGS}}} and {{{LDFLAGS}}} environment variables values must be set before. 394 395 The {{{CFLAGS}}} must contain all the requested paths to find included headers, so the path to the directories where the {{{ogr_api.h}}}, libxml2 directory, {{{service.h}}} and {{{service_internal.h}}} files are located. Thanks to the OSGeoLive environment, some of the provided tools can be used to retrieve those values : {{{xml2-config}}} and {{{gdal-config}}}, both used with the {{{--cflags}}} argument. They will produce the desired paths for you. 396 397 If you follow the instructions to create your ZOO Services Provider main directory in {{{zoo-services}}}, then you should find the ZOO Kernel headers and source tree which is located in the {{{../../zoo-kernel}}} directory relatively to your current path ({{{/home/user/zoows/sources/zoo-services/ws_sp}}}). Note that you can also use a full path to the zoo-kernel directory but using relative path will let you move your sources tree somewhere else and keep your code compiling using exactly the same command line. So you must add a {{{-I../../zoo-kernel}}} to your {{{CFLAGS}}} to make the compiler able to find the {{{service.h}}} and {{{service_internal.h}}} files. 398 399 The full {{{CFLAGS}}} definition should look like this : 400 401 {{{ 402 #!sh 396 403 CFLAGS=`gdal-config --cflags` `xml2-config --clfags` -I../../zoo-kernel/ 397 404 }}} 398 405 399 Once you get the included paths correctly set in your CFLAGS , it is time to concentrate on the library we have to link against (defined in the LDFLAGS env variable). In order to link against the gdal and libxml2 libraries, you can use the same tools than above using the --libs argument rather than --cflags. The full LDFLAGSdefinition must look like this :406 Once you get the included paths correctly set in your {{{CFLAGS}}} , it is time to concentrate on the library we have to link against (defined in the {{{LDFLAGS}}} environment variable). In order to link against the gdal and libxml2 libraries, you can use the same tools than above using the {{{--libs}}} argument rather than {{{--cflags}}}. The full {{{LDFLAGS}}} definition must look like this : 400 407 401 408 {{{ … … 407 414 408 415 {{{ 416 #!sh 409 417 ZOO_SRC_ROOT=../../zoo-kernel/ 410 418 CFLAGS=-I${ZOO_SRC_ROOT} `xml2-config --cflags` `gdal-config --cflags` … … 417 425 }}} 418 426 419 Using this Makefile, you should be able to run make from your ZOO Service Provider main directory and to get the resulting ogr_ws_service_provider.zo file located in the cgi-envdirectory.420 421 The metadata file and the ZOO Service Shared Object are now both located in the cgi-env directory. In order to deploy your new !ServicesProvider, you only have to copy the ZOO Service Shared Object and its corresponding metadata file in the directory where ZOO Kernel is located, so in/usr/lib/cgi-bin. You must use a sudocommand to achieve this task:427 Using this {{{Makefile}}}, you should be able to run make from your ZOO Service Provider main directory and to get the resulting {{{ogr_ws_service_provider.zo}}} file located in the {{{cgi-env}}} directory. 428 429 The metadata file and the ZOO Service Shared Object are now both located in the {{{cgi-env}}} directory. In order to deploy your new !ServicesProvider, you only have to copy the ZOO Service Shared Object and its corresponding metadata file in the directory where ZOO Kernel is located, so in{{{/usr/lib/cgi-bin}}}. You must use a {{{sudo}}} command to achieve this task: 422 430 423 431 {{{ … … 426 434 }}} 427 435 428 You should now understand more clearly the meannings of the ZOO Service Provider source tree ! Thecgi- env directory will let you deploy your new Services or Services Provider in an easy way , simply by copying the whole cgi-env content in your cgi-bin directory. 429 430 Please note that you can add the following lines to your Makefile to be able to type make install directly and to get your new Services Provider available for use from ZOO Kernel : 431 432 {{{ 436 You should now understand more clearly the meannings of the ZOO Service Provider source tree ! The {{{cgi- env}}} directory will let you deploy your new Services or Services Provider in an easy way , simply by copying the whole {{{cgi-env}}} content in your {{{cgi-bin}}} directory. 437 438 Please note that you can add the following lines to your {{{Makefile}}} to be able to type make install directly and to get your new Services Provider available for use from ZOO Kernel : 439 440 {{{ 441 #!sh 433 442 install: 434 443 sudo cp ./cgi-env/* /usr/lib/cgi-bin