/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.referencing.factory; import java.util.Map; import java.util.Set; import java.util.List; import java.util.Arrays; import java.util.Iterator; import java.util.Comparator; import java.util.LinkedHashSet; import javax.measure.unit.Unit; import org.opengis.metadata.citation.Citation; import org.opengis.referencing.IdentifiedObject; import org.opengis.referencing.AuthorityFactory; import org.opengis.referencing.FactoryException; import org.opengis.referencing.cs.*; import org.opengis.referencing.crs.*; import org.opengis.referencing.datum.*; import org.opengis.referencing.operation.*; import org.geotools.util.CanonicalSet; import org.geotools.factory.Hints; import org.geotools.factory.FactoryRegistryException; import org.geotools.referencing.AbstractIdentifiedObject; import org.geotools.referencing.operation.DefiningConversion; import org.geotools.referencing.cs.DefaultCoordinateSystemAxis; import org.geotools.resources.Classes; import org.geotools.resources.i18n.ErrorKeys; import org.geotools.resources.i18n.Errors; import org.geotools.util.Utilities; /** * An authority factory which returns modified {@linkplain CoordinateReferenceSystem CRS}, * {@linkplain CoordinateSystem CS} or {@linkplain Datum datum} objects from other factory * implementations. This class provides a set of {@code replace(...)} methods to be overridden * by subclasses in order to replace some {@linkplain CoordinateReferenceSystem CRS}, * {@linkplain CoordinateSystem CS} or {@linkplain Datum datum} objects by other ones. * The replacement rules are determined by the subclass being used. For example the * {@link OrderedAxisAuthorityFactory} subclass can replace * {@linkplain CoordinateSystem coordinate systems} using (latitude, * longitude) axis order by coordinate systems using (longitude, * latitude) axis order. *
* All constructors are protected because this class must be subclassed in order to
* determine which of the {@link DatumAuthorityFactory}, {@link CSAuthorityFactory}
* and {@link CRSAuthorityFactory} interfaces to implement.
*
* @since 2.3
*
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux (IRD)
*
* @todo Use generic types for all {@code replace(...)} methods when we will be
* allowed to compile for J2SE 1.5, and remove casts in all
* {@code createXXX(...)} methods.
*/
public class TransformedAuthorityFactory extends AuthorityFactoryAdapter {
/**
* Axis that need to be renamed if their direction changes.
*/
private static final DefaultCoordinateSystemAxis[] RENAMEABLE = {
DefaultCoordinateSystemAxis.NORTHING, DefaultCoordinateSystemAxis.SOUTHING,
DefaultCoordinateSystemAxis.EASTING, DefaultCoordinateSystemAxis.WESTING
};
/**
* The coordinate operation factory. Will be created only when first needed.
*/
private transient CoordinateOperationFactory opFactory;
/**
* A pool of modified objects created up to date.
*/
private final CanonicalSet pool = new CanonicalSet();
/**
* Creates a wrapper around the specified factory.
*
* @param factory The factory to wrap.
*/
protected TransformedAuthorityFactory(final AuthorityFactory factory) {
super(factory);
}
/**
* Creates a wrapper around the specified factories.
*
* @param crsFactory The {@linkplain CoordinateReferenceSystem coordinate reference system}
* authority factory, or {@code null}.
* @param csFactory The {@linkplain CoordinateSystem coordinate system} authority
* factory, or {@code null}.
* @param datumFactory The {@linkplain Datum datum} authority factory, or {@code null}.
* @param opFactory The {@linkplain CoordinateOperation coordinate operation}
* authority factory, or {@code null}.
*/
protected TransformedAuthorityFactory(final CRSAuthorityFactory crsFactory,
final CSAuthorityFactory csFactory,
final DatumAuthorityFactory datumFactory,
final CoordinateOperationAuthorityFactory opFactory)
{
super(crsFactory, csFactory, datumFactory, opFactory);
}
/**
* Creates a wrappers around the default factories for the specified
* authority. The factories are fetched using {@link ReferencingFactoryFinder}.
*
* @param authority The authority to wraps (example: {@code "EPSG"}). If {@code null},
* then all authority factories must be explicitly specified in the
* set of hints.
* @param userHints An optional set of hints, or {@code null} if none.
* @throws FactoryRegistryException if at least one factory can not be obtained.
*
* @since 2.4
*/
protected TransformedAuthorityFactory(final String authority, final Hints userHints)
throws FactoryRegistryException
{
super(authority, userHints);
}
/**
* Returns the priority for this factory. Priorities are used by
* {@link ReferencingFactoryFinder} for selecting a preferred factory when many are
* found for the same service. The default implementation returns
* {@linkplain #priority priority} + 1
, which implies that
* this adapter has precedence over the wrapped factories. Subclasses should
* override this method if they want a different priority order for this
* instance.
*/
public int getPriority() {
return priority + 1;
}
/**
* Replaces the specified unit, if applicable. This method is invoked
* automatically by the {@link #replace(CoordinateSystem)} method. The
* default implementation returns the unit unchanged.
*
* @param units The units to replace.
* @return The new units, or {@code units} if no change were needed.
* @throws FactoryException if an error occured while creating the new units.
*/
@Override
protected Unit> replace(final Unit> units) throws FactoryException {
return units;
}
/**
* Replaces the specified direction, if applicable. This method is invoked
* automatically by the {@link #replace(CoordinateSystem)} method. The
* default implementation returns the axis direction unchanged.
*
* @param direction The axis direction to replace.
* @return The new direction, or {@code direction} if no change were needed.
* @throws FactoryException if an error occured while creating the new axis direction.
*/
protected AxisDirection replace(final AxisDirection direction) throws FactoryException {
return direction;
}
/**
* Replaces (if needed) the specified axis by a new one. The default
* implementation invokes {@link #replace(Unit)} and
* {@link #replace(AxisDirection)}.
*
* @param axis The coordinate system axis to replace.
* @return The new coordinate system axis, or {@code axis} if no change were needed.
* @throws FactoryException if an error occured while creating the new coordinate system axis.
*/
@Override
protected CoordinateSystemAxis replace(CoordinateSystemAxis axis) throws FactoryException {
final AxisDirection oldDirection = axis.getDirection();
final AxisDirection newDirection = replace(oldDirection);
Unit> oldUnits = axis.getUnit();
final Unit> newUnits = replace(oldUnits);
boolean directionChanged = !oldDirection.equals(newDirection);
if (directionChanged) {
/*
* Check if the direction change implies an axis renaming. For example if the axis
* name was "Southing" and the direction has been changed from SOUTH to NORTH, then
* the axis should be renamed as "Northing".
*/
final String name = axis.getName().getCode();
for (int i=0; i