    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    }