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