430 | | ==== Python Version ==== |
| 430 | === Python Version === |
| 431 | |
| 432 | For those using Python to implement their ZOO Services Provider, the full code to copy in ogr_ws_service_provider.py in cgi-env directory is shown bellow. Indeed, as Python is an interpreted language, you do not have to compile anything before deploying your service which makes the deployement step much easier : |
| 433 | |
| 434 | {{{ |
| 435 | #!python |
| 436 | import osgeo.ogr |
| 437 | import libxml2 |
| 438 | |
| 439 | def createGeometryFromWFS(my_wfs_response): |
| 440 | doc=libxml2.parseMemory(my_wfs_response,len(my_wfs_response)) |
| 441 | ctxt = doc.xpathNewContext() |
| 442 | res=ctxt.xpathEval("/*/*/*/*/*[local-name()='Polygon' or local- name()='MultiPolygon']") |
| 443 | for node in res: |
| 444 | geometry_as_string=node.serialize() |
| 445 | geometry=osgeo.ogr.CreateGeometryFromGML(geometry_as_string) |
| 446 | return geometry |
| 447 | return geometry |
| 448 | |
| 449 | def Boundary(conf,inputs,outputs): |
| 450 | if inputs["InputPolygon"]["mimeType"]=="application/json": |
| 451 | geometry=osgeo.ogr.CreateGeometryFromJson(inputs["InputPolygon"]["value"]) |
| 452 | else: |
| 453 | geometry=createGeometryFromWFS(inputs["InputPolygon"]["value"]) |
| 454 | rgeom=geometry.GetBoundary() |
| 455 | if outputs["Result"]["mimeType"]=="application/json": |
| 456 | outputs["Result"]["value"]=rgeom.ExportToJson() |
| 457 | outputs["Result"]["mimeType"]="text/plain" |
| 458 | else: |
| 459 | outputs["Result"]["value"]=rgeom.ExportToGML() |
| 460 | geometry.Destroy() |
| 461 | rgeom.Destroy() |
| 462 | return 3 |
| 463 | }}} |
| 464 | |
| 465 | We do not dicuss the functions body here as we already gave all the details before and the code was volontary made in a similar way. |
| 466 | |
| 467 | As done before, you only have to copy the cgi-env files into your cgi-bin directory : |
| 468 | |
| 469 | {{{ |
| 470 | #!sh |
| 471 | sudo cp ./cgi-env/* /usr/lib/cgi-bin |
| 472 | }}} |
| 473 | |
| 474 | A simple Makefile containing the install section can be written as the following : |
| 475 | |
| 476 | {{{ |
| 477 | install: |
| 478 | sudo cp ./cgi-env/* /usr/lib/cgi-bin/ |
| 479 | }}} |
| 480 | |
| 481 | Finally, simply run make install from the ZOO Services Provider main directory, in order to deploy your ZOO Service Provider. |
| 482 | |
| 483 | === Testing the Service using Execute Request === |
| 484 | |
| 485 | ==== The simple and unreadable way ==== |
| 486 | |
| 487 | Everybody should now get his own copy of the OGR Boundary Service stored as a ZOO Services Provider called ogr_ws_service_provider and deployed in the ZOO Kernel tree, so the following Execute request can be used to test the Service : |
| 488 | |
| 489 | [http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Boundary&DataInputs=InputPolygon=Reference@xlink:href= http%3A%2F%2Flocalhost%3A8082%2Fgeoserver%2Fows%3FSERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dtopp%3Astates%26SRS%3DEPSG%3A4326%26FeatureID%3Dstates.15] |
| 490 | |
| 491 | As you can see in the url above, we use an URLEncoded WFS request to the Geoserver WFS server available on OSGeoLive as a xlink:href key in the DataInputs KVP value, and set the InputPolygon value to Reference. The corresponding non encoded WFS request is as follow : |
| 492 | |
| 493 | [http://localhost:8082/geoserver/ows/?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&typename=topp:states&SRS=EPSG:4326&FeatureID=state s.15] |
| 494 | |
| 495 | Please note that you can add lineage=true to the previous request if you need to get information about the input values used to run your Service. Furthermore, you may need to store theExecuteResponse document of your ZOO Service to re-use it later. In this case you must addstoreExecuteResponse=true to the previous request. Note that is an important thing as the behavior of ZOO Kernel is not exactly the same than when running without this parameter settled to true. Indeed, in such a request, ZOO Kernel will give you an ExecuteResponse document which will contain the attribute statusLocation, which inform the client where the ongoing status or the final ExecuteResponse will be located. |
| 496 | |
| 497 | Here is an example of what the ExecuteResponse using storeExecuteResponse=true in the request would look like : |
| 498 | |
| 499 | Then, according to the statusLocation, you should get the ExecuteResponse as you get before using the previous request. Note that can be really useful to provide some caching system for a client application. |
| 500 | |
| 501 | You didn't specify any ResponseForm in the previous request, it is not requested and should return a ResponseDocument per default using the application/json mimeType as you defined in you zcfg file. Nevertheless, you can tell ZOO Kernel what kind of data you want to get in result of your query adding the attribute mimeType=text/xml to your ResponseDocument parameter. Adding this parameter to the previous request will give us the result as its GML representation : |
| 502 | |
| 503 | [http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Boundary&DataInputs=InputPolygon=Reference@xlink:href= http%3A%2F%2Flocalhost%3A8082%2Fgeoserver%2Fows%3FSERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dtopp%3Astates%26SRS%3DEPSG%3A4326%26FeatureID %3Dstates.15&ResponseDocument=Result@mimeType=text/xml] |
| 504 | |
| 505 | As defined by the WPS specifications, you can also ask for a RawDataOutput to get only the data without the full ResponseDocument. To do that, you only have to replace the ResponseDocument of your request by RawDataOutput, like in the following request : |
| 506 | |
| 507 | [http://localhost/cgi-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=Boundary&DataInputs=InputPolygon=Reference@xlink:href= http%3A%2F%2Flocalhost%3A8082%2Fgeoserver%2Fows%3FSERVICE%3DWFS%26REQUEST%3DGetFeature%26VERSION%3D1.0.0%26typename%3Dtopp%3Astates%26SRS%3DEPSG%3A4326%26FeatureID %3Dstates.15&RawDataOutput=Result@mimeType=application/json] |
| 508 | |
| 509 | Finally, please note that we go back to the default mimeType to directly obtain the JSON string as we will use this kind of request to develop our client application in the next section of this workshop. |
| 510 | |
| 511 | ==== Simplification and readability of request ==== |
| 512 | |
| 513 | As you can see in the simple example we used since the begining of this workshop, it is sometimes hard to write the Execute requests using the GET method as it makes really long and complexe URLs. In the next requests examples, we will thus use the POST XML requests. First , here is the XML request corresponding to the previous Execute we used : |
| 514 | |
| 515 | {{{ |
| 516 | #!xml |
| 517 | <wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsd"> |
| 518 | <ows:Identifier>Boundary</ows:Identifier> |
| 519 | <wps:DataInputs> |
| 520 | <wps:Input> |
| 521 | <ows:Identifier>InputPolygon</ows:Identifier> |
| 522 | <ows:Title>Playground area</ows:Title> |
| 523 | <wps:Reference xlink:href="http://localhost:8082/geoserver/ows/?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&typename=topp:states&SRS=EPSG:43 26&FeatureID=states.15"/> |
| 524 | </wps:Input> |
| 525 | </wps:DataInputs> |
| 526 | <wps:ResponseForm> |
| 527 | <wps:ResponseDocument> |
| 528 | <wps:Output> |
| 529 | <ows:Identifier>Result</ows:Identifier> |
| 530 | <ows:Title>Area serviced by playground.</ows:Title> |
| 531 | <ows:Abstract>Area within which most users of this playground will live.</ows:Abstract> |
| 532 | </wps:Output> |
| 533 | </wps:ResponseDocument> |
| 534 | </wps:ResponseForm> |
| 535 | </wps:Execute> |
| 536 | }}} |
| 537 | |
| 538 | In order to let you easily run the XML requests, a simple HTML form called test_services.html is available in your /var/www directory. You can access it using the following link : http://localhost/test_services.html. |
| 539 | |
| 540 | Please open this page in your browser, simply fill the XML request content into the textarea field and click the « run using XML Request » submit button. You will get exactly the same result as when running your Service using the GET request. The screenshot above show the HTML form including the request and the ExecuteResponse document displayed in the iframe at the bottom of the page : |
| 541 | |
| 542 | The xlink:href value is used in the simplest way to deal with such data input. Obviously, you can also use a full JSON string of the geometry, as shown in the following XML Request example : |
| 543 | |
| 544 | {{{ |
| 545 | #!xml |
| 546 | <wps:Execute service="WPS" version="1.0.0" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 ../wpsExecute_request.xsda"> |
| 547 | <ows:Identifier>Boundary</ows:Identifier> |
| 548 | <wps:DataInputs> |
| 549 | <wps:Input> |
| 550 | <ows:Identifier>InputPolygon</ows:Identifier> |
| 551 | <wps:Data> |
| 552 | <wps:ComplexData mimeType="application/json"> |
| 553 | { "type": "MultiPolygon", "coordinates": [ [ [ [ -105.998360, 31.393818 ], [ -106.212753, 31.478128 ], [ -106.383041, 31.733763 ], [ -106.538971, 31.786198 ], [ -106.614441, 31.817728 ], [ -105.769730, 31.170780 ], [ -105.998360, 31.393818 ] ] ], [ [ [ -94.913429, 29.257572 ], [ -94.767380, 29.342451 ], [ -94.748405, 29.319490 ], [ -95.105415, 29.096958 ], [ -94.913429, 29.257572 ] ] ] ] } |
| 554 | </wps:ComplexData> |
| 555 | </wps:Data> |
| 556 | </wps:Input> |
| 557 | </wps:DataInputs> |
| 558 | <wps:ResponseForm> |
| 559 | <wps:ResponseDocument> |
| 560 | <wps:Output> |
| 561 | <ows:Identifier>Result</ows:Identifier> |
| 562 | <ows:Title>Area serviced by playground.</ows:Title> |
| 563 | <ows:Abstract>Area within which most users of this playground will live.</ows:Abstract> |
| 564 | </wps:Output> |
| 565 | </wps:ResponseDocument> |
| 566 | </wps:ResponseForm> |
| 567 | </wps:Execute> |
| 568 | }}} |
| 569 | |
| 570 | If everything went well, you should get the Boundary of the JSON geometry passed as argument, and so be sure that your Service support both GML and JSON as input data. Note that in the previous request, we added a mimeType attribute to the ComplexData node to specify that the input data is not in the default text/xml mimeType but passed as an application/json string directly. It is similar to add @mimeType=application/json as we discussed before. |
| 571 | |
| 572 | == Creating Services for other functions (ConvexHull and Centroid) == |