001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/ogcwebservices/wfs/operation/AbstractWFSRequest.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: Aennchenstraße 19
030: 53177 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.operation;
044:
045: import java.io.StringReader;
046: import java.net.URI;
047: import java.net.URISyntaxException;
048: import java.util.HashMap;
049: import java.util.Map;
050:
051: import org.deegree.datatypes.QualifiedName;
052: import org.deegree.framework.log.ILogger;
053: import org.deegree.framework.log.LoggerFactory;
054: import org.deegree.framework.xml.NamespaceContext;
055: import org.deegree.framework.xml.XMLTools;
056: import org.deegree.i18n.Messages;
057: import org.deegree.model.filterencoding.AbstractFilter;
058: import org.deegree.model.filterencoding.ComplexFilter;
059: import org.deegree.model.filterencoding.Filter;
060: import org.deegree.ogcwebservices.AbstractOGCWebServiceRequest;
061: import org.deegree.ogcwebservices.InconsistentRequestException;
062: import org.deegree.ogcwebservices.InvalidParameterValueException;
063: import org.deegree.ogcwebservices.wfs.WFService;
064: import org.w3c.dom.Document;
065:
066: /**
067: * Abstract base class for requests to web feature services.
068: *
069: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
070: * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
071: * @author last edited by: $Author: apoth $
072: *
073: * @version $Revision: 9345 $, $Date: 2007-12-27 08:22:25 -0800 (Thu, 27 Dec 2007) $
074: */
075: public class AbstractWFSRequest extends AbstractOGCWebServiceRequest {
076:
077: private static final ILogger LOG = LoggerFactory
078: .getLogger(AbstractWFSRequest.class);
079:
080: private static final long serialVersionUID = 6691114984307038750L;
081:
082: /** GML2 format * */
083: public static String FORMAT_GML2 = "text/xml; subtype=gml/2.1.2";
084:
085: /** GML2 format (WFS 1.00 style) * */
086: public static String FORMAT_GML2_WFS100 = "GML2";
087:
088: /** GML3 format * */
089: public static String FORMAT_GML3 = "text/xml; subtype=gml/3.1.1";
090:
091: /** Generic XML format * */
092: public static String FORMAT_XML = "XML";
093:
094: private String handle = null;
095:
096: /**
097: * Creates a new <code>AbstractWFSRequest</code> instance.
098: *
099: * @param version
100: * @param id
101: * @param handle
102: * @param vendorSpecificParameter
103: */
104: protected AbstractWFSRequest(String version, String id,
105: String handle, Map<String, String> vendorSpecificParameter) {
106: super (version, id, vendorSpecificParameter);
107: this .handle = handle;
108: }
109:
110: /**
111: * Returns the value of the service attribute (WFS).
112: *
113: * @return the value of the service attribute (WFS)
114: */
115: public String getServiceName() {
116: return "WFS";
117: }
118:
119: /**
120: * Returns the value of the handle attribute.
121: * <p>
122: * The purpose of the <b>handle</b> attribute is to allow a client application to associate a
123: * mnemonic name with a request for error handling purposes. If a <b>handle</b> is specified,
124: * and an exception is encountered, a Web Feature Service may use the <b>handle</b> to identify
125: * the offending element.
126: *
127: * @return the value of the handle attribute
128: */
129: public String getHandle() {
130: return this .handle;
131: }
132:
133: /**
134: * Checks that the "VERSION" parameter value equals a supported version.
135: *
136: * @param model
137: * contains the parameters of the request
138: * @return value for "VERSION" parameter, never null
139: * @throws InconsistentRequestException
140: * if parameter is not present
141: * @throws InvalidParameterValueException
142: */
143: protected static String checkVersionParameter(
144: Map<String, String> model)
145: throws InconsistentRequestException,
146: InvalidParameterValueException {
147: String version = model.get("VERSION");
148: if (version == null) {
149: throw new InconsistentRequestException(
150: "'VERSION' parameter must be set.");
151: }
152:
153: if (!WFService.VERSION.equals(version)
154: && !"1.0.0".equals(version)) {
155: String msg = Messages.getMessage(
156: "WFS_REQUEST_UNSUPPORTED_VERSION", version,
157: "1.0.0 and " + WFService.VERSION);
158: throw new InvalidParameterValueException(msg);
159: }
160: return version;
161: }
162:
163: /**
164: * Checks that the "SERVICE" parameter value equals the name of the service.
165: *
166: * TODO move this to AbstractOGCWebServiceRequest
167: *
168: * @param model
169: * contains the parameters of the request
170: * @throws InconsistentRequestException
171: * if parameter is not present or does not the service name
172: */
173: protected static void checkServiceParameter(
174: Map<String, String> model)
175: throws InconsistentRequestException {
176: String service = model.get("SERVICE");
177: if (!"WFS".equals(service)) {
178: throw new InconsistentRequestException(
179: "'SERVICE' parameter must be 'WFS', but is '"
180: + service + "'.");
181: }
182: }
183:
184: /**
185: * Extracts the qualified type names from the TYPENAME parameter.
186: *
187: * @param kvp
188: * @return qualified type names (empty array if TYPENAME parameter is not present)
189: * @throws InvalidParameterValueException
190: */
191: protected static QualifiedName[] extractTypeNames(
192: Map<String, String> kvp)
193: throws InvalidParameterValueException {
194: QualifiedName[] typeNames = new QualifiedName[0];
195: NamespaceContext nsContext = extractNamespaceParameter(kvp);
196: String typeNameString = kvp.get("TYPENAME");
197: if (typeNameString != null) {
198: String[] typeNameStrings = typeNameString.split(",");
199: typeNames = new QualifiedName[typeNameStrings.length];
200: for (int i = 0; i < typeNameStrings.length; i++) {
201: typeNames[i] = transformToQualifiedName(
202: typeNameStrings[i], nsContext);
203: }
204: }
205: return typeNames;
206: }
207:
208: /**
209: * Extracts the namespace bindings from the NAMESPACE parameter.
210: * <p>
211: * Example:
212: * <ul>
213: * <li><code>NAMESPACE=xmlns(myns=http://www.someserver.com),xmlns(yourns=http://www.someotherserver.com)</code></li>
214: * </ul>
215: * <p>
216: * The default namespace may also be bound (two variants are supported):
217: * <ul>
218: * <li><code>NAMESPACE=xmlns(=http://www.someserver.com)</code></li>
219: * <li><code>NAMESPACE=xmlns(http://www.someserver.com)</code></li>
220: * </ul>
221: *
222: * @param model
223: * the parameters of the request
224: * @return namespace context
225: * @throws InvalidParameterValueException
226: */
227: protected static NamespaceContext extractNamespaceParameter(
228: Map<String, String> model)
229: throws InvalidParameterValueException {
230:
231: String nsString = model.get("NAMESPACE");
232:
233: NamespaceContext nsContext = new NamespaceContext();
234: if (nsString != null) {
235: String nsDecls[] = nsString.split(",");
236: for (int i = 0; i < nsDecls.length; i++) {
237: String nsDecl = nsDecls[i];
238: if (nsDecl.startsWith("xmlns(") && nsDecl.endsWith(")")) {
239: nsDecl = nsDecl.substring(6, nsDecl.length() - 1);
240: int assignIdx = nsDecl.indexOf('=');
241: String prefix = "";
242: String nsURIString = null;
243: if (assignIdx != -1) {
244: prefix = nsDecl.substring(0, assignIdx);
245: nsURIString = nsDecl.substring(assignIdx + 1);
246: } else {
247: nsURIString = nsDecl;
248: }
249: try {
250: URI nsURI = new URI(nsURIString);
251: nsContext.addNamespace(prefix, nsURI);
252: } catch (URISyntaxException e) {
253: String msg = Messages.getMessage(
254: "WFS_NAMESPACE_PARAM_INVALID_URI",
255: nsURIString, prefix);
256: throw new InvalidParameterValueException(msg);
257: }
258: } else {
259: String msg = Messages
260: .getMessage("WFS_NAMESPACE_PARAM");
261: throw new InvalidParameterValueException(msg);
262: }
263: }
264: }
265: return nsContext;
266: }
267:
268: /**
269: * Extracts a <code>Filter</code> from the BBOX parameter.
270: *
271: * TODO handle other dimension count and crs
272: *
273: * @param model
274: * @return filter representing the BBOX parameter (null, if no BBOX parameter specified)
275: * @throws InvalidParameterValueException
276: */
277: protected static Filter extractBBOXFilter(Map<String, String> model)
278: throws InvalidParameterValueException {
279:
280: ComplexFilter filter = null;
281: String bboxString = model.get("BBOX");
282: if (bboxString != null) {
283: String msg = "Parameter 'BBOX' is currently not supported. Please use the 'FILTER' parameter instead.";
284: throw new InvalidParameterValueException(msg);
285: // String[] parts = bboxString.split( "," );
286: // double[] coords = new double[4];
287: //
288: // if ( parts.length > 5 ) {
289: // String msg = Messages.getString( "WFS_BBOX_PARAM_WRONG_COORD_COUNT" );
290: // throw new InvalidParameterValueException( msg );
291: // }
292: //
293: // for ( int i = 0; i < coords.length; i++ ) {
294: // try {
295: // coords[i] = Double.parseDouble( parts[i] );
296: // } catch ( NumberFormatException e ) {
297: // String msg = Messages.getMessage( "WFS_BBOX_PARAM_COORD_INVALID", coords[i] );
298: // throw new InvalidParameterValueException( msg );
299: // }
300: // }
301: //
302: // // build filter
303: // Envelope bbox = GeometryFactory.createEnvelope( coords[0], coords[1], coords[2],
304: // coords[3], null );
305: // Surface surface;
306: // try {
307: // surface = GeometryFactory.createSurface( bbox, null );
308: // } catch ( GeometryException e ) {
309: // String msg = Messages.getMessage( "WFS_BBOX_PARAM_BBOX_INVALID", e.getMessage() );
310: // throw new InvalidParameterValueException( msg );
311: // }
312: // Operation op = new SpatialOperation( OperationDefines.BBOX, null, surface );
313: // filter = new ComplexFilter( op );
314: }
315: return filter;
316: }
317:
318: /**
319: * Extracts the FILTER parameter and assigns them to the requested type names.
320: * <p>
321: * This is necessary, because it is allowed to specify a filter for each requested feature type.
322: *
323: * @param kvp
324: * @param typeNames
325: * @return map with the assignments of type names to filters
326: * @throws InvalidParameterValueException
327: */
328: protected static Map<QualifiedName, Filter> extractFilters(
329: Map<String, String> kvp, QualifiedName[] typeNames)
330: throws InvalidParameterValueException {
331: Map<QualifiedName, Filter> filterMap = new HashMap<QualifiedName, Filter>();
332: String filterString = kvp.get("FILTER");
333: if (filterString != null) {
334: String[] filterStrings = filterString.split("\\)");
335: if (filterStrings.length != typeNames.length) {
336: String msg = Messages.getMessage(
337: "WFS_FILTER_PARAM_WRONG_COUNT", Integer
338: .toString(filterStrings.length),
339: Integer.toString(typeNames.length));
340: throw new InvalidParameterValueException(msg);
341: }
342: for (int i = 0; i < filterStrings.length; i++) {
343: // remove possible leading parenthesis
344: if (filterStrings[i].startsWith("(")) {
345: filterStrings[i] = filterStrings[i].substring(1);
346: }
347: Document doc;
348: try {
349: doc = XMLTools.parse(new StringReader(
350: filterStrings[i]));
351: Filter filter = AbstractFilter.buildFromDOM(doc
352: .getDocumentElement());
353: filterMap.put(typeNames[i], filter);
354: } catch (Exception e) {
355: LOG.logError(e.getMessage(), e);
356: String msg = Messages.getMessage(
357: "WFS_FILTER_PARAM_PARSING", e.getMessage());
358: throw new InvalidParameterValueException(msg);
359: }
360: }
361: }
362: return filterMap;
363: }
364:
365: /**
366: * Transforms a type name to a qualified name using the given namespace bindings.
367: *
368: * @param name
369: * @param nsContext
370: * @return QualifiedName
371: * @throws InvalidParameterValueException
372: */
373: private static QualifiedName transformToQualifiedName(String name,
374: NamespaceContext nsContext)
375: throws InvalidParameterValueException {
376: QualifiedName typeName;
377: String prefix = "";
378: int idx = name.indexOf(':');
379: if (idx != -1) {
380: prefix = name.substring(0, idx);
381: String localName = name.substring(idx + 1);
382: URI nsURI = nsContext.getURI(prefix);
383: if (nsURI == null) {
384: String msg = Messages.getMessage(
385: "WFS_TYPENAME_PARAM_INVALID_URI", prefix);
386: throw new InvalidParameterValueException(msg);
387: }
388: typeName = new QualifiedName(prefix, localName, nsURI);
389: } else {
390: // default namespace prefix ("")
391: URI nsURI = nsContext.getURI("");
392: typeName = new QualifiedName(name, nsURI);
393: }
394: return typeName;
395: }
396: }
|