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.capabilities; 038 039 import java.util.ArrayList; 040 import java.util.HashMap; 041 import java.util.LinkedList; 042 import java.util.List; 043 import java.util.Map; 044 045 import org.deegree.crs.exceptions.TransformationException; 046 import org.deegree.crs.transformations.Transformation; 047 import org.deegree.crs.transformations.TransformationFactory; 048 import org.deegree.crs.transformations.helmert.Helmert; 049 import org.deegree.framework.log.ILogger; 050 import org.deegree.framework.log.LoggerFactory; 051 import org.deegree.model.crs.CRSFactory; 052 import org.deegree.model.crs.CoordinateSystem; 053 import org.deegree.model.crs.UnknownCRSException; 054 import org.deegree.ogcwebservices.wcts.capabilities.mdprofiles.MetadataProfile; 055 import org.deegree.ogcwebservices.wcts.capabilities.mdprofiles.TransformationMetadata; 056 import org.deegree.owscommon_1_1_0.Metadata; 057 058 /** 059 * <code>Content</code> encapsulates the Content element of the WCTS_0.4.0 Capabilities document. 060 * 061 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 062 * 063 * @author last edited by: $Author:$ 064 * 065 * @version $Revision:$, $Date:$ 066 * 067 */ 068 public class Content { 069 070 private static ILogger LOG = LoggerFactory.getLogger( Content.class ); 071 072 private final Map<String, Transformation> transformations; 073 074 private final List<String> methods; 075 076 private List<CoordinateSystem> sourceCRSs; 077 078 private List<CoordinateSystem> targetCRSs; 079 080 private final CoverageAbilities coverageAbilities; 081 082 private final FeatureAbilities featureAbilities; 083 084 private final List<Metadata> metadata; 085 086 private final boolean userDefinedCRS; 087 088 private final List<MetadataProfile<?>> transformMetadata; 089 090 /** 091 * @param configuredTransforms 092 * Unordered list of zero or more identifiers of well-known coordinate operations which the server can 093 * perform. 094 * @param methods 095 * Unordered list of zero or more identifiers of well-known operation methods which the server can apply 096 * in user-defined coordinate Transformations and Conversions. 097 * @param sourceCRSs 098 * Unordered list of one or more identifiers of well-known CRSs in which the server can accept sourceCRS 099 * values. 100 * @param targetCRSs 101 * Unordered list of one or more identifiers of well-known CRSs in which the server can accept targetCRS 102 * values. 103 * @param coverageAbilities 104 * Specifies coverage transformation abilities of WCTS server. 105 * @param featureAbilities 106 * Specifies feature transformation abilities of WCTS server. 107 * @param metadata 108 * Optional unordered list of additional metadata about the data served by this WCTS implementation. For 109 * example, this metadata could include more detailed definitions of the Methods, Transformations, and 110 * CRSs known to this server, perhaps in the form of a gml:Dictionary of such information. 111 * @param userDefinedCRS 112 * Specifies if this server supports user-defined Coordinate Reference Systems (CRSs). 113 * @param transformMetadata 114 */ 115 public Content( Map<String, Transformation> configuredTransforms, List<String> methods, 116 List<CoordinateSystem> sourceCRSs, List<CoordinateSystem> targetCRSs, 117 CoverageAbilities coverageAbilities, FeatureAbilities featureAbilities, List<Metadata> metadata, 118 boolean userDefinedCRS, List<MetadataProfile<?>> transformMetadata ) { 119 if ( configuredTransforms == null ) { 120 this.transformations = new HashMap<String, Transformation>(); 121 } else { 122 this.transformations = configuredTransforms; 123 } 124 this.methods = methods; 125 this.sourceCRSs = sourceCRSs; 126 this.targetCRSs = targetCRSs; 127 this.coverageAbilities = coverageAbilities; 128 this.featureAbilities = featureAbilities; 129 if ( transformMetadata == null ) { 130 this.transformMetadata = new ArrayList<MetadataProfile<?>>(); 131 } else { 132 this.transformMetadata = transformMetadata; 133 } 134 if ( metadata == null ) { 135 this.metadata = new ArrayList<Metadata>(); 136 } else { 137 this.metadata = metadata; 138 } 139 this.userDefinedCRS = userDefinedCRS; 140 this.transformMetadata.addAll( createMDForConfiguredTransforms( transformations, transformMetadata ) ); 141 } 142 143 /** 144 * @return the transformations. 145 */ 146 public final Map<String, Transformation> getTransformations() { 147 return transformations; 148 } 149 150 /** 151 * @return the methods. 152 */ 153 public final List<String> getMethods() { 154 return methods; 155 } 156 157 /** 158 * @return the sourceCRSs. 159 */ 160 public final List<CoordinateSystem> getSourceCRSs() { 161 return sourceCRSs; 162 } 163 164 /** 165 * @return the targetCRSs. 166 */ 167 public final List<CoordinateSystem> getTargetCRSs() { 168 return targetCRSs; 169 } 170 171 /** 172 * @return the coverageAbilities. 173 */ 174 public final CoverageAbilities getCoverageAbilities() { 175 return coverageAbilities; 176 } 177 178 /** 179 * @return the featureAbilities. 180 */ 181 public final FeatureAbilities getFeatureAbilities() { 182 return featureAbilities; 183 } 184 185 /** 186 * @return the metadatas, may be empty but will never be <code>null</code> 187 */ 188 public final List<Metadata> getMetadata() { 189 return metadata; 190 } 191 192 /** 193 * @return the userDefinedCRS. 194 */ 195 public final boolean supportsUserDefinedCRS() { 196 return userDefinedCRS; 197 } 198 199 /** 200 * @return the transformMetadata elements. 201 */ 202 public final List<MetadataProfile<?>> getTransformMetadata() { 203 return transformMetadata; 204 } 205 206 /** 207 * Create the transformations and their MetaData for all source / target combinations, e.g. create identifiers for 208 * the default transformations of the crs package which is the usage of a wgs 84 pivot crs and the helmert 209 * transformation. 210 * 211 * @param transformationPrefix 212 * to be used for the transformations 213 */ 214 public void describeDefaultTransformations( String transformationPrefix ) { 215 List<TransformationMetadata> result = new ArrayList<TransformationMetadata>( transformMetadata.size() ); 216 List<String> allKeys = new LinkedList<String>( transformations.keySet() ); 217 int tCount = 0; 218 for ( CoordinateSystem sourceCRS : sourceCRSs ) { 219 if ( sourceCRS != null ) { 220 // lets create metadatas for all target crs's. 221 for ( CoordinateSystem tCRS : targetCRSs ) { 222 if ( !sourceCRS.getCRS().equals( tCRS.getCRS() ) ) { 223 Transformation trans = createTransformation( sourceCRS, tCRS ); 224 if ( trans != null ) { 225 // create a unique key. 226 String key = transformationPrefix + tCount; 227 while ( allKeys.contains( key ) ) { 228 key = transformationPrefix + ( ++tCount ); 229 } 230 allKeys.add( key ); 231 result.add( new TransformationMetadata( trans, key, sourceCRS, tCRS, 232 createTransformationMDDescription( sourceCRS, tCRS ) ) ); 233 // add it to the configured transforms as well. 234 transformations.put( key, trans ); 235 } 236 } 237 } 238 } 239 } 240 transformMetadata.addAll( result ); 241 } 242 243 /** 244 * Create a description saying:<code> 245 * Transforming from sourceCRS.getIdentifer (sourceCRS.getName() ) to targetCRS.getIdentifer (targetCRS.getName() ) using the helmert transformation. 246 * </code> 247 * if either the sourceCRS or the targetCRS are null the String "Transform using the helmert transformation." will 248 * be returned. 249 * 250 * @param sourceCRS 251 * @param targetCRS 252 * @return a possible description for a Transformation Metadata. 253 */ 254 protected String createTransformationMDDescription( CoordinateSystem sourceCRS, CoordinateSystem targetCRS ) { 255 if ( sourceCRS == null || targetCRS == null ) { 256 return "Transform using the helmert transformation."; 257 } 258 return "Transforming from " + sourceCRS.getIdentifier() 259 + ( ( sourceCRS.getCRS().getName() == null ) ? "" : " (" + sourceCRS.getCRS().getName() + ")" ) + " to " 260 + targetCRS.getIdentifier() 261 + ( ( targetCRS.getCRS().getName() == null ) ? "" : " (" + targetCRS.getCRS().getName() + ")" ) 262 + " using the helmert transformation."; 263 } 264 265 /** 266 * Creates a {@link TransformationMetadata} for the configured transformations and create Transformations for 267 * {@link TransformationMetadata} which do not have a {@link Transformation}. 268 * 269 * @param configuredTransformations 270 * to which the transformations will be added 271 * @param transformationMetadata 272 * containing all configured {@link TransformationMetadata} 273 * 274 * @return The list of {@link TransformationMetadata} that were created. 275 */ 276 private List<TransformationMetadata> createMDForConfiguredTransforms( 277 Map<String, Transformation> configuredTransformations, 278 List<MetadataProfile<?>> transformationMetadata ) { 279 List<TransformationMetadata> result = new ArrayList<TransformationMetadata>( transformationMetadata.size() ); 280 for ( String key : configuredTransformations.keySet() ) { 281 if ( key != null && !"".equals( key ) ) { 282 LOG.logDebug( "Finding transformation metadata for key:" + key ); 283 TransformationMetadata sync = null; 284 for ( MetadataProfile<?> mp : transformationMetadata ) { 285 if ( mp != null && ( mp instanceof TransformationMetadata ) ) { 286 if ( key.equalsIgnoreCase( ( (TransformationMetadata) mp ).getTransformID() ) ) { 287 if ( sync != null ) { 288 LOG.logWarning( "The key: " + key + " has multiple metadatas, this may not be." ); 289 } else { 290 LOG.logDebug( "Found a metadata for key: ", key ); 291 sync = (TransformationMetadata) mp; 292 if ( configuredTransformations.get( sync.getTransformID() ) == null 293 || configuredTransformations.get( sync.getTransformID() ) instanceof Helmert ) { 294 LOG.logDebug( "The transformation metadata referencing transformation: ", 295 sync.getTransformID(), 296 " did not have a transformation, creating a default one." ); 297 Transformation trans = createTransformation( sync.getSourceCRS(), 298 sync.getTargetCRS() ); 299 if ( trans != null ) { 300 configuredTransformations.put( key, trans ); 301 } 302 } 303 } 304 } 305 } 306 } 307 if ( sync == null ) { 308 Transformation trans = configuredTransformations.get( key ); 309 if ( trans != null ) { 310 LOG.logDebug( "Creating a metadata for key: ", key ); 311 result.add( new TransformationMetadata( trans, key, CRSFactory.create( trans.getSourceCRS() ), 312 CRSFactory.create( trans.getTargetCRS() ), 313 trans.getDescription() ) ); 314 } else { 315 LOG.logWarning( "Unable to create metadata from id: " + key 316 + " because no transformation was given." ); 317 } 318 319 } 320 } 321 } 322 return result; 323 } 324 325 /** 326 * Uses the configured identifiers of the source and targets to create new (cached) coordinatesystems. 327 * 328 * @param configuredProvider 329 * may be <code>null</code> to use the default crs provider. 330 * 331 */ 332 public synchronized void updateFromProvider( String configuredProvider ) { 333 LOG.logWarning( "Updating the transformations is currently not supported." ); 334 List<CoordinateSystem> newCRSs = updateCRSs( configuredProvider, sourceCRSs ); 335 sourceCRSs = newCRSs; 336 337 newCRSs = updateCRSs( configuredProvider, targetCRSs ); 338 targetCRSs = newCRSs; 339 } 340 341 private List<CoordinateSystem> updateCRSs( String configuredProvider, List<CoordinateSystem> crss ) { 342 List<CoordinateSystem> newCRSs = new ArrayList<CoordinateSystem>( crss.size() ); 343 for ( CoordinateSystem crs : crss ) { 344 if ( crs != null ) { 345 CoordinateSystem newCRS = null; 346 try { 347 newCRS = CRSFactory.create( configuredProvider, crs.getIdentifier() ); 348 } catch ( UnknownCRSException e ) { 349 LOG.logError( e ); 350 } 351 if ( newCRS != null ) { 352 newCRSs.add( newCRS ); 353 } else { 354 LOG.logWarning( "Removing old crs with id: " + crs.getIdentifier() 355 + " because it is no longer available in the crs registry." ); 356 } 357 } 358 } 359 return newCRSs; 360 } 361 362 private Transformation createTransformation( CoordinateSystem sourceCRS, CoordinateSystem targetCRS ) { 363 Transformation result = null; 364 try { 365 result = TransformationFactory.getInstance().createFromCoordinateSystems( sourceCRS.getCRS(), 366 targetCRS.getCRS() ); 367 } catch ( IllegalArgumentException e ) { 368 LOG.logError( "Error while creating a default transformation for sourceCRS: " + sourceCRS, e ); 369 } catch ( TransformationException e ) { 370 LOG.logError( "Error while creating a default transformation for sourceCRS: " + sourceCRS, e ); 371 } 372 return result; 373 374 } 375 376 }