001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.referencing.factory.epsg;
017:
018: // OpenGIS dependencies
019: import org.opengis.metadata.citation.Citation;
020: import org.opengis.referencing.FactoryException;
021: import org.opengis.referencing.cs.CSAuthorityFactory;
022: import org.opengis.referencing.crs.CRSAuthorityFactory;
023: import org.opengis.referencing.datum.DatumAuthorityFactory;
024: import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
025:
026: // Geotools dependencies
027: import org.geotools.factory.Hints;
028: import org.geotools.factory.GeoTools;
029: import org.geotools.factory.FactoryRegistryException;
030: import org.geotools.factory.FactoryNotFoundException;
031: import org.geotools.referencing.ReferencingFactoryFinder;
032: import org.geotools.referencing.factory.AbstractAuthorityFactory;
033: import org.geotools.referencing.factory.DeferredAuthorityFactory;
034: import org.geotools.referencing.factory.OrderedAxisAuthorityFactory;
035: import org.geotools.metadata.iso.citation.Citations;
036:
037: /**
038: * An EPSG authority factory using (<var>longitude</var>, <var>latitude</var>) axis order.
039: * This factory wraps a {@link ThreadedEpsgFactory} into an {@link OrderedAxisAuthorityFactory}
040: * when first needed.
041: * <p>
042: * Users don't need to create explicitly an instance of this class. Instead, one can get
043: * an instance using the following code:
044: *
045: * <blockquote><pre>
046: * Hints hints = new Hints({@linkplain Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER}, Boolean.TRUE);
047: * CRSAuthorityFactory factory = {@linkplain ReferencingFactoryFinder}.getCRSAuthorityFactory("EPSG", hints);
048: * </pre></blockquote>
049: *
050: * @since 2.3
051: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/LongitudeFirstFactory.java $
052: * @version $Id: LongitudeFirstFactory.java 25931 2007-06-19 20:41:08Z jgarnett $
053: * @author Martin Desruisseaux
054: *
055: * @see OrderedAxisAuthorityFactory
056: * @see Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER
057: * @tutorial http://docs.codehaus.org/display/GEOTOOLS/The+axis+order+issue
058: */
059: public class LongitudeFirstFactory extends DeferredAuthorityFactory
060: implements CRSAuthorityFactory, CSAuthorityFactory,
061: CoordinateOperationAuthorityFactory, DatumAuthorityFactory {
062: /*
063: * Implementation note: in theory the DatumAuthorityFactory interface is useless here, since
064: * "axis order" doesn't make any sense for them. However if we do not register this class for
065: * the DatumAuthorityFactory as well, user will get a FactoryNotFoundException when asking for
066: * a factory with the FORCE_LONGITUDE_FIRST_AXIS_ORDER hint set.
067: */
068:
069: /**
070: * The {@linkplain System#getProperty(String) system property} key for setting the default
071: * {@link Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER FORCE_LONGITUDE_FIRST_AXIS_ORDER} hint value.
072: * This setting can provide a transition path for projects expecting a (<var>longitude</var>,
073: * <var>latitude</var>) axis order on a system-wide level. Application developpers can set the
074: * default value as below:
075: *
076: * <blockquote><pre>
077: * System.setProperty(SYSTEM_DEFAULT_KEY, "true");
078: * </pre></blockquote>
079: *
080: * Note that this system property applies mostly to the default EPSG factory. Most other
081: * factories ({@code "CRS"}, {@code "AUTO"}, <cite>etc.</cite>) don't need this property
082: * since they use (<var>longitude</var>, <var>latitude</var>) axis order by design.
083: *
084: * @see Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER
085: *
086: * @deprecated Moved to {@link GeoTools#FORCE_LONGITUDE_FIRST_AXIS_ORDER}.
087: */
088: public static final String SYSTEM_DEFAULT_KEY = GeoTools.FORCE_LONGITUDE_FIRST_AXIS_ORDER;
089:
090: /**
091: * Creates a default factory. The
092: * {@link Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER FORCE_LONGITUDE_FIRST_AXIS_ORDER}
093: * hint is always set to {@link Boolean#TRUE TRUE}. The
094: * {@link Hints#FORCE_STANDARD_AXIS_DIRECTIONS FORCE_STANDARD_AXIS_DIRECTIONS} and
095: * {@link Hints#FORCE_STANDARD_AXIS_UNITS FORCE_STANDARD_AXIS_UNITS} hints are set
096: * to {@link Boolean#FALSE FALSE} by default. A different value for those two hints
097: * can be specified using the {@linkplain LongitudeFirstFactory(Hints) constructor
098: * below}.
099: */
100: public LongitudeFirstFactory() {
101: this (null);
102: }
103:
104: /**
105: * Creates a factory from the specified set of hints.
106: *
107: * @param userHints An optional set of hints, or {@code null} for the default values.
108: */
109: public LongitudeFirstFactory(final Hints userHints) {
110: super (userHints, ThreadedEpsgFactory.PRIORITY
111: + relativePriority());
112: // See comment in createBackingStore() method body.
113: hints.put(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
114: put(userHints, Hints.FORCE_STANDARD_AXIS_DIRECTIONS);
115: put(userHints, Hints.FORCE_STANDARD_AXIS_UNITS);
116: }
117:
118: /**
119: * Stores a value from the specified hints.
120: */
121: private void put(final Hints userHints, final Hints.Key key) {
122: Object value = null;
123: if (userHints != null) {
124: value = userHints.get(key);
125: }
126: if (value == null) {
127: value = Boolean.FALSE;
128: }
129: hints.put(key, value);
130: }
131:
132: /**
133: * Returns the priority to use relative to the {@link ThreadedEpsgFactory} priority. The default
134: * priority should be lower, except if the <code>{@value #SYSTEM_DEFAULT_KEY}</code> system
135: * property is set to {@code true}.
136: *
137: * @deprecated Not needed anymore since {@link GeoTools#getDefaultHints}.
138: */
139: private static int relativePriority() {
140: try {
141: if (Boolean.getBoolean(SYSTEM_DEFAULT_KEY)) {
142: return +10;
143: }
144: } catch (SecurityException e) {
145: // Fall back on default value.
146: }
147: return -10;
148: }
149:
150: /**
151: * Returns the authority for this EPSG database.
152: * This authority will contains the database version in the {@linkplain Citation#getEdition
153: * edition} attribute, together with the {@linkplain Citation#getEditionDate edition date}.
154: */
155: public Citation getAuthority() {
156: final Citation authority = super .getAuthority();
157: return (authority != null) ? authority : Citations.EPSG;
158: }
159:
160: /**
161: * Returns the factory instance (usually {@link ThreadedEpsgFactory})
162: * to be used as the backing store.
163: *
164: * @throws FactoryException If no suitable factory instance was found.
165: */
166: protected AbstractAuthorityFactory createBackingStore()
167: throws FactoryException {
168: /*
169: * Set the hints for the backing store to fetch. I'm not sure that we should request a
170: * org.geotools.referencing.factory.epsg.ThreadedEpsgFactory implementation; for now we are
171: * making this requirement mostly as a safety in order to get an implementation that is
172: * known to work, but we could relax that in a future version. AbstractAuthorityFactory
173: * is the minimal class required with current OrderedAxisAuthorityFactory API.
174: *
175: * The really important hints are the FORCE_*_AXIS_* handled by this class, which MUST
176: * be set to FALSE. This is especially important for FORCE_LONGITUDE_FIRST_AXIS_ORDER,
177: * which must be set to a different value than the value set by the constructor in order
178: * to prevent LongitudeFirstFactory to fetch itself. The other hints must also be set to
179: * false since forcing axis directions / units is handled by OrderedAxisAuthorityFactory
180: * and we don't want the backing store to interfer with that.
181: */
182: final Hints backingStoreHints;
183: backingStoreHints = new Hints(Hints.CRS_AUTHORITY_FACTORY,
184: ThreadedEpsgFactory.class);
185: backingStoreHints.put(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER,
186: Boolean.FALSE);
187: backingStoreHints.put(Hints.FORCE_STANDARD_AXIS_DIRECTIONS,
188: Boolean.FALSE);
189: backingStoreHints.put(Hints.FORCE_STANDARD_AXIS_UNITS,
190: Boolean.FALSE);
191: final AbstractAuthorityFactory factory;
192: try {
193: factory = (AbstractAuthorityFactory) ReferencingFactoryFinder
194: .getCRSAuthorityFactory("EPSG", backingStoreHints);
195: } catch (FactoryNotFoundException exception) {
196: throw new org.geotools.referencing.factory.FactoryNotFoundException(
197: exception);
198: } catch (FactoryRegistryException exception) {
199: throw new FactoryException(exception);
200: }
201: return new OrderedAxisAuthorityFactory(factory,
202: new Hints(hints), null);
203: }
204: }
|