//$Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/ogcwebservices/wfs/DescribeFeatureTypeHandler.java,v 1.17 2006/11/16 08:53:21 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; import java.io.IOException; import java.net.URI; import java.util.HashSet; import java.util.Set; import javax.xml.transform.TransformerException; import org.deegree.datatypes.QualifiedName; import org.deegree.framework.log.ILogger; import org.deegree.framework.log.LoggerFactory; import org.deegree.framework.xml.XMLFragment; import org.deegree.framework.xml.XMLTools; import org.deegree.framework.xml.XSLTDocument; import org.deegree.framework.xml.schema.XSDocument; import org.deegree.i18n.Messages; import org.deegree.io.datastore.schema.MappedFeatureType; import org.deegree.io.datastore.schema.MappedGMLSchema; import org.deegree.model.feature.schema.FeatureType; import org.deegree.ogcbase.CommonNamespaces; import org.deegree.ogcwebservices.OGCWebServiceException; import org.deegree.ogcwebservices.getcapabilities.DCPType; import org.deegree.ogcwebservices.getcapabilities.HTTP; import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities; import org.deegree.ogcwebservices.wfs.capabilities.WFSOperationsMetadata; import org.deegree.ogcwebservices.wfs.operation.DescribeFeatureType; import org.deegree.ogcwebservices.wfs.operation.FeatureTypeDescription; import org.w3c.dom.Element; import org.xml.sax.SAXException; /** * Handler for {@link DescribeFeatureType} requests. * * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a> * @author <a href="mailto:deshmukh@lat-lon.de">Anup Deshmukh </a> * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider</a> * @author last edited by: $Author: mschneider $ * * @version $Revision: 1.17 $, $Date: 2006/11/16 08:53:21 $ */ class DescribeFeatureTypeHandler { private static final ILogger LOG = LoggerFactory.getLogger( DescribeFeatureTypeHandler.class ); private static final String TEMPLATE_FILE = "SchemaContainerTemplate.xml"; private static final URI XSNS = CommonNamespaces.XSNS; private static final String XS_PREFIX = CommonNamespaces.XS_PREFIX; private WFService owner; private String describeFeatureTypeURL; private static XSLTDocument xslt; static { try { xslt = new XSLTDocument(); xslt.load( DescribeFeatureTypeHandler.class.getResource( "descfeaturetype.xsl" ) ); } catch ( Exception e ) { e.printStackTrace(); LOG.logError( "could not read describe feature type annotation filter XSLT", e ); } } /** * Creates a new <code>DescribeFeatureHandler</code> for the given <code>WFService</code>. * * @param owner */ DescribeFeatureTypeHandler( WFService owner ) throws OGCWebServiceException { this.owner = owner; this.describeFeatureTypeURL = getDescribeFeatureTypeURL(); } /** * Handles a DescribeFeatureType request. * <p> * If the requested feature types are all defined in the same GML application schema, the * corresponding document is returned. Otherwise, a container schema document is generated which * imports all necessary GML application schemas. * * @param request * DescribeFeatureType request * @return schema document encapsulated in a FeatureTypeDescription */ FeatureTypeDescription handleRequest( DescribeFeatureType request ) throws OGCWebServiceException { LOG.entering(); XSDocument schema = null; // used to collect and eliminate duplicate GML application schema instances Set<MappedGMLSchema> schemaSet = new HashSet<MappedGMLSchema>(); QualifiedName[] ftNames = request.getTypeNames(); if ( ftNames == null || ftNames.length == 0 ) { // no feature types specified in request -> describe all visible feature types for ( MappedFeatureType ft : this.owner.getMappedFeatureTypes().values() ) { if ( ft.isVisible() ) { schemaSet.add( ft.getGMLSchema() ); } } } else { for ( QualifiedName ftName : ftNames ) { MappedFeatureType ft = this.owner.getMappedFeatureType( ftName ); if ( ft == null ) { String msg = Messages.getMessage( "WFS_FEATURE_TYPE_UNKNOWN", ftName ); throw new OGCWebServiceException( this.getClass().getName(), msg ); } if ( !ft.isVisible() ) { String msg = Messages.getMessage( "WFS_FEATURE_TYPE_INVISIBLE", ftName ); throw new OGCWebServiceException( this.getClass().getName(), msg ); } schemaSet.add( ft.getGMLSchema() ); } } if ( schemaSet.size() == 1 ) { schema = schemaSet.iterator().next().getDocument(); try { schema = filterAnnotations( schema ); } catch ( TransformerException e ) { String msg = "Could not remove annotations from annotated GML application schema."; LOG.logError( msg, e ); throw new OGCWebServiceException( this.getClass().getName(), msg ); } } else { try { schema = getXSDContainer( schemaSet ); schema = filterAnnotations( schema ); } catch ( Exception e ) { String msg = "Could not create XSD container document."; LOG.logError( msg, e ); throw new OGCWebServiceException( this.getClass().getName(), msg ); } } FeatureTypeDescription ftd = new FeatureTypeDescription( schema ); LOG.exiting(); return ftd; } /** * Filters out all annotation elements from the schema. * * @param schema * @return filter document (without annotation elements) */ private XSDocument filterAnnotations( XSDocument schema ) throws TransformerException { XMLFragment xml = xslt.transform( schema ); schema.setRootElement( xml.getRootElement() ); return schema; } /** * Creates a container schema document that imports all necessary GML application schemas. * * @param schemaSet * @return container schema document */ private XSDocument getXSDContainer( Set<MappedGMLSchema> schemaSet ) throws IOException, SAXException { XSDocument schemaDoc = new XSDocument(); schemaDoc.load( this.getClass().getResource( TEMPLATE_FILE ) ); for ( MappedGMLSchema schema : schemaSet ) { FeatureType representative = schema.getFeatureTypes()[0]; appendImportElement( schemaDoc.getRootElement(), representative.getName() ); } return schemaDoc; } /** * It is assumed that the passed Element is the root of an XML schema description. The different * schema described by the passed <code>XMLFragment</code> will be included by adding an * import statement to the root schema: * * <pre> * <?xml version="1.0" ?> * <schema targetNamespace="http://www.someserver.com/myns" * xmlns:myns=http://www.someserver.com/myns * xmlns="http://www.w3.org/2001/XMLSchema" * elementFormDefault="qualified" * attributeFormDefault="unqualified"> * * <import namespace="http://www.server01.com/ns01" * schemaLocation="http://www.deegree.org/wfs?request=DescribeFeatureType&typeName=ns01:TreesA_1M"/> * </schema> * </pre> * * @param root * root element of the target schema * @param schema * schema that shall be imported to the target schema */ private void appendImportElement( Element root, QualifiedName representative ) { LOG.entering(); MappedFeatureType featureType = this.owner.getMappedFeatureType( representative ); MappedGMLSchema schema = featureType.getGMLSchema(); URI targetNS = schema.getTargetNamespace(); Element importElement = XMLTools.appendElement( root, XSNS, XS_PREFIX + ":import" ); StringBuffer describeFeatureTypeURL = new StringBuffer( this.describeFeatureTypeURL ); if ( !this.describeFeatureTypeURL.endsWith( "?" ) ) { describeFeatureTypeURL.append( "?" ); } describeFeatureTypeURL.append( "SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=" ); describeFeatureTypeURL.append( representative.getAsString() ); describeFeatureTypeURL.append( "&NAMESPACE=xmlns(" ); describeFeatureTypeURL.append( representative.getPrefix() ).append( "=" ); describeFeatureTypeURL.append( representative.getNamespace() ); describeFeatureTypeURL.append( ")" ); importElement.setAttribute( "namespace", targetNS.toString() ); importElement.setAttribute( "schemaLocation", describeFeatureTypeURL.toString() ); LOG.exiting(); } /** * Extracts one valid URL with HTTP binding that can be used for describe feature type * operations. * * @return a valid URL for DescribeFeatureType requests * @throws OGCWebServiceException */ private String getDescribeFeatureTypeURL() throws OGCWebServiceException { WFSCapabilities capa = (WFSCapabilities) owner.getCapabilities(); WFSOperationsMetadata om = (WFSOperationsMetadata) capa.getOperationsMetadata(); DCPType[] dcp = om.getDescribeFeatureType().getDCPs(); int i = 0; while ( i < dcp.length - 1 && !( dcp[i].getProtocol() instanceof HTTP ) ) { i++; } if ( i >= dcp.length ) { String msg = "No HTTP DCP for DescribeFeatureType operation defined in WFS capabilities."; throw new OGCWebServiceException( this.getClass().getName(), msg ); } String address = null; if ( ( (HTTP) dcp[i].getProtocol() ).getGetOnlineResources() != null && ( (HTTP) dcp[i].getProtocol() ).getGetOnlineResources().length > 0 ) { address = ( (HTTP) dcp[i].getProtocol() ).getGetOnlineResources()[0].toExternalForm(); } else { address = ( (HTTP) dcp[i].getProtocol() ).getPostOnlineResources()[0].toExternalForm(); } return address; } } /*************************************************************************************************** * Changes to this class. What the people have been up to: * $Log: DescribeFeatureTypeHandler.java,v $ * Revision 1.17 2006/11/16 08:53:21 mschneider * Merged messages from org.deegree.ogcwebservices.wfs and its subpackages. * * Revision 1.16 2006/10/12 16:25:23 mschneider * Javadoc + compiler warning fixes. * * Revision 1.15 2006/10/11 20:13:24 mschneider * Fixed detection of application schemas that have to be references (if more than one feature type is asked for). * * Revision 1.14 2006/08/14 13:15:40 mschneider * Javadoc fixes. * * Revision 1.13 2006/07/05 23:24:01 mschneider * Fixed NullPointer that occured when no type names were specified at all. * * Revision 1.12 2006/04/06 20:25:21 poth * *** empty log message *** * * Revision 1.11 2006/03/30 21:20:23 poth * *** empty log message *** * * Revision 1.10 2006/03/21 13:23:56 poth * *** empty log message *** * * Revision 1.9 2006/02/05 21:22:32 mschneider * Added handling for invisible feature types. * * Revision 1.8 2006/01/24 11:08:59 poth * *** empty log message *** * * Revision 1.7 2005/12/08 13:30:52 poth * bug fixes for getNode and getNodes * * Revision 1.6 2005/12/04 19:21:09 poth * no message * * Revision 1.5 2005/11/16 13:44:59 mschneider * Merge of wfs development branch. * * Revision 1.4.2.7 2005/11/09 18:02:29 mschneider * More refactoring. * * Revision 1.10 2005/04/24 13:11:40 poth no message * * Revision 1.9 2005/04/06 10:58:15 poth no message * * Revision 1.8 2005/04/05 08:03:28 poth no message * * Revision 1.7 2005/04/04 16:16:17 poth no message * * Revision 1.6 2005/03/31 15:12:53 poth no message * * Revision 1.5 2005/03/22 17:44:41 mschneider ** empty log message *** * * Revision 1.4 2005/03/16 12:22:05 mschneider ** empty log message *** * * Revision 1.3 2005/03/12 10:45:03 poth no message * * Revision 1.2 2005/03/09 08:44:31 poth no message * * Revision 1.1 2005/03/07 08:23:40 poth no message * **************************************************************************************************/