001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/ogcwebservices/wfs/DescribeFeatureTypeHandler.java $ 002 /*---------------------------------------------------------------------------- 003 This file is part of deegree, http://deegree.org/ 004 Copyright (C) 2001-2009 by: 005 Department of Geography, University of Bonn 006 and 007 lat/lon GmbH 008 009 This library is free software; you can redistribute it and/or modify it under 010 the terms of the GNU Lesser General Public License as published by the Free 011 Software Foundation; either version 2.1 of the License, or (at your option) 012 any later version. 013 This library is distributed in the hope that it will be useful, but WITHOUT 014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 016 details. 017 You should have received a copy of the GNU Lesser General Public License 018 along with this library; if not, write to the Free Software Foundation, Inc., 019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 021 Contact information: 022 023 lat/lon GmbH 024 Aennchenstr. 19, 53177 Bonn 025 Germany 026 http://lat-lon.de/ 027 028 Department of Geography, University of Bonn 029 Prof. Dr. Klaus Greve 030 Postfach 1147, 53001 Bonn 031 Germany 032 http://www.geographie.uni-bonn.de/deegree/ 033 034 e-mail: info@deegree.org 035 ----------------------------------------------------------------------------*/ 036 package org.deegree.ogcwebservices.wfs; 037 038 import java.io.IOException; 039 import java.net.URI; 040 import java.util.HashSet; 041 import java.util.Set; 042 043 import javax.xml.transform.TransformerException; 044 045 import org.deegree.datatypes.QualifiedName; 046 import org.deegree.framework.log.ILogger; 047 import org.deegree.framework.log.LoggerFactory; 048 import org.deegree.framework.xml.XMLFragment; 049 import org.deegree.framework.xml.XMLTools; 050 import org.deegree.framework.xml.XSLTDocument; 051 import org.deegree.framework.xml.schema.XSDocument; 052 import org.deegree.i18n.Messages; 053 import org.deegree.io.datastore.schema.MappedFeatureType; 054 import org.deegree.io.datastore.schema.MappedGMLSchema; 055 import org.deegree.model.feature.schema.FeatureType; 056 import org.deegree.ogcbase.CommonNamespaces; 057 import org.deegree.ogcwebservices.OGCWebServiceException; 058 import org.deegree.ogcwebservices.getcapabilities.DCPType; 059 import org.deegree.ogcwebservices.getcapabilities.HTTP; 060 import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities; 061 import org.deegree.ogcwebservices.wfs.capabilities.WFSOperationsMetadata; 062 import org.deegree.ogcwebservices.wfs.operation.DescribeFeatureType; 063 import org.deegree.ogcwebservices.wfs.operation.FeatureTypeDescription; 064 import org.w3c.dom.Element; 065 import org.xml.sax.SAXException; 066 067 /** 068 * Handler for {@link DescribeFeatureType} requests. 069 * 070 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a> 071 * @author <a href="mailto:deshmukh@lat-lon.de">Anup Deshmukh </a> 072 * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider</a> 073 * @author last edited by: $Author: mschneider $ 074 * 075 * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18 Jun 2009) $ 076 */ 077 class DescribeFeatureTypeHandler { 078 079 private static final ILogger LOG = LoggerFactory.getLogger( DescribeFeatureTypeHandler.class ); 080 081 private static final String TEMPLATE_FILE = "SchemaContainerTemplate.xml"; 082 083 private static final URI XSNS = CommonNamespaces.XSNS; 084 085 private static final String XS_PREFIX = CommonNamespaces.XS_PREFIX; 086 087 private WFService wfs; 088 089 private String describeFeatureTypeURL; 090 091 private static XSLTDocument annotationFilter; 092 093 static { 094 try { 095 annotationFilter = new XSLTDocument(); 096 annotationFilter.load( DescribeFeatureTypeHandler.class.getResource( "descfeaturetype.xsl" ) ); 097 } catch ( Exception e ) { 098 e.printStackTrace(); 099 LOG.logError( "Could not read describe feature type annotation filter XSLT-script:" + e.getMessage(), e ); 100 } 101 } 102 103 /** 104 * Creates a new <code>DescribeFeatureHandler</code> for the given {@link WFService}. 105 * 106 * @param wfs 107 * associated WFService 108 */ 109 DescribeFeatureTypeHandler( WFService wfs ) throws OGCWebServiceException { 110 this.wfs = wfs; 111 this.describeFeatureTypeURL = getDescribeFeatureTypeURL(); 112 } 113 114 /** 115 * Handles a DescribeFeatureType request. 116 * <p> 117 * If the requested feature types are all defined in the same GML application schema, the 118 * corresponding document is returned. Otherwise, a container schema document is generated which 119 * imports all necessary GML application schemas. 120 * 121 * @param request 122 * DescribeFeatureType request 123 * @return schema document encapsulated in a FeatureTypeDescription 124 */ 125 FeatureTypeDescription handleRequest( DescribeFeatureType request ) 126 throws OGCWebServiceException { 127 128 XSDocument schema = null; 129 // used to collect and eliminate duplicate GML application schema instances 130 Set<MappedGMLSchema> schemaSet = new HashSet<MappedGMLSchema>(); 131 132 QualifiedName[] ftNames = request.getTypeNames(); 133 if ( ftNames == null || ftNames.length == 0 ) { 134 // no feature types specified in request -> describe all visible feature types 135 for ( MappedFeatureType ft : this.wfs.getMappedFeatureTypes().values() ) { 136 if ( ft.isVisible() ) { 137 schemaSet.add( ft.getGMLSchema() ); 138 } 139 } 140 } else { 141 for ( QualifiedName ftName : ftNames ) { 142 MappedFeatureType ft = this.wfs.getMappedFeatureType( ftName ); 143 if ( ft == null ) { 144 String msg = Messages.getMessage( "WFS_FEATURE_TYPE_UNKNOWN", ftName ); 145 throw new OGCWebServiceException( this.getClass().getName(), msg ); 146 } 147 if ( !ft.isVisible() ) { 148 String msg = Messages.getMessage( "WFS_FEATURE_TYPE_INVISIBLE", ftName ); 149 throw new OGCWebServiceException( this.getClass().getName(), msg ); 150 } 151 schemaSet.add( ft.getGMLSchema() ); 152 } 153 } 154 155 if ( schemaSet.size() == 1 ) { 156 schema = schemaSet.iterator().next().getDocument(); 157 try { 158 schema = filterAnnotations( schema ); 159 } catch ( TransformerException e ) { 160 String msg = "Could not remove annotations from annotated GML application schema."; 161 LOG.logError( msg, e ); 162 throw new OGCWebServiceException( this.getClass().getName(), msg ); 163 } 164 } else { 165 try { 166 schema = getXSDContainer( schemaSet ); 167 schema = filterAnnotations( schema ); 168 } catch ( Exception e ) { 169 String msg = "Could not create XSD container document."; 170 LOG.logError( msg, e ); 171 throw new OGCWebServiceException( this.getClass().getName(), msg ); 172 } 173 } 174 return new FeatureTypeDescription( schema ); 175 } 176 177 /** 178 * Filters out all annotation elements from the schema. 179 * 180 * @param schema 181 * @return filter document (without annotation elements) 182 */ 183 private XSDocument filterAnnotations( XSDocument schema ) 184 throws TransformerException { 185 186 XMLFragment xml = annotationFilter.transform( schema ); 187 schema.setRootElement( xml.getRootElement() ); 188 return schema; 189 } 190 191 /** 192 * Creates a container schema document that imports all necessary GML application schemas. 193 * 194 * @param schemaSet 195 * @return container schema document 196 */ 197 private XSDocument getXSDContainer( Set<MappedGMLSchema> schemaSet ) 198 throws IOException, SAXException { 199 200 XSDocument schemaDoc = new XSDocument(); 201 schemaDoc.load( this.getClass().getResource( TEMPLATE_FILE ) ); 202 for ( MappedGMLSchema schema : schemaSet ) { 203 FeatureType representative = schema.getFeatureTypes()[0]; 204 appendImportElement( schemaDoc.getRootElement(), representative.getName() ); 205 } 206 207 return schemaDoc; 208 } 209 210 /** 211 * It is assumed that the passed Element is the root of an XML schema description. The different 212 * schema described by the passed <code>XMLFragment</code> will be included by adding an 213 * import statement to the root schema: 214 * 215 * <pre> 216 * <?xml version="1.0" ?> 217 * <schema targetNamespace="http://www.someserver.com/myns" 218 * xmlns:myns=http://www.someserver.com/myns 219 * xmlns="http://www.w3.org/2001/XMLSchema" 220 * elementFormDefault="qualified" 221 * attributeFormDefault="unqualified"> 222 * 223 * <import namespace="http://www.server01.com/ns01" 224 * schemaLocation="http://www.deegree.org/wfs?request=DescribeFeatureType&typeName=ns01:TreesA_1M"/> 225 * </schema> 226 * </pre> 227 * 228 * @param root 229 * root element of the target schema 230 * @param representative 231 * that shall be imported to the target schema 232 */ 233 private void appendImportElement( Element root, QualifiedName representative ) { 234 235 MappedFeatureType featureType = this.wfs.getMappedFeatureType( representative ); 236 MappedGMLSchema schema = featureType.getGMLSchema(); 237 238 URI targetNS = schema.getTargetNamespace(); 239 Element importElement = XMLTools.appendElement( root, XSNS, XS_PREFIX + ":import" ); 240 241 StringBuffer describeFeatureTypeURL = new StringBuffer( this.describeFeatureTypeURL ); 242 if ( !this.describeFeatureTypeURL.endsWith( "?" ) ) { 243 describeFeatureTypeURL.append( "?" ); 244 } 245 describeFeatureTypeURL.append( "SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=" ); 246 describeFeatureTypeURL.append( representative.getPrefixedName() ); 247 describeFeatureTypeURL.append( "&NAMESPACE=xmlns(" ); 248 describeFeatureTypeURL.append( representative.getPrefix() ).append( "=" ); 249 describeFeatureTypeURL.append( representative.getNamespace() ); 250 describeFeatureTypeURL.append( ")" ); 251 252 importElement.setAttribute( "namespace", targetNS.toString() ); 253 importElement.setAttribute( "schemaLocation", describeFeatureTypeURL.toString() ); 254 } 255 256 /** 257 * Extracts one valid URL with HTTP binding that can be used for describe feature type 258 * operations. 259 * 260 * @return a valid URL for DescribeFeatureType requests 261 * @throws OGCWebServiceException 262 */ 263 private String getDescribeFeatureTypeURL() 264 throws OGCWebServiceException { 265 WFSCapabilities capa = wfs.getCapabilities(); 266 WFSOperationsMetadata om = (WFSOperationsMetadata) capa.getOperationsMetadata(); 267 DCPType[] dcp = om.getDescribeFeatureType().getDCPs(); 268 int i = 0; 269 while ( i < dcp.length - 1 && !( dcp[i].getProtocol() instanceof HTTP ) ) { 270 i++; 271 } 272 273 if ( i >= dcp.length ) { 274 String msg = "No HTTP DCP for DescribeFeatureType operation defined in WFS capabilities."; 275 throw new OGCWebServiceException( this.getClass().getName(), msg ); 276 } 277 278 String address = null; 279 if ( ( (HTTP) dcp[i].getProtocol() ).getGetOnlineResources() != null 280 && ( (HTTP) dcp[i].getProtocol() ).getGetOnlineResources().length > 0 ) { 281 address = ( (HTTP) dcp[i].getProtocol() ).getGetOnlineResources()[0].toExternalForm(); 282 } else { 283 address = ( (HTTP) dcp[i].getProtocol() ).getPostOnlineResources()[0].toExternalForm(); 284 } 285 return address; 286 } 287 }