= Creating WPS compliant OGR based Web Services =
[[TOC]]
[wiki:ZooWorkshop/FOSS4GJapan Table of content]
== Introduction ==
In this part, we are going to create a ZOO ServiceProvider containing several Services based on the OGR C API or on the OGR Python module, which have also been placed in the ZOO installation on OSGeoLive. The intended goal is to use OGR and its GEOS based simple spatial functions as WPS Services.
We will first start with the Boundary spatial function, which will be explained, codded and tested gradually as a ZOO Service. The same procedure will then be used to enable the Buffer, Centroid and Convex Hull functions. Once done, some multiple geometries processes such as Intersection, Union, Difference and Symetric Difference will be implemented through an exercise at the end of the workshop.
As already said in the introduction, you have the choice to code your service in C or Python (or both!) during this workshop. Explanations will be based on the C part, but will be very helpful for those who will choose Python. Please decide according to your habits and preferences and tell your choice to the instructors. The results will be the same in both case.
== Preparing ZOO metadata file ==
A ZOO Service is a combination of a ZOO metadata file (.zcfg) and the runtime module for the corresponding implementation, which is commonly called ZOO Service Provider. We will first prepare a .zcfg file step-by-step. Please open your preferred text editor and edit a file named Boundary.zcfg in your /home/user/zoows/sources/zoo-services/ws_sp directory. First, you need to name the service between brackets at the top of the file, as the following:
{{{
[Boundary]
}}}
This name is very important, it is the name of the Service and so the name of the function defined in the Services Provider. A title and a brief abstract must then be added to inform clients on what the service can do :
{{{
Title = Compute boundary.
Abstract = Returns the boundary of the geometry on which the method is invoked.
}}}
Such metadata informations will be returned by a GetCapabilities request.
You can also add other specific informations like the processVersion. You can set if your ZOO Service can store its results, by setting the storeSupported parameter to true or false. You can also decide if the function can be run as a background task and inform on its current status, according to the statusSupported value :
{{{
processVersion = 1
storeSupported = true
statusSupported = true
}}}
In the main section of the ZOO Service metadata file, you must also specify two important things:
* serviceProvider, which is the name of the C shared library containing the Service function or the Python module name.
* serviceType, which defines the programming language to be used for the Service. (value can be C or Python depending on what language you have decided to use)
C ServiceProvider Example :
{{{
serviceProvider=ogr_ws_service_provider.zo
serviceType=C
}}}
In this case you will get an ogr_ws_service_provider.zo shared library containing the Boundary function, placed in the same directory than ZOO Kernel.
Python ServiceProvider Example :
{{{
serviceProvider=ogr_ws_service_provider
serviceType=Python
}}}
In this case, you will get an ogr_ws_service_provider.py file containing the Python code of your Boundary function.
In the main section you can also add any other metadata information, as the following:
{{{
Title = Demo
}}}
The main metadata informations have been declared, so you can now define data input which will be used by the ZOO Service. You can define any input needed by the Service. Please note that you can request ZOO Kernel using more data input than defined in the .zcfg file without any problem, those values will be passed to your service without filtering. In the Boundary Service example, a single polygon will be used as input, the one on which to apply the Boundary function.
The data input declarations are included in a DataInputs block. They use the same syntax as the Service itself and the input name is between brackets. You can also fill a title, an abstract and aMetaData section for the input. You must set values for the minOccurs and maxOccurs parameters, as they will inform ZOO Kernel which parameters are required to be able to run the Service function.
{{{
[InputPolygon]
Title = Polygon to compute boundary
Abstract = URI to a set of GML that describes the polygon.
minOccurs = 1
maxOccurs = 1
Test = My test
}}}
The metadata defines what type of data the Service supports. In the Boundary example, the input polygon can be provided as a GML file or as a JSON string. Next step is thus to define the default and supported input formats. Both formats should be declared in a LitteralData or ComplexData block depending on their types. For this first example we will use ComplexData blocks only.
{{{
mimeType = text/xml
encoding = UTF-8
mimeType = application/json
encoding = UTF-8
}}}
Then, the same metadata information must be defined for the output of the Service, inside aDataOutputs block, as the following:
{{{
[Result]
Title = The created geometry
Abstract = The geometry containing the boundary of the geometry on which the method was invoked.
Title = Result
mimeType = application/json
encoding = UTF-8
mimeType = text/xml
encoding = UTF-8
}}}
A complete copy of this .zcfg file can be found at the following URL :
http://zoo-project.org/trac/browser/trunk/zoo-services/ogr/base-vect-ops/cgi-env/Boundary.zcfg
Once the ZOO metadata file is modified, you have to copy it in the same directory than your ZOO Kernel (so in your case /usr/lib/cgi-bin). Then you should be able to run the following request :
http://localhost/zoo/?Request=DescribeProcess&Service=WPS&Identifier=Boundary&version=1.0.0
The returned ProcessDescriptions XML document should look like the following :
Please note that the GetCapabilities and DescribeProcess only need a .zcfg file to be completed. Simple, isn't it ? At this step, if you request ZOO Kernel for an Execute, you will get an ExceptionReport document as response, looking as the following :
A similar error message will be returned if you try to run your Python Service :