Implementing OFC WFS as a Web Service - Initial Issues
From CrisisGridWiki
Contents |
OGC Schemas
Implementing WFS (or any other OGC service) requires producing OGC compible XML documents. Each service has a set of XML Schemas defined for expressing services it offers and capabilities it can demonsrate. We use these schemas for data binding -to create XML documents with code- and to make sure that these documents are compatible with the standards.
Overview
The interconnection between OGC schemas are as follows:
A WFS should be able to fulfill following service requests (Definitions are from OGC WFS document):
| Request | Definition |
| GetCapabilities |
WFS describes its capabilities through an XML document. This document should be returned for this request. |
| DescribeFeatureType |
WFS should be able to generate a schema description of feature types serviced. |
| GetFeature |
Allows retrieval of features in XML format. |
| GetFeatureWithLock |
Functionally similar to the GetFeature, except that it indicates to a WFS to attempt to lock the features that are selected. |
| LockFeature |
The purpose of this request is to expose a long term feature locking mechanism to ensure consistency. |
| Transaction |
Data transformation operations that are to be applied to web accessible feature instances. |
Data Binding Tools and OGC Schemas
Data binding frameworks such as Castor (http://castor.exolab.org) or XMLBeans (http://xml.apache.org/xmlbeans ) take XML Schemas as input and produce java sources. But one major problem with these frameworks is that sometimes it is not easy to find an object oriented correspondence of the XML Schema constructs. In such cases either the source codes can not be generated or generated source codes may not produce correct XML instances.
Some of the XML Schema types -such as substitutions and abstract types- used in OGC Schemas are currently not supported by Castor. I had to make several changes to make these schemas compatible with Castor Source Generator. Some of these changes are summarized below.
Original OGC Schemas can be found here: http://schemas.opengis.net/. Modified schemas are here: http://complexity.ucs.indiana.edu/~gaydin/ogc/modified/
In general OGC Schemas use substitution to express a group of elements can be used interchangeably. Substitution is defined by W3.org as follows
XML Schema provides a mechanism, called substitution groups, that allows elements to be substituted for other elements. More specifically, elements can be assigned to a special group of elements that are said to be substitutable for a particular named element called the head element. (Note that the head element must be declared as a global element.)
The existence of a substitution group does not require any of the elements in that class to be used, nor does it preclude use of the head element. It simply provides a mechanism for allowing elements to be used interchangeably.
Modifying Schemas for Castor Compatibility
Since Castor does not support substitution groups I had to find a way around this problem and it appears that using choices is the answer.
Consider following example from expr schema:
<expression> element in this schema is a top level definition for general expressions. Any one of the seven elements in ‘expression substitution group’ may be used while constructing an expression in an XML instance.
<xsd:element name="expression" type="ogc:ExpressionType" abstract="true"/> .. <xsd:complexType name="ExpressionType" abstract="true" mixed="true"/> |
As it can be seen from the schema fragment, <expression> element is ‘abstract’, meaning we don’t expect to see any <expression> tags in the final XML instance.
Since one of the seven elements can be used where an expression is to be defined, I simply replaced the substitution group with a <choice> in <ExpressionType>.
<xsd:element name="expression" abstract="true">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="ogc:ExpressionType"/>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
…
<xsd:complexType name="ExpressionType" mixed="true">
<xsd:choice>
<xsd:element ref="ogc:Add"/>
<xsd:element ref="ogc:Div"/>
<xsd:element ref="ogc:Function"/>
<xsd:element ref="ogc:Literal"/>
<xsd:element ref="ogc:Mul"/>
<xsd:element ref="ogc:PropertyName"/>
<xsd:element ref="ogc:Sub"/>
</xsd:choice>
</xsd:complexType>
|
I made several changes of the same kind, but some cases required different approaches to produce XML instances that are compatible with the original schemas. For instance, a function element may have multiple expressions at the same time.
<xsd:element name="Function" type="ogc:FunctionType" substitutionGroup="ogc:expression"/>
…
<xsd:complexType name="FunctionType">
<xsd:complexContent>
<xsd:extension base="ogc:ExpressionType">
<xsd:sequence>
<xsd:element ref="ogc:expression" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
|
To express this element with a <choice> I changed the Function as follows:
<xsd:complexType name="FunctionType">
<xsd:sequence minOccurs="0">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="ogc:Add" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element ref="ogc:Div" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element ref="ogc:Function" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element ref="ogc:Literal" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element ref="ogc:Mul" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element ref="ogc:PropertyName" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element ref="ogc:Sub" minOccurs="0" maxOccurs="unbounded"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
|
Here the Function has a sequence of choices which basically means a sequence of the seven elements.
OGC Filter Implementation
One of the challenges with implementing OGC WFS is to be able to create and parse XML documents that contain Filters. Filters are used to define constraints on a query.
GetFeature (and GetFeatureWithLock) requests contain <Query> element which in turn may contain <Filter> element to constraint the query. If no <Filter> element is contained in <Query> than the query is unconstrained and all feature instances should be retrieved Filters can be used to specify both spatial and/or non-spatial constraints in a query. (WFS Spec p.26).
A Filter may include an operation element in one of the following three operation types:
- Spatial Operations
- Comparison Operations
- Logic Operations
These operation types are defined as substitution groups in Filter Schema as following picture shows:
<xsd:element name="Filter" type="ogc:FilterType"/>
..
<xsd:complexType name="FilterType">
<xsd:choice>
<xsd:element ref="ogc:spatialOps"/>
<xsd:element ref="ogc:comparisonOps"/>
<xsd:element ref="ogc:logicOps"/>
<xsd:element ref="ogc:FeatureId" maxOccurs="unbounded"/>
</xsd:choice>
</xsd:complexType>
|
The picture tells us that at any given time a Filter may have one element from one of the three groups and any sub element under these groups may substitute each other.
I removed the substitution groups and created choices to replace them. Finally in this version of the schema the Filter has a choice which in turn has three choices that correspond to three substitution groups in the original schema.
<xsd:element name="Filter" type="ogc:FilterType"/>
..
<xsd:complexType name="FilterType">
<xsd:choice id="FilterTypeChoice">
<xsd:choice id="spatialOpsChoice">
<xsd:element ref="ogc:BBOX"/>
<xsd:element ref="ogc:Beyond"/>
<xsd:element ref="ogc:Contains"/>
<xsd:element ref="ogc:Crosses"/>
<xsd:element ref="ogc:DWithin"/>
<xsd:element ref="ogc:Disjoint"/>
<xsd:element ref="ogc:Equals"/>
<xsd:element ref="ogc:Intersects"/>
<xsd:element ref="ogc:Overlaps"/>
<xsd:element ref="ogc:Touches"/>
<xsd:element ref="ogc:Within"/>
</xsd:choice>
<xsd:choice id="comparisonOpsChoice">
<xsd:element ref="ogc:PropertyIsBetween"/>
<xsd:element ref="ogc:PropertyIsEqualTo"/>
<xsd:element ref="ogc:PropertyIsGreaterThan"/>
<xsd:element ref="ogc:PropertyIsGreaterThanOrEqualTo"/>
<xsd:element ref="ogc:PropertyIsLessThan"/>
<xsd:element ref="ogc:PropertyIsLessThanOrEqualTo"/>
<xsd:element ref="ogc:PropertyIsLike"/>
<xsd:element ref="ogc:PropertyIsNotEqualTo"/>
<xsd:element ref="ogc:PropertyIsNull"/>
</xsd:choice>
<xsd:choice id="LogicOpsChoice">
<xsd:element ref="ogc:And"/>
<xsd:element ref="ogc:Not"/>
<xsd:element ref="ogc:Or"/>
</xsd:choice>
<xsd:element ref="ogc:FeatureId" maxOccurs="unbounded"/>
</xsd:choice>
</xsd:complexType>
|
Similar changes were made in WFS and GML schemas as well.
The Demo
The OGC specifications do not have information on how to build Web Services; instead the specified services are intended to be servlets that can exchange information using HTTP GET and POST operations.
Since we wanted to make OGC Web Services I have created a wsdl file for WFS which defines operations for required WFS request types.
The WFS-WS methods receive requests as XML strings and return the results as strings. The request – response XML formats are fully compatible with the OGC specifications.
To use WFS-WS user generates the client stubs from wfs.wsdl which is available on WFS server. Then using this client stub code user sends the requests in appropriate format and receives the results as XML strings.
I used Apache Axis for creating and publishing the Web Service. Axis takes care of the SOAP communication between server and the client.
Currently this WFS-WS can process GetCapabilities and a subset of GetFeature requests. I used capabilities document and the data from the deegree’s sample WFS implementation.
deegree-WFS uses Microsoft Access database for two sample geographic data sets, Europe and Cities. I used a tool called access2mysql for mapping these tables to our MySQL server in gridfarm8.
This version of WFS supports GetFeature requests with a BBOX constraint. User needs to define Query which includes a BBOX filter. BBOX constraint should include coordinates inside the scope of the sample Europe data.
A sample GetFeature request is provided in the demo page. By changing the PropertyName elements user can retrieve different column values from the database.
After user submits the GetFeature request the WFS parses this XML document and extracts Property Names and coordinate information to construct an SQL query. This query is then executed for MySQL database and the results are returned as plain-text. GetFeature responses should be GML 2.1.2 compatible XML documents which contains Feature Collections. But for the demo this property is not supported.
I am working on developing a more general data layer (which might use Hibernate) that would make it easier to adopt new data stores.
This is not a complete WFS-WebService implementation; rather it is a small demo to show current progress.
What has been done
- Modifying OGC schemas for data binding and source code generation.
- OGC Filter Encoding implementation (This will improve as I implement a new DataStore interface for the databases that have Geographic Features).
- Parsing and creating WFS 1.1, Filter 1.0.0 and GML 2.1.2 OGC schemas.
- WSDL interface for the WFS Web Service
- GetCapabilities request
- GetFeature request (This is a partial implementation)
What to do
- Complete GetFeature request. WFS returns an XML document as a response to this request.Returning document has a collection of Features (FeatureCollection) which satisfy the constraints in the GetFeature request. Features retrieved from the database are defined in a GML compatible schema and I need to create instances of this schema to include in the FeatureCollection. I think using XSL will help us overcome this problem.
- A general and flexible DataStore implementation: This would allow us to integrate any number of databases that contain geographic features. DescribeFeatureType request. This involves in returning the schema that defines the data store in which the geographic feature resides. This should be straightforward.
- GetFeatureWithLock, LockFeature, Transaction requests. These are advanced request types, not required initially to have a working WFS, so they are not supposed to be implemented immediately. But we should have them to have a complete WFS implementation.
- Integrate with WMS etc.







