Locked History Actions

WebFeatureService

deegree WFS (Web Feature Service)

This page provides an overview on the deegree Web Feature Service.

1. Introduction

"The deegree Web Feature Service provides customisable access to vector data and supports complex schema mappings."

Er... but what does this mean, exactly?

A WFS serves "feature types". If you look at it from an XML schema point-of-view, feature types are XML elements that are substitutable for the abstract "gml:_Feature" element. The "gml:_Feature" element is defined in the GML core schemas, along with dozens of other elements and types, such as geometries. As the possibilities of XML schemas as well as the GML core schemas are fairly complex, not every possible GML application schema can be served by current WFS implementations. However, the deegree WFS is quite sophisticated in respect to the possibilities it offers for defining feature types. Here are some highlights:

  • supports properties that contain features themselves (complex features)
  • multi-properties (properties that may occur several times in a feature)
  • recursive feature/property structures
  • "dynamic" content, e.g. content of properties may be generated using SQL functions
  • XSL-scripts can be used to preprocess incoming requests and postprocess outgoing responses

2. Implemented OGC standards

3. Known issues

The deegree WFS is (of course) not perfect. Some of the issues are implementation related and can be resolved, others stem from fundamental problems in the implementation specification.

WFSKnownIssues

4. Supported request types / encodings

The WFS Implementation Specification defines XML as well as KVP (key-value-pair) encodings for different request types. However, the KVP encoded requests only support a subset of the possibilities of their XML counterparts. Therefore, XML is the primary encoding for WFS requests and not all KVP requests are currently implemented by the deegree WFS.

4.1. Non-Transactional

Operation

KVP

XML

GetCapabilities

YES

YES

DescribeFeatureType

YES

YES

GetFeature

YES*

YES

GetGmlObject

NO

NO

* except BBOX-Parameter, because name of GeometryProperty must not be specified (use encoded Filter with BBOX as workaround)

4.2. Transactional

Operation

KVP

XML

Transaction

NO

YES

LockFeature

NO

YES

5. Configuration

  • TransactionalWebFeatureServiceConfiguration - Configuring transactional WFS

  • ArcSDEBackend - Configuring deegree WFS against ArcSDE

6. How to write a custom Datastore implementation

If you need full (Java) control over the processing of a Query (part of a GetFeature request), you can simply write your own Datastore implementation:

Use this as a template (and have a look at org.deegree.io.datastore.shape.ShapeDatastore for a simple Datastore that actually does something):

package org.deegree.io.datastore;
import org.deegree.io.datastore.schema.MappedFeatureType;
import org.deegree.model.feature.FeatureCollection;
import org.deegree.ogcwebservices.wfs.operation.LockFeature;
import org.deegree.ogcwebservices.wfs.operation.Query;
public class CustomDatastore extends Datastore {
    /**
     * Performs a query against the datastore.
     *
     * @param query
     *            query to be performed
     * @param rootFt
     *            the root feature type that is queried
     * @return requested feature instances
     * @throws DatastoreException
     */
    @Override
    public FeatureCollection performQuery( Query query, MappedFeatureType rootFt )
                            throws DatastoreException {
        // for a read-only WFS, you need to implement this method only
        return null;
    }
    @Override
    public FeatureCollection performQuery( Query query, MappedFeatureType rootFt, DatastoreTransaction context )
                            throws DatastoreException {
        return performQuery( query, rootFt );
    }
    @Override
    public FeatureCollection performQueryWithLock( Query query )
                            throws DatastoreException {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public void performLockFeature( LockFeature request )
                            throws DatastoreException {
        // TODO Auto-generated method stub
    }
    @Override
    public void close()
                            throws DatastoreException {
        // TODO Auto-generated method stub
    }
    @Override
    public DatastoreTransaction acquireTransaction()
                            throws DatastoreException {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public void releaseTransaction( DatastoreTransaction ta )
                            throws DatastoreException {
        // TODO Auto-generated method stub
    }
}

Next thing that you have to do:

Add a mapping to org.deegree.io.datastore.datastores.properties:

...
ORACLE=org.deegree.io.datastore.sql.oracle.OracleDatastore
POSTGIS=org.deegree.io.datastore.sql.postgis.PostGISDatastore
SHAPE=org.deegree.io.datastore.shape.ShapeDatastore
GENERICSQL=org.deegree.io.datastore.sql.generic.GenericSQLDatastore
SDE=org.deegree.io.datastore.sde.SDEDatastore
CUSTOM=org.deegree.io.datastore.CUSTOMDatastore

Afterwards, the WFS will know the new backend 'CUSTOM', and the Datastore implementation will be used to process queries, if the mapped application schema requests it.

<?xml version="1.0" encoding="UTF-8"?>
<schema ...>
    <import .../>
    <import .../>
    <!-- configuration of the persistence backend to be used -->
    <annotation>
        <appinfo>
            <deegreewfs:Prefix>...</deegreewfs:Prefix>
            <!-- CUSTOM (CUSTOMDatastore) ->
            <deegreewfs:Backend>CUSTOM</deegreewfs:Backend>
            <deegreewfs:DefaultSRS>...</deegreewfs:DefaultSRS>
            <deegreewfs:SuppressXLinkOutput>...</deegreewfs:SuppressXLinkOutput>
$

If you require read access only, this is all you need to do.

7. How a GetFeature-query is performed internally (on SQL based datastores)

Consider an incoming GetFeature request:

<?xml version="1.0" encoding="UTF-8"?>
<wfs:GetFeature version="1.1.0" xmlns:app="http://www.deegree.org/app" xmlns:wfs="http://www.opengis.net/wfs" xmlns:gml="http://www.opengis.net/gml" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
  <wfs:Query typeName="app:Philosopher">
    <ogc:Filter>
      <ogc:PropertyIsEqualTo>
        <ogc:PropertyName>app:placeOfBirth/app:Place/app:country/app:Country/app:name</ogc:PropertyName>
        <ogc:Literal>France</ogc:Literal>
      </ogc:PropertyIsEqualTo>
    </ogc:Filter>
  </wfs:Query>
</wfs:GetFeature>

For each wfs:Query-element, a 2 phase-request is performed (SQL-wise) to build the result:

  1. An *initial* SQL-SELECT statement is issued to determines the ids of all features that match the specified ogc:Filter criterion. To improve efficiency, all necessary properties from the "root-feature" table (the queried feature type's main table; in this case: Philosopher) are fetched by the initial statement as well.
  2. For complex feature types (as Philosopher), the graph of connected tables is traversed in order to fetch the data for all properties and subfeatures.

7.1. Phase 1: Initial SELECT

SELECT X1.PLACE_OF_BIRTH,X1.NAME,X1.DATE_OF_BIRTH,X1.SEX,X1.DATE_OF_DEATH,X1.ID,X1.PLACE_OF_DEATH
FROM PHILOSOPHER X1
LEFT OUTER JOIN PLACE X2 ON X2.ID=X1.PLACE_OF_BIRTH
LEFT OUTER JOIN COUNTRY X3 ON X3.ID=X2.COUNTRY_ID
WHERE X3.NAME = 'France'

As you can see, only columns from the "root" table (PHILOSOPHER) are fetched initially:

  • X1.PLACE_OF_BIRTH
  • X1.NAME
  • X1.DATE_OF_BIRTH
  • X1.SEX
  • X1.DATE_OF_DEATH
  • X1.ID
  • X1.PLACE_OF_DEATH

Also, the statement builds a chain of LEFT OUTER JOINs in order to constrain the result to these rows in the PHILOSOPHER table which match the filter expression (informally: app:placeOfBirth/app:Place/app:country/app:Country/app:name='France').

7.2. Phase 2: Follow-up SELECTs

TODO


CategoryDeegree2