001 //$HeadURL: $
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
037 package org.deegree.ogcwebservices.wcts;
038
039 import static org.deegree.framework.xml.XMLTools.appendElement;
040 import static org.deegree.framework.xml.XMLTools.create;
041 import static org.deegree.framework.xml.XMLTools.getElement;
042 import static org.deegree.ogcbase.CommonNamespaces.GMLNS;
043 import static org.deegree.ogcbase.CommonNamespaces.GML_PREFIX;
044 import static org.deegree.ogcbase.CommonNamespaces.OWS_1_1_0PREFIX;
045 import static org.deegree.ogcbase.CommonNamespaces.WCTSNS;
046 import static org.deegree.ogcbase.CommonNamespaces.WCTS_PREFIX;
047 import static org.deegree.ogcbase.CommonNamespaces.getNamespaceContext;
048
049 import java.util.ArrayList;
050 import java.util.List;
051 import java.util.Map;
052
053 import org.deegree.crs.configuration.CRSConfiguration;
054 import org.deegree.crs.configuration.CRSProvider;
055 import org.deegree.crs.transformations.Transformation;
056 import org.deegree.framework.log.ILogger;
057 import org.deegree.framework.log.LoggerFactory;
058 import org.deegree.framework.util.Pair;
059 import org.deegree.framework.xml.XMLFragment;
060 import org.deegree.framework.xml.XMLParsingException;
061 import org.deegree.framework.xml.XMLTools;
062 import org.deegree.i18n.Messages;
063 import org.deegree.model.crs.CRSFactory;
064 import org.deegree.model.crs.CoordinateSystem;
065 import org.deegree.model.spatialschema.GMLGeometryAdapter;
066 import org.deegree.ogcbase.ExceptionCode;
067 import org.deegree.ogcwebservices.OGCWebService;
068 import org.deegree.ogcwebservices.OGCWebServiceException;
069 import org.deegree.ogcwebservices.OGCWebServiceRequest;
070 import org.deegree.ogcwebservices.wcts.capabilities.Content;
071 import org.deegree.ogcwebservices.wcts.capabilities.FeatureAbilities;
072 import org.deegree.ogcwebservices.wcts.capabilities.WCTSCapabilities;
073 import org.deegree.ogcwebservices.wcts.capabilities.mdprofiles.MetadataProfile;
074 import org.deegree.ogcwebservices.wcts.capabilities.mdprofiles.TransformationMetadata;
075 import org.deegree.ogcwebservices.wcts.configuration.WCTSConfiguration;
076 import org.deegree.ogcwebservices.wcts.configuration.WCTSDeegreeParams;
077 import org.deegree.ogcwebservices.wcts.data.TransformableData;
078 import org.deegree.ogcwebservices.wcts.operation.GetResourceByID;
079 import org.deegree.ogcwebservices.wcts.operation.GetTransformation;
080 import org.deegree.ogcwebservices.wcts.operation.IsTransformable;
081 import org.deegree.ogcwebservices.wcts.operation.Transform;
082 import org.deegree.ogcwebservices.wcts.operation.TransformResponse;
083 import org.deegree.ogcwebservices.wcts.operation.TransformationReference;
084 import org.deegree.ogcwebservices.wcts.operation.WCTSGetCapabilities;
085 import org.w3c.dom.Document;
086 import org.w3c.dom.Element;
087
088 /**
089 * The <code>WCTService</code> class is the interface between the actual handling of an incoming request and the
090 * configuration, key method is the {@link #doService(OGCWebServiceRequest)} implementation.
091 *
092 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
093 *
094 * @author last edited by: $Author:$
095 *
096 * @version February 7th 2008
097 *
098 */
099 public class WCTService implements OGCWebService {
100 private static ILogger LOG = LoggerFactory.getLogger( WCTService.class );
101
102 private final WCTSConfiguration config;
103
104 /**
105 * The version of this wcts, will be read from the configuration.
106 */
107 public static String version = "0.4.0";
108
109 /**
110 * The configured crs provider to use.
111 */
112 public static String CRS_PROVIDER = null;
113
114 /**
115 * @param config
116 */
117 public WCTService( final WCTSConfiguration config ) {
118 this.config = config;
119 synchronized ( LOG ) {
120 version = config.getVersion();
121 LOG.notifyAll();
122 }
123 CRS_PROVIDER = config.getDeegreeParams().getConfiguredCRSProvider();
124 }
125
126 /*
127 * (non-Javadoc)
128 *
129 * @see org.deegree.ogcwebservices.OGCWebService#doService(org.deegree.ogcwebservices.OGCWebServiceRequest)
130 */
131 public Object doService( OGCWebServiceRequest request )
132 throws OGCWebServiceException {
133 Object result = null;
134 if ( request != null ) {
135 long time = System.currentTimeMillis();
136 LOG.logDebug( "Incoming request with id: " + request.getId() );
137 if ( request instanceof GetResourceByID ) {
138 result = handleGetResourceByID( (GetResourceByID) request );
139 } else if ( request instanceof IsTransformable ) {
140 result = handleIsTransformable( (IsTransformable) request );
141 } else if ( request instanceof GetTransformation ) {
142 throw new OGCWebServiceException( Messages.getMessage( "WCTS_OPERATION_NOT_SUPPORTED",
143 "GetTransformation" ),
144 ExceptionCode.OPERATIONNOTSUPPORTED );
145 } else if ( request instanceof WCTSGetCapabilities ) {
146 result = handleCapabilities( (WCTSGetCapabilities) request );
147 } else if ( request instanceof Transform ) {
148 result = handleTransform( (Transform) request );
149 } else {
150 throw new OGCWebServiceException( request.toString(), Messages.getMessage( "WCTS_UNKNOWN_REQUEST" ),
151 ExceptionCode.OPERATIONNOTSUPPORTED );
152 }
153 LOG.logDebug( "The handling of request with id: " + request.getId() + " took: "
154 + ( System.currentTimeMillis() - time ) / 1000. + " seconds" );
155 }
156 if ( result == null ) {
157 LOG.logError( Messages.getMessage( "WCTS_ILLEGAL_STATE" ) + " incoming request is: " + request );
158 throw new OGCWebServiceException( Messages.getMessage( "WCTS_ILLEGAL_STATE" ),
159 ExceptionCode.NOAPPLICABLECODE );
160 }
161
162 return result;
163 }
164
165 /**
166 * @param request
167 * to be handled.
168 * @return the response to a GetResourceByID request (i.e. a gml:Dictionary with the description of the resource in
169 * gml3 ).
170 */
171 private XMLFragment handleGetResourceByID( GetResourceByID request ) {
172 Document doc = create();
173 Element root = doc.createElementNS( GMLNS.toASCIIString(), GML_PREFIX + ":Dictionary" );
174 XMLFragment response = new XMLFragment( root );
175 List<String> ids = request.getResourceIDs();
176 // for a crs this might be the way, maybe enhance the CRSProvider api to get an
177 // Identifiable?
178 CRSProvider provider = CRSConfiguration.getCRSConfiguration().getProvider();
179 List<org.deegree.crs.coordinatesystems.CoordinateSystem> requestedCRSs = new ArrayList<org.deegree.crs.coordinatesystems.CoordinateSystem>(
180 ids.size() );
181 for ( String id : ids ) {
182 org.deegree.crs.coordinatesystems.CoordinateSystem tmp = provider.getCRSByID( id );
183 if ( tmp != null ) {
184 requestedCRSs.add( tmp );
185 } else {
186 // what to do here? maybe an exception or try something else?.
187 }
188 }
189
190 return response;
191 }
192
193 /**
194 * @param request
195 * to be handled.
196 * @return a IsTransformable response, never <code>null</code>.
197 */
198 private XMLFragment handleIsTransformable( IsTransformable request ) {
199 Document doc = create();
200 Element root = doc.createElementNS( WCTSNS.toASCIIString(), WCTS_PREFIX + ":IsTransformableResponse" );
201 XMLFragment response = new XMLFragment( root );
202
203 Content content = config.getContents();
204 List<String> problems = new ArrayList<String>();
205 if ( request.getSourceCRS() == null ) {
206 problems.add( "SourceCRS" );
207 } else {
208 if ( content != null ) {
209 List<CoordinateSystem> sourceCRSs = content.getSourceCRSs();
210 if ( sourceCRSs == null || !sourceCRSs.contains( request.getSourceCRS() ) ) {
211 problems.add( "SourceCRS" );
212 }
213 }
214 }
215 if ( request.getTargetCRS() == null ) {
216 problems.add( "TargetCRS" );
217 } else {
218 if ( content != null ) {
219 List<CoordinateSystem> targetCRSs = content.getTargetCRSs();
220 if ( targetCRSs == null || !targetCRSs.contains( request.getTargetCRS() ) ) {
221 problems.add( "TargetCRS" );
222 }
223 }
224 }
225
226 // currently not supported operations.
227 if ( request.getCoverageTypes() != null && request.getCoverageTypes().size() > 0 ) {
228 problems.add( "CoverageType" );
229 }
230 if ( request.getInterpolationTypes() != null && request.getInterpolationTypes().size() > 0 ) {
231 problems.add( "InterpolationMethod" );
232 }
233
234 // check for geometry types.
235 List<Pair<String, String>> requestedGeoms = request.getGeometryTypes();
236 boolean geometriesFitConfigured = true;
237 if ( requestedGeoms != null && requestedGeoms.size() > 0 ) {
238 if ( content != null ) {
239 FeatureAbilities featureAbilities = content.getFeatureAbilities();
240 if ( featureAbilities != null ) {
241 List<Pair<String, String>> configuredGeomTypes = featureAbilities.getGeometryTypes();
242 if ( configuredGeomTypes != null && configuredGeomTypes.size() > 0 ) {
243 for ( Pair<String, String> requestedGeometry : requestedGeoms ) {
244 if ( geometriesFitConfigured && !configuredGeomTypes.contains( requestedGeometry ) ) {
245 problems.add( "GeometryType" );
246 geometriesFitConfigured = false;
247 }
248 }
249 } else {
250 problems.add( "GeometryType" );
251 geometriesFitConfigured = false;
252 }
253 } else {
254 problems.add( "GeometryType" );
255 geometriesFitConfigured = false;
256 }
257 } else {
258 problems.add( "GeometryType" );
259 geometriesFitConfigured = false;
260 }
261 }
262 if ( geometriesFitConfigured ) {
263 // the requested geometries did fit the configured geometries, but does deegree support them too?
264 if ( requestedGeoms != null ) {
265 boolean deegreeSupported = true;
266 for ( Pair<String, String> requestedGeometry : requestedGeoms ) {
267 if ( deegreeSupported && requestedGeometry != null ) {
268 String value = requestedGeometry.first;
269 if ( !GMLGeometryAdapter.isGeometrieSupported( value ) ) {
270 problems.add( "GeometryType" );
271 deegreeSupported = false;
272 }
273 }
274 }
275 }
276 }
277 root.setAttribute( "transformable", problems.size() == 0 ? "true" : "false" );
278 if ( problems.size() != 0 ) {
279 for ( String problem : problems ) {
280 if ( problem != null && !"".equals( problem.trim() ) ) {
281 Element problemo = appendElement( root, WCTSNS, WCTS_PREFIX + ":problem", problem );
282 problemo.setAttribute( "codeSpace", "http://schemas.opengis.net/wcts/0.0.0/problemType.xml" );
283 }
284 }
285 }
286 return response;
287 }
288
289 /**
290 * @return the capabilities according to the request.
291 */
292 private XMLFragment handleCapabilities( WCTSGetCapabilities request ) {
293 XMLFragment result = XMLFactory.create( getCapabilities() );
294 Element oldRoot = result.getRootElement();
295 Document doc = XMLTools.create();
296 Element root = (Element) doc.importNode( oldRoot, true );
297 doc.appendChild( root );
298 List<String> sections = request.getSections();
299 if ( sections.size() > 0 ) {
300 try {
301 // sections
302 if ( !sections.contains( "all" ) ) {
303 if ( !sections.contains( "serviceidentification" ) ) {
304 Element remove = getElement( root, OWS_1_1_0PREFIX + ":ServiceIdentification",
305 getNamespaceContext() );
306 if ( remove != null ) {
307 root.removeChild( remove );
308 }
309 }
310 if ( !sections.contains( "serviceprovider" ) ) {
311 Element remove = getElement( root, OWS_1_1_0PREFIX + ":ServiceProvider", getNamespaceContext() );
312 if ( remove != null ) {
313 root.removeChild( remove );
314 }
315 }
316 if ( !sections.contains( "operationsmetadata" ) ) {
317 Element remove = getElement( root, OWS_1_1_0PREFIX + ":OperationsMetadata",
318 getNamespaceContext() );
319 if ( remove != null ) {
320 root.removeChild( remove );
321 }
322 }
323 if ( !sections.contains( "contents" ) ) {
324 Element remove = getElement( root, WCTS_PREFIX + ":Contents", getNamespaceContext() );
325 if ( remove != null ) {
326 root.removeChild( remove );
327 }
328 }
329 }
330 } catch ( XMLParsingException e ) {
331 LOG.logError( "Could not handle requested 'sections' parameter because: " + e.getMessage(), e );
332 }
333 }
334 return new XMLFragment( root );
335 }
336
337 /**
338 * @param request
339 * to be handled
340 * @return the response or <code>null</code> if the request was <code>null</code>.
341 * @throws OGCWebServiceException
342 * if the inputdata could not be found, or the given crs are not configured to be supported.
343 */
344 public TransformResponse handleTransform( Transform request )
345 throws OGCWebServiceException {
346 if ( request == null ) {
347 return null;
348 }
349 // get the data and call transform.
350 TransformableData<?> transformableData = request.getTransformableData();
351 if ( transformableData == null ) {
352 throw new OGCWebServiceException( Messages.getMessage( "WCTS_TRANSFORM_MISSING_DATA" ),
353 WCTSExceptionCode.NO_INPUT_DATA );
354 }
355 Content content = config.getContents();
356 CoordinateSystem sourceCRS = request.getSourceCRS();
357 CoordinateSystem targetCRS = request.getTargetCRS();
358 Transformation transform = null;
359 if ( content != null ) {
360 if ( sourceCRS != null && targetCRS != null ) {
361 List<CoordinateSystem> sourceCRSs = content.getSourceCRSs();
362 if ( sourceCRSs == null || !sourceCRSs.contains( request.getSourceCRS() ) ) {
363 throw new OGCWebServiceException( Messages.getMessage( "CRS_UNKNOWNCRS",
364 request.getSourceCRS().getIdentifier() ),
365 ExceptionCode.INVALID_SRS );
366 }
367 List<CoordinateSystem> targetCRSs = content.getTargetCRSs();
368 if ( targetCRSs == null || !targetCRSs.contains( request.getTargetCRS() ) ) {
369 throw new OGCWebServiceException( Messages.getMessage( "CRS_UNKNOWNCRS",
370 request.getTargetCRS().getIdentifier() ),
371 ExceptionCode.INVALID_SRS );
372 }
373 } else {
374 // if no source and target crs were given, lets find the transformation.
375 TransformationReference transRef = request.getTransformationReference();
376 if ( transRef != null ) {
377 Map<String, Transformation> transformations = content.getTransformations();
378 String transformID = transRef.gettransformationId();
379 if ( transformID == null ) {
380 throw new OGCWebServiceException( Messages.getMessage( "WCTS_NO_TRANSFORM_ID" ),
381 ExceptionCode.MISSINGPARAMETERVALUE );
382 }
383 transform = transformations.get( transformID );
384 if ( transform == null ) {
385 List<MetadataProfile<?>> transformMetadata = content.getTransformMetadata();
386 if ( transformMetadata.size() > 0 ) {
387 for ( int i = 0; i < transformMetadata.size() && sourceCRS == null; ++i ) {
388 MetadataProfile<?> mp = transformMetadata.get( i );
389 if ( mp != null && ( mp instanceof TransformationMetadata ) ) {
390 if ( transformID.equals( ( (TransformationMetadata) mp ).getTransformID() ) ) {
391 sourceCRS = ( (TransformationMetadata) mp ).getSourceCRS();
392 targetCRS = ( (TransformationMetadata) mp ).getTargetCRS();
393 }
394 }
395 }
396 } else {
397 throw new OGCWebServiceException( Messages.getMessage( "WCTS_INVALID_TRANSFORM",
398 transformID ),
399 ExceptionCode.MISSINGPARAMETERVALUE );
400 }
401 }
402 } else {
403 throw new OGCWebServiceException( Messages.getMessage( "WCTS_NOT_VALID_XML_CHOICE",
404 "SourceCRS/TargetCRS and Transformation" ),
405 ExceptionCode.MISSINGPARAMETERVALUE );
406 }
407
408 }
409 }
410 if ( transform != null ) {
411 transformableData.doTransform( transform, request.extensiveLogging() );
412 sourceCRS = CRSFactory.create( transform.getSourceCRS() );
413 targetCRS = CRSFactory.create( transform.getTargetCRS() );
414 } else {
415 if ( sourceCRS == null || targetCRS == null ) {
416 throw new OGCWebServiceException( Messages.getMessage( "WCTS_NO_TRANSFORM_ID",
417 ExceptionCode.MISSINGPARAMETERVALUE ) );
418 }
419 transformableData.doTransform( sourceCRS, targetCRS, request.extensiveLogging() );
420 }
421
422 return new TransformResponse( sourceCRS, targetCRS, request.getDataPresentation(), request.mustStore(),
423 request.getInputData(), transformableData );
424 }
425
426 /*
427 * (non-Javadoc)
428 *
429 * @see org.deegree.ogcwebservices.OGCWebService#getCapabilities()
430 */
431 public WCTSCapabilities getCapabilities() {
432 return config;
433 }
434
435 /**
436 * The configuration of this wcts.
437 *
438 * @return the configuration of this wcts.
439 */
440 public final WCTSConfiguration getConfiguration() {
441 return config;
442 }
443
444 /**
445 * @return the deegree specific parameters for the wcts.
446 */
447 public final WCTSDeegreeParams getDeegreeParams() {
448 return config.getDeegreeParams();
449 }
450
451 }