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 }