// $Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/ogcwebservices/wfs/capabilities/WFSCapabilitiesDocument.java,v 1.20 2006/11/09 17:47:18 mschneider Exp $
/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2006 by:
EXSE, Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
This library 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 2.1 of the License, or (at your option) any later version.
This library 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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53115 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.ogcwebservices.wfs.capabilities;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.deegree.datatypes.Code;
import org.deegree.datatypes.QualifiedName;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.framework.util.StringTools;
import org.deegree.framework.xml.XMLParsingException;
import org.deegree.framework.xml.XMLTools;
import org.deegree.model.filterencoding.capabilities.FilterCapabilities;
import org.deegree.model.filterencoding.capabilities.FilterCapabilities110Fragment;
import org.deegree.model.metadata.iso19115.Keywords;
import org.deegree.model.spatialschema.Envelope;
import org.deegree.ogcbase.CommonNamespaces;
import org.deegree.ogcwebservices.getcapabilities.InvalidCapabilitiesException;
import org.deegree.ogcwebservices.getcapabilities.MetadataURL;
import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
import org.deegree.ogcwebservices.getcapabilities.Operation;
import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata;
import org.deegree.ogcwebservices.getcapabilities.ServiceIdentification;
import org.deegree.owscommon.OWSCommonCapabilitiesDocument;
import org.deegree.owscommon.OWSDomainType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
/**
* Represents a capabilities document for an OGC WFS 1.1.0 compliant web service.
*
* @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
* @author last edited by: $Author: mschneider $
*
* @version $Revision: 1.20 $, $Date: 2006/11/09 17:47:18 $
*/
public class WFSCapabilitiesDocument extends OWSCommonCapabilitiesDocument {
private static final long serialVersionUID = 6664839532969382269L;
public final static String FEATURE_TYPE_LIST_NAME = "FeatureTypeList";
public final static String SERVES_GML_OBJECT_TYPE_LIST_NAME = "ServesGMLObjectTypeList";
public final static String SUPPORTS_GML_OBJECT_TYPE_LIST_NAME = "SupportsGMLObjectTypeList";
public final static String FILTER_CAPABILITIES_NAME = "FilterCapabilities";
protected static final URI WFSNS = CommonNamespaces.WFSNS;
protected static final URI OGCNS = CommonNamespaces.OGCNS;
protected static final URI DEEGREEWFSNS = CommonNamespaces.DEEGREEWFS;
private static final String XML_TEMPLATE = "WFSCapabilitiesTemplate.xml";
private static final String[] VALID_TYPES = { "TDC211", "FGDC", "19115", "19139" };
private static final String[] VALID_FORMATS = { "text/xml", "text/html", "text/sgml",
"text/plain" };
private static final ILogger LOG = LoggerFactory.getLogger( WFSCapabilitiesDocument.class );
/**
* Creates a skeleton capabilities document that contains the mandatory elements only.
*
* @throws IOException
* @throws SAXException
*/
public void createEmptyDocument()
throws IOException, SAXException {
URL url = WFSCapabilitiesDocument.class.getResource( XML_TEMPLATE );
if ( url == null ) {
throw new IOException( "The resource '" + XML_TEMPLATE + " could not be found." );
}
load( url );
}
/**
* Creates a class representation of the document.
*
* @return class representation of the configuration document
*/
@Override
public OGCCapabilities parseCapabilities()
throws InvalidCapabilitiesException {
LOG.entering();
WFSCapabilities wfsCapabilities = null;
try {
wfsCapabilities = new WFSCapabilities( parseVersion(), parseUpdateSequence(),
getServiceIdentification(),
getServiceProvider(), getOperationsMetadata(),
getFeatureTypeList(),
getServesGMLObjectTypeList(),
getSupportsGMLObjectTypeList(), null,
getFilterCapabilities() );
} catch ( XMLParsingException e ) {
throw new InvalidCapabilitiesException( e.getMessage() + "\n"
+ StringTools.stackTraceToString( e ) );
}
LOG.exiting();
return wfsCapabilities;
}
/**
* Returns the class representation for the <code>ServiceIdentification</code> section of the
* document.
* <p>
* NOTE: this method is overridden, because the WFS 1.1.0 requires the OWS 1.0.0 version of
* the element
*
* @return class representation for the <code>ServiceIdentification</code> section
* @throws XMLParsingException
*/
@Override
public ServiceIdentification getServiceIdentification()
throws XMLParsingException {
Element element = XMLTools.getRequiredChildElement( "ServiceIdentification", OWSNS,
getRootElement() );
// 'ServiceType' element (mandatory)
Element serviceTypeElement = XMLTools.getRequiredChildElement( "ServiceType", OWSNS,
element );
Code serviceType = null;
try {
String codeSpace = XMLTools.getAttrValue( serviceTypeElement, OWSNS, "codeSpace" );
URI uri = codeSpace != null ? new URI( codeSpace ) : null;
serviceType = new Code( XMLTools.getStringValue( serviceTypeElement ), uri );
} catch ( URISyntaxException e ) {
throw new XMLParsingException( "Given value '"
+ XMLTools.getAttrValue( serviceTypeElement, OWSNS,
"codeSpace" )
+ "' in attribute 'codeSpace' of element 'ServiceType' "
+ "(namespace: '" + OWSNS + "') is not a valid URI." );
}
// 'ServiceTypeVersion' elements (mandatory)
String[] serviceTypeVersions = XMLTools.getRequiredNodeAsStrings( element,
"ows:ServiceTypeVersion",
nsContext, ",;" );
if ( serviceTypeVersions.length == 0 ) {
String msg = "No version specified in 'ows:ServiceTypeVersion' element.";
throw new XMLParsingException( msg );
}
// 'Fees' element (optional)
String fees = XMLTools.getStringValue( "Fees", OWSNS, element, null );
// 'AccessConstraints' elements (optional)
String accessConstraints[] = XMLTools.getNodesAsStrings( element, "ows:AccessConstraints",
nsContext );
ServiceIdentification serviceIdentification = new ServiceIdentification(
serviceType,
serviceTypeVersions,
null, null, null,
fees,
accessConstraints );
return serviceIdentification;
}
/**
* Creates an object representation of the <code>ows:OperationsMetadata</code> section.
*
* @return object representation of the <code>ows:OperationsMetadata</code> section
* @throws XMLParsingException
*/
public OperationsMetadata getOperationsMetadata()
throws XMLParsingException {
LOG.entering();
List operationElementList = XMLTools.getNodes( getRootElement(),
"ows:OperationsMetadata/ows:Operation",
nsContext );
// build HashMap of 'ows:Operation'-elements for easier access
Map operations = new HashMap();
for ( int i = 0; i < operationElementList.size(); i++ ) {
operations.put( XMLTools.getRequiredNodeAsString( (Node) operationElementList.get( i ),
"@name", nsContext ),
operationElementList.get( i ) );
}
Operation getCapabilities = getOperation( OperationsMetadata.GET_CAPABILITIES_NAME, true,
operations );
Operation describeFeatureType = getOperation(
WFSOperationsMetadata.DESCRIBE_FEATURETYPE_NAME,
true, operations );
Operation getFeature = getOperation( WFSOperationsMetadata.GET_FEATURE_NAME, false,
operations );
Operation getFeatureWithLock = getOperation(
WFSOperationsMetadata.GET_FEATURE_WITH_LOCK_NAME,
false, operations );
Operation getGMLObject = getOperation( WFSOperationsMetadata.GET_GML_OBJECT_NAME, false,
operations );
Operation lockFeature = getOperation( WFSOperationsMetadata.LOCK_FEATURE_NAME, false,
operations );
Operation transaction = getOperation( WFSOperationsMetadata.TRANSACTION_NAME, false,
operations );
List parameterElementList = XMLTools.getNodes( getRootElement(),
"ows:OperationsMetadata/ows:Parameter",
nsContext );
OWSDomainType[] parameters = new OWSDomainType[parameterElementList.size()];
for ( int i = 0; i < parameters.length; i++ ) {
parameters[i] = getOWSDomainType( null, (Element) parameterElementList.get( i ) );
}
List constraintElementList = XMLTools.getNodes( getRootElement(),
"ows:OperationsMetadata/ows:Constraint",
nsContext );
OWSDomainType[] constraints = new OWSDomainType[constraintElementList.size()];
for ( int i = 0; i < constraints.length; i++ ) {
constraints[i] = getOWSDomainType( null, (Element) constraintElementList.get( i ) );
}
WFSOperationsMetadata metadata = new WFSOperationsMetadata( getCapabilities,
describeFeatureType,
getFeature, getFeatureWithLock,
getGMLObject, lockFeature,
transaction, parameters,
constraints );
LOG.exiting();
return metadata;
}
/**
* Returns the object representation for the <code>wfs:FeatureTypeList</code>- section.
*
* @return object representation of the <code>wfs:FeatureTypeList</code> section, may be empty
* (if missing)
* @throws XMLParsingException
*/
public FeatureTypeList getFeatureTypeList()
throws XMLParsingException {
List<WFSFeatureType> wfsFeatureTypes = new ArrayList<WFSFeatureType>();
FeatureTypeList featureTypeList = new FeatureTypeList(
new org.deegree.ogcwebservices.wfs.capabilities.Operation[0],
wfsFeatureTypes );
Element element = (Element) XMLTools.getNode( getRootElement(), "wfs:FeatureTypeList",
nsContext );
if ( element != null ) {
org.deegree.ogcwebservices.wfs.capabilities.Operation[] globalOperations = null;
Element operationsTypeElement = (Element) XMLTools.getNode( element, "wfs:Operations",
nsContext );
if ( operationsTypeElement != null ) {
globalOperations = getOperationsType( operationsTypeElement );
}
List featureTypeElementList = XMLTools.getNodes( element, "wfs:FeatureType", nsContext );
// TODO Check this.
// if ( featureTypeElementList.getLength() < 1 ) {
// throw new XMLParsingException(
// "A wfs:FeatureTypeListType must contain at least one wfs:FeatureType-element." );
// }
for ( int i = 0; i < featureTypeElementList.size(); i++ ) {
WFSFeatureType wfsFT = getFeatureTypeType( (Element) featureTypeElementList.get( i ) );
wfsFeatureTypes.add( wfsFT );
}
featureTypeList = new FeatureTypeList( globalOperations, wfsFeatureTypes );
}
return featureTypeList;
}
/**
* Returns the object representation for the <code>wfs:ServesGMLObjectTypeList</code>-
* section.
*
* @return object representation of the <code>wfs:ServesGMLObjectTypeList</code> section, null
* if the section does not exist
* @throws XMLParsingException
*/
public GMLObject[] getServesGMLObjectTypeList()
throws XMLParsingException {
LOG.entering();
GMLObject[] gmlObjectTypes = null;
Element element = (Element) XMLTools.getNode( getRootElement(),
"wfs:ServesGMLObjectTypeList", nsContext );
if ( element != null ) {
List nodeList = XMLTools.getRequiredNodes( element, "wfs:GMLObjectType", nsContext );
gmlObjectTypes = new GMLObject[nodeList.size()];
for ( int i = 0; i < gmlObjectTypes.length; i++ ) {
gmlObjectTypes[i] = getGMLObjectType( (Element) nodeList.get( i ) );
}
}
LOG.exiting();
return gmlObjectTypes;
}
/**
* Returns the object representation for the <code>wfs:SupportsGMLObjectTypeList</code>-
* section.
*
* @return object representation of the <code>wfs:SupportsGMLObjectTypeList</code> section,
* null if the section does not exist
* @throws XMLParsingException
*/
public GMLObject[] getSupportsGMLObjectTypeList()
throws XMLParsingException {
LOG.entering();
GMLObject[] gmlObjectTypes = null;
Element element = (Element) XMLTools.getNode( getRootElement(),
"wfs:SupportsGMLObjectTypeList", nsContext );
if ( element != null ) {
List nodeList = XMLTools.getRequiredNodes( element, "wfs:GMLObjectType", nsContext );
gmlObjectTypes = new GMLObject[nodeList.size()];
for ( int i = 0; i < gmlObjectTypes.length; i++ ) {
gmlObjectTypes[i] = getGMLObjectType( (Element) nodeList.get( i ) );
}
}
LOG.exiting();
return gmlObjectTypes;
}
/**
* Returns the object representation for an element of type <code>wfs:GMLObjectType</code>.
*
* @param element
* @return object representation of the element of type <code>wfs:GMLObjectType</code>
* @throws XMLParsingException
*/
public GMLObject getGMLObjectType( Element element )
throws XMLParsingException {
QualifiedName name = parseQualifiedName( XMLTools.getRequiredNode( element,
"wfs:Name/text()",
nsContext ) );
String title = XMLTools.getNodeAsString( element, "wfs:Title/text()", nsContext, null );
String abstract_ = XMLTools.getNodeAsString( element, "wfs:Abstract/text()", nsContext,
null );
Keywords[] keywords = getKeywords( XMLTools.getNodes( element, "ows:Keywords", nsContext ) );
List formatElementList = XMLTools.getNodes( element, "wfs:OutputFormats/wfs:Format",
nsContext );
FormatType[] outputFormats = new FormatType[formatElementList.size()];
for ( int i = 0; i < outputFormats.length; i++ ) {
outputFormats[i] = getFormatType( (Element) formatElementList.get( i ) );
}
return new GMLObject( name, title, abstract_, keywords, outputFormats );
}
/**
* Returns the object representation for an element of type <code>wfs:FeatureTypeType</code>.
*
* @param element
* @return object representation for the element of type <code>wfs:OperationsType</code>
* @throws XMLParsingException
*/
public WFSFeatureType getFeatureTypeType( Element element )
throws XMLParsingException {
LOG.entering();
QualifiedName name = parseQualifiedName( XMLTools.getRequiredNode( element,
"wfs:Name/text()",
nsContext ) );
String title = XMLTools.getRequiredNodeAsString( element, "wfs:Title/text()", nsContext );
String abstract_ = XMLTools.getNodeAsString( element, "wfs:Abstract/text()", nsContext,
null );
Keywords[] keywords = getKeywords( XMLTools.getNodes( element, "ows:Keywords", nsContext ) );
URI defaultSrs = null;
URI[] otherSrs = null;
Node noSrsElement = XMLTools.getNode( element, "wfs:NoSRS", nsContext );
if ( noSrsElement == null ) {
defaultSrs = XMLTools.getNodeAsURI( element, "wfs:DefaultSRS/text()", nsContext, null );
if ( defaultSrs == null ) {
String msg = "A 'wfs:FeatureType' element must always contain a 'wfs:NoSRS' "
+ "element or a 'wfs:DefaultSRS' element";
throw new XMLParsingException (msg);
}
otherSrs = XMLTools.getNodesAsURIs( element, "wfs:OtherSRS/text()", nsContext );
}
org.deegree.ogcwebservices.wfs.capabilities.Operation[] operations = null;
Element operationsTypeElement = (Element) XMLTools.getNode( element, "wfs:Operations",
nsContext );
if ( operationsTypeElement != null ) {
operations = getOperationsType( operationsTypeElement );
}
List formatElementList = XMLTools.getNodes( element, "wfs:OutputFormats/wfs:Format",
nsContext );
FormatType[] formats = new FormatType[formatElementList.size()];
for ( int i = 0; i < formats.length; i++ ) {
formats[i] = getFormatType( (Element) formatElementList.get( i ) );
}
List wgs84BoundingBoxElements = XMLTools.getNodes( element, "ows:WGS84BoundingBox",
nsContext );
if ( wgs84BoundingBoxElements.size() < 1 ) {
throw new XMLParsingException( "A 'wfs:FeatureTypeType' must contain at least one "
+ "'ows:WGS84BoundingBox'-element." );
}
Envelope[] wgs84BoundingBoxes = new Envelope[wgs84BoundingBoxElements.size()];
for ( int i = 0; i < wgs84BoundingBoxes.length; i++ ) {
wgs84BoundingBoxes[i] = getWGS84BoundingBoxType( (Element) wgs84BoundingBoxElements.get( i ) );
}
List metadataURLElementList = XMLTools.getNodes( element, "wfs:MetadataURL", nsContext );
MetadataURL[] metadataUrls = new MetadataURL[metadataURLElementList.size()];
for ( int i = 0; i < metadataUrls.length; i++ ) {
metadataUrls[i] = getMetadataURL( (Element) metadataURLElementList.get( i ) );
}
WFSFeatureType featureType = new WFSFeatureType( name, title, abstract_, keywords,
defaultSrs, otherSrs, operations, formats,
wgs84BoundingBoxes, metadataUrls );
LOG.exiting();
return featureType;
}
/**
* Returns the object representation for an <code>wfs:OutputFormat</code> -element.
*
* @param element
* @return object representation for the element
* @throws XMLParsingException
*/
public FormatType getFormatType( Element element )
throws XMLParsingException {
LOG.entering();
URI inFilter = XMLTools.getNodeAsURI( element, "@deegreewfs:inFilter", nsContext, null );
URI outFilter = XMLTools.getNodeAsURI( element, "@deegreewfs:outFilter", nsContext, null );
URI schemaLocation = XMLTools.getNodeAsURI( element, "@deegreewfs:schemaLocation",
nsContext, null );
String value = XMLTools.getRequiredNodeAsString( element, "text()", nsContext );
FormatType outputFormat = new FormatType( inFilter, outFilter, schemaLocation, value );
LOG.exiting();
return outputFormat;
}
/**
* Returns the object representation for an element node of type
* <code>wfs:MetadataURLType</code>.
*
* TODO: Schema says base type is String, not URL!
*
* @param element
* @return object representation for the element of type <code>wfs:MetadataURLType</code>
* @throws XMLParsingException
*/
public MetadataURL getMetadataURL( Element element )
throws XMLParsingException {
LOG.entering();
String type = XMLTools.getRequiredNodeAsString( element, "@type", nsContext, VALID_TYPES );
String format = XMLTools.getRequiredNodeAsString( element, "@format", nsContext,
VALID_FORMATS );
String url = XMLTools.getRequiredNodeAsString( element, "text()", nsContext );
URL onlineResource;
try {
onlineResource = new URL( url );
} catch ( MalformedURLException e ) {
throw new XMLParsingException( "A wfs:MetadataURLType must contain a valid URL: "
+ e.getMessage() );
}
LOG.exiting();
return new MetadataURL( type, format, onlineResource );
}
/**
* Returns the object representation for an element node of type <code>wfs:OperationsType</code>.
*
* @param element
* @return object representation for the element of type <code>wfs:OperationsType</code>
* @throws XMLParsingException
*/
public org.deegree.ogcwebservices.wfs.capabilities.Operation[] getOperationsType(
Element element )
throws XMLParsingException {
LOG.entering();
String[] operationCodes = XMLTools.getNodesAsStrings( element, "wfs:Operation/text()",
nsContext );
org.deegree.ogcwebservices.wfs.capabilities.Operation[] operations = new org.deegree.ogcwebservices.wfs.capabilities.Operation[operationCodes.length];
for ( int i = 0; i < operations.length; i++ ) {
try {
operations[i] = new org.deegree.ogcwebservices.wfs.capabilities.Operation(
operationCodes[i] );
} catch ( InvalidParameterException e ) {
throw new XMLParsingException( e.getMessage() );
}
}
LOG.exiting();
return operations;
}
/**
* Returns the object representation for the <code>Filter_Capabilities</code> section of the
* document.
*
* @return class representation for the <code>Filter_Capabilities</code> section
* @throws XMLParsingException
*/
public FilterCapabilities getFilterCapabilities()
throws XMLParsingException {
FilterCapabilities filterCapabilities = null;
Element filterCapabilitiesElement = (Element) XMLTools.getNode( getRootElement(),
"ogc:Filter_Capabilities",
nsContext );
if ( filterCapabilitiesElement != null ) {
filterCapabilities = new FilterCapabilities110Fragment( filterCapabilitiesElement,
getSystemId() ).parseFilterCapabilities();
}
return filterCapabilities;
}
}
/* ********************************************************************
Changes to this class. What the people have been up to:
$Log: WFSCapabilitiesDocument.java,v $
Revision 1.20 2006/11/09 17:47:18 mschneider
Improved parsing of NoSRS element.
Revision 1.19 2006/11/07 11:09:36 mschneider
Added exceptions in case anything other than the 1.1.0 format is requested.
Revision 1.18 2006/10/02 16:53:34 mschneider
Reformatted.
Revision 1.17 2006/09/21 12:21:49 mschneider
Changed #getFilterCapabilities() to comply to WFS 1.1.0 and Filter Capabilities 1.1.0 specification.
Revision 1.16 2006/09/20 12:58:50 mschneider
Added overriden #getServiceIdentification() method for OWS 1.0.0 compliance.
Revision 1.15 2006/07/21 14:10:03 mschneider
Added constants for section names.
Revision 1.14 2006/07/12 14:46:15 poth
comment footer added
********************************************************************** */