001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/crs/configuration/deegree/DeegreeCRSProvider.java $
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.crs.configuration.deegree;
038    
039    import java.io.ByteArrayOutputStream;
040    import java.io.PrintWriter;
041    import java.io.UnsupportedEncodingException;
042    import java.lang.reflect.Constructor;
043    import java.lang.reflect.InvocationTargetException;
044    import java.util.LinkedList;
045    import java.util.List;
046    import java.util.Properties;
047    
048    import org.deegree.crs.Identifiable;
049    import org.deegree.crs.configuration.AbstractCRSProvider;
050    import org.deegree.crs.coordinatesystems.CoordinateSystem;
051    import org.deegree.crs.exceptions.CRSConfigurationException;
052    import org.deegree.crs.projections.Projection;
053    import org.deegree.crs.transformations.Transformation;
054    import org.deegree.framework.log.ILogger;
055    import org.deegree.framework.log.LoggerFactory;
056    import org.deegree.framework.util.CharsetUtils;
057    import org.deegree.framework.xml.NamespaceContext;
058    import org.deegree.framework.xml.XMLParsingException;
059    import org.deegree.framework.xml.XMLTools;
060    import org.deegree.i18n.Messages;
061    import org.deegree.ogcbase.CommonNamespaces;
062    import org.w3c.dom.Element;
063    
064    /**
065     * The <code>DeegreeCRSProvider</code> reads the deegree crs-config (based on it's own xml-schema) and creates the
066     * CRS's (and their datums, conversion info's, ellipsoids and projections) if requested.
067     * <p>
068     * Attention, although urn's are case-sensitive, the deegreeCRSProvider is not. All incoming id's are toLowerCased!
069     * </p>
070     * <h2>Automatic loading of projection/transformation classes</h2>
071     * It is possible to create your own projection/transformation classes, which can be automatically loaded.
072     * <p>
073     * You can achieve this loading by supplying the <b><code>class</code></b> attribute to a
074     * <code>crs:projectedCRS/crs:projection</code> or <code>crs:coordinateSystem/crs:transformation</code> element in
075     * the 'deegree-crs-configuration.xml'. This attribute must contain the full class name (with package), e.g.
076     * &lt;crs:projection class='my.package.and.projection.Implementation'&gt;
077     * </p>
078     * Because the loading is done with reflections your classes must sustain following criteria:
079     * <h3>Projections</h3>
080     * <ol>
081     * <li>It must be a sub class of {@link org.deegree.crs.projections.Projection}</li>
082     * <li>A constructor with following signature must be supplied: <br/> <code>
083     * public MyProjection( <br/>
084     * &emsp;&emsp;&emsp;&emsp;{@link org.deegree.crs.coordinatesystems.GeographicCRS} underlyingCRS,<br/>
085     * &emsp;&emsp;&emsp;&emsp;double falseNorthing,<br/>
086     * &emsp;&emsp;&emsp;&emsp;double falseEasting,<br/>
087     * &emsp;&emsp;&emsp;&emsp;javax.vecmath.Point2d naturalOrigin,<br/>
088     * &emsp;&emsp;&emsp;&emsp;{@link org.deegree.crs.components.Unit} units,<br/>
089     * &emsp;&emsp;&emsp;&emsp;double scale,<br/>
090     * &emsp;&emsp;&emsp;&emsp;java.util.List&lt;org.w3c.dom.Element&gt; yourProjectionElements<br/>
091     * );<br/>
092     * </code>
093     * <p>
094     * The first six parameters are common to all projections (for an explanation of their meaning take a look at
095     * {@link Projection}). The last list, will contain all xml-dom elements you supplied in the deegree configuration
096     * (child elements of the crs:projection/crs:MyProjection), thus relieving you of the parsing of the
097     * deegree-crs-configuration.xml document.
098     * </p>
099     * </li>
100     * </ol>
101     * <h3>Transformations</h3>
102     * <ol>
103     * <li>It must be a sub class of {@link org.deegree.crs.transformations.polynomial.PolynomialTransformation}</li>
104     * <li>A constructor with following signature must be supplied: <br/> <code>
105     * public MyTransformation( <br/>
106     * &emsp;&emsp;&emsp;&emsp;java.util.list&lt;Double&gt; aValues,<br/>
107     * &emsp;&emsp;&emsp;&emsp;java.util.list&lt;Double&gt; bValues,<br/>
108     * &emsp;&emsp;&emsp;&emsp;{@link org.deegree.crs.coordinatesystems.CoordinateSystem} targetCRS,<br/>
109     * &emsp;&emsp;&emsp;&emsp;java.util.List&lt;org.w3c.dom.Element&gt; yourTransformationElements<br/>
110     * );<br/>
111     * </code>
112     * <p>
113     * The first three parameters are common to all polynomial values (for an explanation of their meaning take a look at
114     * {@link org.deegree.crs.transformations.polynomial.PolynomialTransformation}). Again, the last list, will contain all
115     * xml-dom elements you supplied in the deegree configuration (child elements of the
116     * crs:transformation/crs:MyTransformation), thus relieving you of the parsing of the deegree-crs-configuration.xml
117     * document.
118     * </p>
119     * </li>
120     * </ol>
121     * 
122     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
123     * 
124     * @author last edited by: $Author: rbezema $
125     * 
126     * @version $Revision: 18308 $, $Date: 2009-07-02 14:40:19 +0200 (Do, 02. Jul 2009) $
127     * 
128     */
129    
130    public class DeegreeCRSProvider extends AbstractCRSProvider<Element> {
131    
132        private static ILogger LOG = LoggerFactory.getLogger( DeegreeCRSProvider.class );
133    
134        private CRSExporter exporter;
135    
136        /**
137         * The namespaces used in deegree.
138         */
139        private static NamespaceContext nsContext = CommonNamespaces.getNamespaceContext();
140    
141        /**
142         * The prefix to use.
143         */
144        private final static String PRE = CommonNamespaces.CRS_PREFIX + ":";
145    
146        // /**
147        // * The EPSG-Database defines only 48 different ellipsoids, set to 60, will --probably-- result in no collisions.
148        // */
149        // private final Map<String, Ellipsoid> ellipsoids = new HashMap<String, Ellipsoid>( 60 * 5 );
150        //
151        // /**
152        // * The EPSG-Database defines over 400 different Geodetic Datums, set to 450, will --probably-- result in no
153        // * collisions.
154        // */
155        // private final Map<String, GeodeticDatum> datums = new HashMap<String, GeodeticDatum>( 450 * 5 );
156        //
157        // /**
158        // * The EPSG-Database defines over 1100 different CoordinateTransformations, set to 1200, will --probably-- result
159        // in
160        // * no collisions.
161        // */
162        // private final Map<String, Helmert> conversionInfos = new HashMap<String, Helmert>( 1200 * 5 );
163        //
164        // /**
165        // * Theoretically infinite prime meridians could be defined, let's set it to a more practical number of 42.
166        // */
167        // private final Map<String, PrimeMeridian> primeMeridians = new HashMap<String, PrimeMeridian>( 42 * 5 );
168        //
169        // /**
170        // * The EPSG-Database defines over 2960 different ProjectedCRS's, set to 3500, will --probably-- result in no
171        // * collisions.
172        // */
173        // private final Map<String, ProjectedCRS> projectedCRSs = new HashMap<String, ProjectedCRS>( 3500 * 5 );
174        //
175        // /**
176        // * The EPSG-Database defines over 490 different GeographicCRS's (geodetic), set to 600, will --probably-- result
177        // in
178        // * no collisions.
179        // */
180        // private final Map<String, GeographicCRS> geographicCRSs = new HashMap<String, GeographicCRS>( 600 * 5 );
181        //
182        // /**
183        // * The EPSG-Database defines ???
184        // */
185        // private final Map<String, CompoundCRS> compoundCRSs = new HashMap<String, CompoundCRS>( 600 * 5 );
186        //
187        // /**
188        // * The EPSG-Database doesn't define GeocentricCRS's, set to 30, will --probably-- result in no collisions.
189        // */
190        // private final Map<String, GeocentricCRS> geocentricCRSs = new HashMap<String, GeocentricCRS>( 30 );
191        //
192        // private final List<GeocentricCRS> cachedGeocentricCRSs = new LinkedList<GeocentricCRS>();
193        //
194        // private final Map<String, String> doubleGeocentricCRSs = new HashMap<String, String>( 5000 );
195        //
196        // private final List<CompoundCRS> cachedCompoundCRSs = new LinkedList<CompoundCRS>();
197        //
198        // private final Map<String, String> doubleCompoundCRSs = new HashMap<String, String>( 5000 );
199        //
200        // private final List<GeographicCRS> cachedGeoCRSs = new LinkedList<GeographicCRS>();
201        //
202        // private final Map<String, String> doubleGeos = new HashMap<String, String>( 5000 );
203        //
204        // private final List<ProjectedCRS> cachedProjCRSs = new LinkedList<ProjectedCRS>();
205        //
206        // private final Map<String, String> doubleProjCRS = new HashMap<String, String>( 3000 );
207        //
208        // private final List<GeodeticDatum> cachedDatums = new LinkedList<GeodeticDatum>();
209        //
210        // private final Map<String, String> doubleDatums = new HashMap<String, String>( 3000 );
211        //
212        // private final List<Helmert> cachedToWGS = new LinkedList<Helmert>();
213        //
214        // private final Map<String, String> doubleToWGS = new HashMap<String, String>( 3000 );
215        //
216        // private final List<Ellipsoid> cachedEllipsoids = new LinkedList<Ellipsoid>();
217        //
218        // private final Map<String, String> doubleEllipsoids = new HashMap<String, String>( 3000 );
219        //
220        // private final List<PrimeMeridian> cachedMeridians = new LinkedList<PrimeMeridian>();
221        //
222        // private final Map<String, String> doubleMeridians = new HashMap<String, String>( 3000 );
223        //
224        // private final Map<String, String> doubleProjections = new HashMap<String, String>( 3000 );
225    
226        // /**
227        // * The root element of the deegree - crs - configuration.
228        // */
229        // private Element rootElement;
230    
231        // private boolean checkForDoubleDefinition = false;
232    
233        /**
234         * @param properties
235         *            containing information about the crs resource class and the file location of the crs configuration. If
236         *            either is null the default mechanism is using the {@link CRSParser} and the
237         *            deegree-crs-configuration.xml
238         * @throws CRSConfigurationException
239         *             if the give file or the default-crs-configuration.xml file could not be loaded.
240         */
241        public DeegreeCRSProvider( Properties properties ) throws CRSConfigurationException {
242            super( properties, CRSParser.class, null );
243            if ( getResolver() == null ) {
244                CRSParser versionedParser = new CRSParser( this, new Properties( properties ) );
245                String version = versionedParser.getVersion();
246                if ( !"".equals( version ) ) {
247                    version = version.trim().replaceAll( "\\.", "_" );
248                    String className = "org.deegree.crs.configuration.deegree.CRSParser_" + version;
249                    try {
250                        Class<?> tClass = Class.forName( className );
251                        tClass.asSubclass( CRSParser.class );
252                        LOG.logDebug( "Trying to load configured CRS provider from classname: " + className );
253                        Constructor<?> constructor = tClass.getConstructor( this.getClass(), Properties.class,
254                                                                            Element.class );
255                        if ( constructor == null ) {
256                            LOG.logError( "No constructor ( " + this.getClass() + ", Properties.class) found in class:"
257                                          + className );
258                        } else {
259                            versionedParser = (CRSParser) constructor.newInstance( this, new Properties( properties ),
260                                                                                   versionedParser.getRootElement() );
261                        }
262                        className = "org.deegree.crs.configuration.deegree.CRSExporter_" + version;
263                        try {
264                            tClass = Class.forName( className );
265                            tClass.asSubclass( CRSExporter.class );
266                            constructor = tClass.getConstructor( Properties.class );
267                            LOG.logDebug( "Trying to load configured CRS exporter for version: " + version
268                                          + " from classname: " + className );
269                        } catch ( ClassNotFoundException e ) {
270                            LOG.logDebug( "Could not load the exporter for version 1, using fallback mechanism." );
271                            constructor = null;
272                        }
273    
274                        if ( constructor == null ) {
275                            exporter = new CRSExporter( new Properties( properties ) );
276                            LOG.logDebug( "No constructor ( Properties.class ) found in class:" + className );
277                        } else {
278                            versionedParser = (CRSParser) constructor.newInstance( new Properties( properties ) );
279                        }
280                    } catch ( InstantiationException e ) {
281                        LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ) );
282                    } catch ( IllegalAccessException e ) {
283                        LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e );
284                    } catch ( ClassNotFoundException e ) {
285                        LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e );
286                    } catch ( SecurityException e ) {
287                        LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e );
288                    } catch ( NoSuchMethodException e ) {
289                        LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e );
290                    } catch ( IllegalArgumentException e ) {
291                        LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e );
292                    } catch ( InvocationTargetException e ) {
293                        LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, e.getMessage() ), e );
294                    } catch ( Throwable t ) {
295                        LOG.logError( Messages.getMessage( "CRS_CONFIG_INSTANTIATION_ERROR", className, t.getMessage() ), t );
296                    }
297                } else {
298                    exporter = new CRSExporter( new Properties( properties ) );
299                }
300                setResolver( versionedParser );
301            }
302        }
303    
304        public boolean canExport() {
305            return exporter != null;
306        }
307    
308        public void export( StringBuilder sb, List<CoordinateSystem> crsToExport ) {
309            if ( exporter == null ) {
310                throw new UnsupportedOperationException( "Exporting is not supported for this deegree-crs version" );
311            }
312            ByteArrayOutputStream out = new ByteArrayOutputStream();
313            PrintWriter writer = new PrintWriter( out );
314            exporter.export( writer, crsToExport );
315    
316            try {
317                sb.append( out.toString( CharsetUtils.getSystemCharset() ) );
318            } catch ( UnsupportedEncodingException e ) {
319                LOG.logError( e );
320            }
321    
322        }
323    
324        /**
325         * @return the casted resolver of the super class.
326         */
327        @Override
328        public CRSParser getResolver() {
329            return (CRSParser) super.getResolver();
330        }
331    
332        public List<String> getAvailableCRSIds()
333                                throws CRSConfigurationException {
334            List<Element> allCRSIDs = new LinkedList<Element>();
335    
336            try {
337                allCRSIDs.addAll( XMLTools.getElements( getResolver().getRootElement(), "//" + PRE + "geographicCRS/" + PRE
338                                                                                        + "id", nsContext ) );
339                allCRSIDs.addAll( XMLTools.getElements( getResolver().getRootElement(), "//" + PRE + "projectedCRS/" + PRE
340                                                                                        + "id", nsContext ) );
341                allCRSIDs.addAll( XMLTools.getElements( getResolver().getRootElement(), "//" + PRE + "geocentricCRS/" + PRE
342                                                                                        + "id", nsContext ) );
343                allCRSIDs.addAll( XMLTools.getElements( getResolver().getRootElement(), "//" + PRE + "compoundCRS/" + PRE
344                                                                                        + "id", nsContext ) );
345            } catch ( XMLParsingException e ) {
346                throw new CRSConfigurationException(
347                                                     Messages.getMessage( "CRS_CONFIG_GET_ALL_ELEMENT_IDS", e.getMessage() ),
348                                                     e );
349            }
350            List<String> result = new LinkedList<String>();
351            for ( Element crs : allCRSIDs ) {
352                if ( crs != null ) {
353                    result.add( XMLTools.getStringValue( crs ) );
354                }
355            }
356            return result;
357        }
358    
359        public List<CoordinateSystem> getAvailableCRSs()
360                                throws CRSConfigurationException {
361            List<CoordinateSystem> allSystems = new LinkedList<CoordinateSystem>();
362            if ( getResolver().getRootElement() != null ) {
363                List<Element> allCRSIDs = new LinkedList<Element>();
364    
365                try {
366                    allCRSIDs.addAll( XMLTools.getElements( getResolver().getRootElement(), "//" + PRE + "geographicCRS/"
367                                                                                            + PRE + "id", nsContext ) );
368                    allCRSIDs.addAll( XMLTools.getElements( getResolver().getRootElement(), "//" + PRE + "projectedCRS/"
369                                                                                            + PRE + "id", nsContext ) );
370                    allCRSIDs.addAll( XMLTools.getElements( getResolver().getRootElement(), "//" + PRE + "geocentricCRS/"
371                                                                                            + PRE + "id", nsContext ) );
372                    allCRSIDs.addAll( XMLTools.getElements( getResolver().getRootElement(), "//" + PRE + "compoundCRS/"
373                                                                                            + PRE + "id", nsContext ) );
374                } catch ( XMLParsingException e ) {
375                    throw new CRSConfigurationException( Messages.getMessage( "CRS_CONFIG_GET_ALL_ELEMENT_IDS",
376                                                                              e.getMessage() ), e );
377                }
378                final int total = allCRSIDs.size();
379                int count = 0;
380                int percentage = (int) Math.round( total / 100.d );
381                int number = 0;
382                System.out.println( "Trying to create a total of " + total + " coordinate systems." );
383                for ( Element crsID : allCRSIDs ) {
384                    if ( crsID != null ) {
385                        String id = crsID.getTextContent();
386                        if ( id != null && !"".equals( id.trim() ) ) {
387                            if ( count++ % percentage == 0 ) {
388                                System.out.print( "\r" + ( number ) + ( ( number++ < 10 ) ? "  " : " " ) + "% created" );
389                            }
390                            allSystems.add( getCRSByID( id ) );
391                        }
392                    }
393                }
394                System.out.println();
395                // if ( checkForDoubleDefinition ) {
396                // allSystems.addAll( cachedGeoCRSs );
397                // allSystems.addAll( cachedProjCRSs );
398                // allSystems.addAll( cachedGeocentricCRSs );
399                // allSystems.addAll( cachedCompoundCRSs );
400                // StringBuilder cachedGeos = new StringBuilder( "Cached Geographic coordinatesystems (" );
401                // cachedGeos.append( cachedGeoCRSs.size() ).append( "):\n" );
402                // for ( GeographicCRS geo : cachedGeoCRSs ) {
403                // cachedGeos.append( geo.getIdentifier() ).append( "\n" );
404                // }
405                // System.out.println( cachedGeos.toString() );
406                // if ( !doubleGeos.isEmpty() ) {
407                // Set<String> keys = doubleGeos.keySet();
408                // LOG.logInfo( "Following geographic crs's could probably be mapped on eachother" );
409                // for ( String key : keys ) {
410                // LOG.logInfo( key + " : " + doubleGeos.get( key ) );
411                // }
412                // }
413                // if ( !doubleProjCRS.isEmpty() ) {
414                // Set<String> keys = doubleProjCRS.keySet();
415                // LOG.logInfo( "Following projected crs's could probably be mapped on eachother" );
416                // for ( String key : keys ) {
417                // LOG.logInfo( key + " : " + doubleProjCRS.get( key ) );
418                // }
419                //
420                // }
421                // if ( !doubleGeocentricCRSs.isEmpty() ) {
422                // Set<String> keys = doubleGeocentricCRSs.keySet();
423                // LOG.logInfo( "Following geocentric crs's could probably be mapped on eachother" );
424                // for ( String key : keys ) {
425                // LOG.logInfo( key + " : " + doubleGeocentricCRSs.get( key ) );
426                // }
427                // }
428                //
429                // if ( !doubleProjections.isEmpty() ) {
430                // Set<String> keys = doubleProjections.keySet();
431                // LOG.logInfo( "Following projections could probably be mapped on eachother" );
432                // for ( String key : keys ) {
433                // LOG.logInfo( key + " : " + doubleProjections.get( key ) );
434                // }
435                // }
436                // if ( !doubleDatums.isEmpty() ) {
437                // Set<String> keys = doubleDatums.keySet();
438                // LOG.logInfo( "Following datums could probably be mapped on eachother" );
439                // for ( String key : keys ) {
440                // LOG.logInfo( key + " : " + doubleDatums.get( key ) );
441                // }
442                // }
443                // if ( !doubleToWGS.isEmpty() ) {
444                // Set<String> keys = doubleToWGS.keySet();
445                // LOG.logInfo( "Following wgs conversion infos could probably be mapped on eachother" );
446                // for ( String key : keys ) {
447                // LOG.logInfo( key + " : " + doubleToWGS.get( key ) );
448                // }
449                // }
450                // if ( !doubleEllipsoids.isEmpty() ) {
451                // Set<String> keys = doubleEllipsoids.keySet();
452                // LOG.logInfo( "Following ellipsoids could probably be mapped on eachother" );
453                // for ( String key : keys ) {
454                // LOG.logInfo( key + " : " + doubleEllipsoids.get( key ) );
455                // }
456                // }
457                // if ( !doubleMeridians.isEmpty() ) {
458                // Set<String> keys = doubleEllipsoids.keySet();
459                // LOG.logInfo( "Following prime meridians could probably be mapped on eachother" );
460                // for ( String key : keys ) {
461                // LOG.logInfo( key + " : " + doubleMeridians.get( key ) );
462                // }
463                // }
464                // } else {
465                // Collection<CompoundCRS> cCRSs = compoundCRSs.values();
466                // for ( String key : compoundCRSs.keySet() ) {
467                // CompoundCRS crs = compoundCRSs.get( key );
468                // if ( !allSystems.contains( crs ) ) {
469                // allSystems.add( crs );
470                // }
471                // }
472                // for ( String key : geographicCRSs.keySet() ) {
473                // GeographicCRS crs = geographicCRSs.get( key );
474                // if ( !allSystems.contains( crs ) ) {
475                // allSystems.add( crs );
476                // }
477                // }
478                // for ( String key : geocentricCRSs.keySet() ) {
479                // GeocentricCRS crs = geocentricCRSs.get( key );
480                // if ( !allSystems.contains( crs ) ) {
481                // allSystems.add( crs );
482                // }
483                // }
484                // for ( String key : projectedCRSs.keySet() ) {
485                // ProjectedCRS crs = projectedCRSs.get( key );
486                // if ( !allSystems.contains( crs ) ) {
487                // allSystems.add( crs );
488                // }
489                // }
490                // }
491    
492            } else {
493                LOG.logDebug( "The root element is null, is this correct behaviour?" );
494            }
495            return allSystems;
496        }
497    
498        public Identifiable getIdentifiable( String id )
499                                throws CRSConfigurationException {
500            Identifiable result = getCachedIdentifiable( id );
501            if ( result == null ) {
502                result = getResolver().parseIdentifiableObject( id );
503            }
504            return result;
505        }
506    
507        @Override
508        protected CoordinateSystem parseCoordinateSystem( Element crsDefinition )
509                                throws CRSConfigurationException {
510            return getResolver().parseCoordinateSystem( crsDefinition );
511        }
512    
513        @Override
514        public Transformation parseTransformation( Element transformationDefinition )
515                                throws CRSConfigurationException {
516            return getResolver().parseTransformation( transformationDefinition );
517    
518        }
519    
520        public Transformation getTransformation( CoordinateSystem sourceCRS, CoordinateSystem targetCRS )
521                                throws CRSConfigurationException {
522            return getResolver().getTransformation( sourceCRS, targetCRS );
523        }
524    
525    }