/**
* Copyright (c) Codice Foundation
*
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*
**/
package org.codice.ddf.spatial.ogc.wfs.catalog.endpoint;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.common.util.StringUtils;
import org.apache.ws.commons.schema.XmlSchema;
import org.apache.ws.commons.schema.XmlSchemaCollection;
import org.apache.ws.commons.schema.XmlSchemaForm;
import org.apache.ws.commons.schema.XmlSchemaImport;
import org.apache.ws.commons.schema.XmlSchemaSerializer;
import org.apache.ws.commons.schema.utils.NamespaceMap;
import org.codice.ddf.spatial.ogc.wfs.catalog.common.WfsException;
import org.codice.ddf.spatial.ogc.wfs.catalog.common.WfsFeatureCollection;
import org.codice.ddf.spatial.ogc.wfs.catalog.endpoint.visitor.EncodedFilterVisitor;
import org.codice.ddf.spatial.ogc.wfs.v1_0_0.catalog.common.DescribeFeatureTypeRequest;
import org.codice.ddf.spatial.ogc.wfs.v1_0_0.catalog.common.GetCapabilitiesRequest;
import org.codice.ddf.spatial.ogc.wfs.v1_0_0.catalog.common.Wfs;
import org.codice.ddf.spatial.ogc.wfs.v1_0_0.catalog.common.Wfs10Constants;
import org.geotools.xml.Configuration;
import org.geotools.xml.Parser;
import org.opengis.filter.Filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
import ddf.catalog.CatalogFramework;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.Result;
import ddf.catalog.federation.FederationException;
import ddf.catalog.filter.FilterBuilder;
import ddf.catalog.operation.QueryResponse;
import ddf.catalog.operation.impl.QueryImpl;
import ddf.catalog.operation.impl.QueryRequestImpl;
import ddf.catalog.source.SourceUnavailableException;
import ddf.catalog.source.UnsupportedQueryException;
import ogc.schema.opengis.BaseVisitor;
import ogc.schema.opengis.DepthFirstTraverserImpl;
import ogc.schema.opengis.filter.v_1_0_0.FilterType;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.Between;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.Beyond;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.ComparisonOperatorsType;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.Contains;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.Crosses;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.DWithin;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.Disjoint;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.FilterCapabilities;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.Intersect;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.Like;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.LogicalOperators;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.NullCheck;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.Overlaps;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.ScalarCapabilitiesType;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.SimpleComparisons;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.SpatialCapabilitiesType;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.SpatialOperatorsType;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.Touches;
import ogc.schema.opengis.filter_capabilities.v_1_0_0.Within;
import ogc.schema.opengis.wfs.v_1_0_0.GetFeatureType;
import ogc.schema.opengis.wfs.v_1_0_0.QueryType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.CapabilityType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.DCPTypeType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.DescribeFeatureTypeType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.EmptyType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.FeatureTypeListType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.FeatureTypeType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.GetCapabilitiesType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.GetFeatureTypeType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.GetType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.HTTPType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.ObjectFactory;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.OperationsType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.PostType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.RequestType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.ResultFormatType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.SchemaDescriptionLanguageType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.ServiceType;
import ogc.schema.opengis.wfs_capabilities.v_1_0_0.WFSCapabilitiesType;
/**
* Implementation of a WFS server. Supports both HTTP GET and POST.
*
*/
@Path("/")
public class WfsEndpoint implements Wfs {
private static final String SERVICE_NAME = "WFS";
private static final String SERVICE_TITLE = "Web Feature Service";
private static final int DEFAULT_PAGE_SIZE = 10;
private static final String ERROR_PARSING_MSG = "Error parsing request: ";
private static final Logger LOGGER = LoggerFactory.getLogger(WfsEndpoint.class);
private static final Configuration PARSER_CONFIG = new org.geotools.filter.v1_0.OGCConfiguration();
private ObjectFactory capsObjectFactory = new ObjectFactory();
private FilterBuilder builder;
private CatalogFramework framework;
private FeatureTypeSchemaCache schemaCache;
@Context
private UriInfo uri;
/**
* JAX-RS Server that represents a WFS v1.0.0 Server.
*/
public WfsEndpoint(CatalogFramework ddf, FilterBuilder filterBuilder,
FeatureTypeSchemaCache cache) {
this.framework = ddf;
this.builder = filterBuilder;
this.schemaCache = cache;
}
/* Constructor for unit testing */
public WfsEndpoint(CatalogFramework ddf, FilterBuilder filterBuilder, UriInfo uri,
FeatureTypeSchemaCache cache) {
this.framework = ddf;
this.builder = filterBuilder;
this.uri = uri;
this.schemaCache = cache;
}
@Override
@GET
@Consumes({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
@Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
public WFSCapabilitiesType getCapabilities(
@QueryParam("") GetCapabilitiesRequest request) throws WfsException {
LOGGER.debug("Got getCapabilites via HTTP GET");
if (request == null) {
throw new WfsException("GetCapabilities request is null");
}
// Validate request
if (Wfs10Constants.GET_CAPABILITES.equalsIgnoreCase(request.getRequest())) {
// Since we only support 1.0.0 we should return the capabilities
// even if a different version was requested.
return buildWfsCapabilitiesType();
} else {
throw createUnexpectedServiceException(request.getService(), request.getVersion(),
request.getRequest());
}
}
@Override
@POST
@Consumes({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
@Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
public WFSCapabilitiesType getCapabilities(
ogc.schema.opengis.wfs.v_1_0_0.GetCapabilitiesType request) throws WfsException {
LOGGER.debug("Got getCapabilites via HTTP POST");
if (request == null) {
throw new WfsException("GetCapabilities request is null");
}
// Validate the request
if (validateRequestParameters(request.getService(), request.getVersion())) {
return buildWfsCapabilitiesType();
} else {
throw createUnexpectedServiceException(request.getService(), request.getVersion(),
Wfs10Constants.GET_CAPABILITES);
}
}
@Override
@GET
@Consumes({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
@Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
public XmlSchema describeFeatureType(@QueryParam("") DescribeFeatureTypeRequest request) throws
WfsException {
LOGGER.debug("Got describeFeatureType via HTTP GET");
if (request == null) {
throw new WfsException("DescribeFeatureType request is null");
}
if (Wfs10Constants.DESCRIBE_FEATURE_TYPE.equalsIgnoreCase(request.getRequest())
&& validateRequestParameters(request.getService(), request.getVersion())) {
if (request.getTypeName() == null) {
return buildMultipleFeatureTypeImportSchema(schemaCache.getFeatureTypeQnames());
} else {
String[] types = request.getTypeName().split(",");
Set<QName> qnames = new HashSet<QName>();
for (String type : types) {
String[] parsed = type.split(":");
QName qname = null;
if (parsed.length == 2) {
qname = new QName(Wfs10Constants.NAMESPACE_URN_ROOT + parsed[0], parsed[1]);
} else {
qname = schemaCache.getQnamefromLocalPart(type);
}
if (null == schemaCache.getSchemaByQname(qname)) {
throw createUnknownTypeException(type);
}
qnames.add(qname);
}
return processQnamesFromDescribeFeature(qnames);
}
} else {
throw createUnexpectedServiceException(request.getService(), request.getVersion(),
request.getRequest());
}
}
@Override
@POST
@Consumes({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
@Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
public XmlSchema describeFeatureType(
ogc.schema.opengis.wfs.v_1_0_0.DescribeFeatureTypeType request) throws WfsException {
LOGGER.debug("Got describeFeatureType via HTTP POST");
if (request == null) {
throw new WfsException("DescribeFeatureType request is null");
}
if (validateRequestParameters(request.getService(), request.getVersion())) {
if (request.getTypeName().isEmpty()) {
return buildMultipleFeatureTypeImportSchema(schemaCache.getFeatureTypeQnames());
} else {
Set<QName> qnames = new HashSet<QName>();
for (QName qname : request.getTypeName()) {
if (null == schemaCache.getSchemaByQname(qname)) {
throw createUnknownTypeException(qname.toString());
}
qnames.add(qname);
}
return processQnamesFromDescribeFeature(qnames);
}
} else {
throw createUnexpectedServiceException(request.getService(), request.getVersion(),
Wfs10Constants.DESCRIBE_FEATURE_TYPE);
}
}
private XmlSchema processQnamesFromDescribeFeature(Set<QName> qnames) throws WfsException {
if (qnames.isEmpty()) {
throw new WfsException("No valid featureTypes available to describe");
}
if (qnames.size() == 1) {
XmlSchema schema = schemaCache.getSchemaByQname(qnames.iterator().next());
return schema;
} else {
return buildMultipleFeatureTypeImportSchema(qnames);
}
}
private XmlSchema buildMultipleFeatureTypeImportSchema(Set<QName> qnames) throws WfsException {
XmlSchema schema = new XmlSchema("", new XmlSchemaCollection());
schema.setElementFormDefault(XmlSchemaForm.QUALIFIED);
schema.setTargetNamespace(XmlSchemaSerializer.XSD_NAMESPACE);
NamespaceMap nsMap = new NamespaceMap();
nsMap.add("", XmlSchemaSerializer.XSD_NAMESPACE);
schema.setNamespaceContext(nsMap);
for (QName qName : qnames) {
XmlSchemaImport schemaImport = new XmlSchemaImport(schema);
schemaImport.setNamespace(qName.getNamespaceURI());
URI fullUri = UriBuilder.fromUri(uri.getBaseUri())
.queryParam("request", Wfs10Constants.DESCRIBE_FEATURE_TYPE)
.queryParam("version", Wfs10Constants.VERSION_1_0_0)
.queryParam("service", Wfs10Constants.WFS).queryParam("typeName",
(StringUtils.isEmpty(qName.getPrefix())) ?
qName.getLocalPart() :
qName.getPrefix() + ":" + qName.getLocalPart()).build();
schemaImport.setSchemaLocation(fullUri.toString());
schema.getExternals().add(schemaImport);
}
return schema;
}
@Override
@POST
@Consumes({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
@Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
public WfsFeatureCollection getFeature(GetFeatureType request) throws WfsException {
LOGGER.debug("Got getFeature via HTTP POST");
if (request == null) {
throw new WfsException("GetFeature request is null");
}
if (validateRequestParameters(request.getService(), request.getVersion())) {
List<QueryType> incomingQueries = request.getQuery();
List<Filter> anyOfFilters = new ArrayList<Filter>();
for (QueryType queryType : incomingQueries) {
if (queryType.getTypeName() == null) {
throw new WfsException("Query must contain a featureType name");
}
List<Filter> allOfFilters = new ArrayList<Filter>();
// First get the Type
Filter filter = builder.attribute(Metacard.CONTENT_TYPE).is()
.text(queryType.getTypeName().getLocalPart());
allOfFilters.add(filter);
if (queryType.getFilter() != null) {
FilterType filterType = queryType.getFilter();
LOGGER.debug("featureID query?{}", filterType.isSetFeatureId());
EncodedFilterVisitor visitor;
try {
visitor = new EncodedFilterVisitor(new DepthFirstTraverserImpl(),
new BaseVisitor(), builder);
filterType.accept(visitor);
} catch (UnsupportedOperationException e) {
throw new WfsException(e);
}
if (filterType.isSetComparisonOps() || filterType.isSetLogicOps() || filterType
.isSetSpatialOps()) {
InputStream inputStream = null;
try {
allOfFilters.add(parseFilter(filterType));
} catch (JAXBException e) {
throw new WfsException(ERROR_PARSING_MSG, e);
} catch (IOException e) {
throw new WfsException(ERROR_PARSING_MSG, e);
} catch (SAXException e) {
throw new WfsException(ERROR_PARSING_MSG, e);
} catch (ParserConfigurationException e) {
throw new WfsException(ERROR_PARSING_MSG, e);
} finally {
IOUtils.closeQuietly(inputStream);
}
}
if (filterType.isSetFeatureId()) {
allOfFilters.add(builder.anyOf(visitor.getFeatureIdFilters()));
}
}
anyOfFilters.add(builder.allOf(allOfFilters));
}
Filter totalFilter = builder.anyOf(anyOfFilters);
QueryImpl query = new QueryImpl(totalFilter);
query.setStartIndex(1);
query.setPageSize((request.getMaxFeatures() == null) ?
DEFAULT_PAGE_SIZE :
request.getMaxFeatures().intValue());
WfsFeatureCollection featureCollection = new WfsFeatureCollection();
try {
QueryResponse queryResponse = framework.query(new QueryRequestImpl(query, true));
for (Result result : queryResponse.getResults()) {
featureCollection.getFeatureMembers().add(result.getMetacard());
}
} catch (UnsupportedQueryException e) {
LOGGER.warn("Unable to query", e);
throw new WfsException(e);
} catch (SourceUnavailableException e) {
LOGGER.warn("Unable to query", e);
throw new WfsException(e);
} catch (FederationException e) {
LOGGER.warn("Unable to query", e);
throw new WfsException(e);
}
return featureCollection;
} else {
throw createUnexpectedServiceException(request.getService(), request.getVersion(),
Wfs10Constants.GET_FEATURE);
}
}
private Boolean validateRequestParameters(final String service, final String version) {
return (service != null && version != null && Wfs10Constants.WFS.equalsIgnoreCase(service)
&& Wfs10Constants.VERSION_1_0_0.equalsIgnoreCase(version));
}
private WFSCapabilitiesType buildWfsCapabilitiesType() {
WFSCapabilitiesType wfsCapabilities = new WFSCapabilitiesType();
wfsCapabilities.setVersion(Wfs10Constants.VERSION_1_0_0);
// Create the Service Type
ServiceType serviceType = new ServiceType();
serviceType.setName(SERVICE_NAME);
serviceType.setTitle(SERVICE_TITLE);
serviceType.setOnlineResource(uri.getBaseUri().toASCIIString());
wfsCapabilities.setService(serviceType);
// Create the HTTP types. The URI is that of this service.
GetType httpGet = new GetType();
httpGet.setOnlineResource(uri.getBaseUri().toASCIIString());
PostType httpPost = new PostType();
httpPost.setOnlineResource(uri.getBaseUri().toASCIIString());
HTTPType httpGetType = new HTTPType();
httpGetType.getGetOrPost().add(httpGet);
HTTPType httpPostType = new HTTPType();
httpPostType.getGetOrPost().add(httpPost);
DCPTypeType dcpGet = new DCPTypeType();
dcpGet.setHTTP(httpGetType);
DCPTypeType dcpPost = new DCPTypeType();
dcpPost.setHTTP(httpPostType);
// GetCapabilites - Supports both GET and POST
GetCapabilitiesType getCapsType = new GetCapabilitiesType();
getCapsType.getDCPType().add(dcpGet);
getCapsType.getDCPType().add(dcpPost);
// DescribeFeatureType - Supports both GET and POST - Returns XMLSchemas
DescribeFeatureTypeType describeFeatureType = new DescribeFeatureTypeType();
describeFeatureType.getDCPType().add(dcpGet);
describeFeatureType.getDCPType().add(dcpPost);
SchemaDescriptionLanguageType sdlt = new SchemaDescriptionLanguageType();
sdlt.getXMLSCHEMA().add(capsObjectFactory.createXMLSCHEMA(new EmptyType()).getValue());
describeFeatureType.setSchemaDescriptionLanguage(sdlt);
// GetFeature - Supports both GET and POST
GetFeatureTypeType getFeatureType = new GetFeatureTypeType();
ResultFormatType resultFormat = new ResultFormatType();
resultFormat.getGML2().add(new EmptyType());
getFeatureType.setResultFormat(resultFormat);
getFeatureType.getDCPType().add(dcpGet);
getFeatureType.getDCPType().add(dcpPost);
// Create The Capability Type
CapabilityType capability = new CapabilityType();
RequestType wfsRequest = new RequestType();
wfsRequest.getGetCapabilitiesOrDescribeFeatureTypeOrTransaction()
.add(capsObjectFactory.createRequestTypeGetCapabilities(getCapsType));
wfsRequest.getGetCapabilitiesOrDescribeFeatureTypeOrTransaction()
.add(capsObjectFactory.createRequestTypeDescribeFeatureType(describeFeatureType));
wfsRequest.getGetCapabilitiesOrDescribeFeatureTypeOrTransaction()
.add(capsObjectFactory.createRequestTypeGetFeature(getFeatureType));
capability.setRequest(wfsRequest);
wfsCapabilities.setCapability(capability);
// Create the Feature Type List
FeatureTypeListType featureTypeList = new FeatureTypeListType();
OperationsType operations = new OperationsType();
operations.getInsertOrUpdateOrDelete().add(capsObjectFactory.createQuery(new EmptyType()));
featureTypeList.setOperations(operations);
featureTypeList.getFeatureType().addAll(buildFeatureTypes());
wfsCapabilities.setFeatureTypeList(featureTypeList);
// Create the Filter_Capabilites - These are defined statically by the
// DDF FilterAdapter implementation
FilterCapabilities filterCapabilities = new FilterCapabilities();
ScalarCapabilitiesType scalarCapabilites = new ScalarCapabilitiesType();
scalarCapabilites.getLogicalOperatorsOrComparisonOperatorsOrArithmeticOperators()
.add(new LogicalOperators());
ComparisonOperatorsType compOpsType = new ComparisonOperatorsType();
compOpsType.getSimpleComparisonsOrLikeOrBetween().add(new Between());
compOpsType.getSimpleComparisonsOrLikeOrBetween().add(new NullCheck());
compOpsType.getSimpleComparisonsOrLikeOrBetween().add(new Like());
compOpsType.getSimpleComparisonsOrLikeOrBetween().add(new SimpleComparisons());
scalarCapabilites.getLogicalOperatorsOrComparisonOperatorsOrArithmeticOperators()
.add(compOpsType);
filterCapabilities.setScalarCapabilities(scalarCapabilites);
SpatialOperatorsType spatialOpsType = new SpatialOperatorsType();
spatialOpsType.getBBOXOrEqualsOrDisjoint().add(new Beyond());
spatialOpsType.getBBOXOrEqualsOrDisjoint().add(new Contains());
spatialOpsType.getBBOXOrEqualsOrDisjoint().add(new Crosses());
spatialOpsType.getBBOXOrEqualsOrDisjoint().add(new Disjoint());
spatialOpsType.getBBOXOrEqualsOrDisjoint().add(new DWithin());
spatialOpsType.getBBOXOrEqualsOrDisjoint().add(new Intersect());
spatialOpsType.getBBOXOrEqualsOrDisjoint().add(new Overlaps());
spatialOpsType.getBBOXOrEqualsOrDisjoint().add(new Touches());
spatialOpsType.getBBOXOrEqualsOrDisjoint().add(new Within());
SpatialCapabilitiesType spatialCaps = new SpatialCapabilitiesType();
spatialCaps.setSpatialOperators(spatialOpsType);
filterCapabilities.setSpatialCapabilities(spatialCaps);
wfsCapabilities.setFilterCapabilities(filterCapabilities);
return wfsCapabilities;
}
private List<FeatureTypeType> buildFeatureTypes() {
Set<QName> featureTypeNames = schemaCache.getFeatureTypeQnames();
List<FeatureTypeType> featureTypes = new ArrayList<FeatureTypeType>();
for (QName typeName : featureTypeNames) {
FeatureTypeType featureType = new FeatureTypeType();
// Name and SRS are the only required fields.
featureType.setName(typeName);
featureType.setSRS(Wfs10Constants.EPSG_4326);
featureType.setAbstract("DWithin and Beyond filters must use either \"METRE\" "
+ "or \"FOOT\" as the value in the Distance element's units attribute.");
featureTypes.add(featureType);
}
return featureTypes;
}
private InputStream marshalFilter(JAXBElement<FilterType> filterElement) throws JAXBException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
FilterTypeContextFactory.getInstance().createMarshaller().marshal(filterElement, os);
ByteArrayInputStream input = new ByteArrayInputStream(os.toByteArray());
IOUtils.closeQuietly(os);
return input;
}
private Filter parseFilter(FilterType filterType) throws JAXBException, IOException,
SAXException, ParserConfigurationException {
Parser filterParser = new Parser(PARSER_CONFIG);
InputStream inputStream = null;
JAXBElement<FilterType> filterElement = new ogc.schema.opengis.filter.v_1_0_0.ObjectFactory()
.createFilter(filterType);
inputStream = marshalFilter(filterElement);
return (Filter) filterParser.parse(inputStream);
}
private WfsException createUnexpectedServiceException(final String service,
final String version, final String request) {
return new WfsException(
"Unexpected service (" + service + ") or version (" + version + ") in request "
+ request + ".");
}
private WfsException createUnknownTypeException(final String type) {
return new WfsException("The type '" + type + "' is not known to this service.");
}
}