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 }