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;
017:
018: // J2SE dependencies
019: import java.util.Arrays;
020: import java.util.List;
021: import java.util.SortedMap;
022: import java.util.TreeMap;
023:
024: // OpenGIS dependencies
025: import org.opengis.metadata.citation.Citation;
026: import org.opengis.referencing.AuthorityFactory;
027: import org.opengis.referencing.FactoryException;
028: import org.opengis.referencing.NoSuchAuthorityCodeException;
029: import org.opengis.referencing.crs.CRSAuthorityFactory;
030: import org.opengis.referencing.cs.CSAuthorityFactory;
031: import org.opengis.referencing.datum.DatumAuthorityFactory;
032: import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
033:
034: // Geotools dependencies
035: import org.geotools.util.Version;
036: import org.geotools.factory.Hints;
037: import org.geotools.metadata.iso.citation.Citations;
038:
039: /**
040: * Wraps {@linkplain AllAuthoritiesFactory all factories} in a {@code "urn:ogc:def"}
041: * name space. An exemple of complete URN is {@code "urn:ogc:def:crs:EPSG:6.8:4326"}.
042: * <p>
043: * Users don't need to create an instance of this class, since one is automatically
044: * registered for use in {@link org.opengis.referencing.ReferencingFactoryFinder}.
045: *
046: * @since 2.4
047: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/factory/URN_AuthorityFactory.java $
048: * @version $Id: URN_AuthorityFactory.java 29058 2008-02-03 17:47:07Z desruisseaux $
049: * @author Justin Deoliveira
050: * @author Martin Desruisseaux
051: *
052: * @see <A HREF="https://portal.opengeospatial.org/files/?artifact_id=8814">URNs of definitions
053: * in OGC namespace</A>
054: *
055: * @deprecated This class will move in a <code>org.geotools.referencing.factory.<strong>web</strong></code>
056: * package in Geotools 2.5, in order to put together other web-related factories.
057: * Don't use this class directly. You should not need to anyway - use
058: * {@link org.geotools.referencing.ReferencingFactoryFinder} instead, which will
059: * continue to work no matter where this class is located.
060: */
061: public class URN_AuthorityFactory extends AuthorityFactoryAdapter
062: implements CRSAuthorityFactory, CSAuthorityFactory,
063: DatumAuthorityFactory, CoordinateOperationAuthorityFactory {
064: /**
065: * The backing factory. Will be used as a fallback if no object
066: * is available for some specific version of an EPSG database.
067: */
068: private final AllAuthoritiesFactory factory;
069:
070: /**
071: * The authority factories by versions. Factories will be created by
072: * {@link #createVersionedFactory} when first needed.
073: */
074: private final SortedMap/*<Version,AbstractAuthorityFactory>*/byVersions = new TreeMap();
075:
076: /**
077: * The last code processed, or {@code null} if none.
078: */
079: private transient URN_Parser last;
080:
081: /**
082: * Creates a default wrapper.
083: */
084: public URN_AuthorityFactory() {
085: this ((Hints) null);
086: }
087:
088: /**
089: * Creates a wrapper using the specified hints. For strict compliance with OGC definition
090: * of {@code "urn:ogc:def"} namespace, the supplied hints should contains at least the
091: * {@link Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER FORCE_LONGITUDE_FIRST_AXIS_ORDER} hint
092: * with value {@link Boolean#FALSE FALSE}.
093: *
094: * @param userHints The hints to be given to backing factories.
095: */
096: public URN_AuthorityFactory(final Hints userHints) {
097: this (HTTP_AuthorityFactory.getFactory(userHints, "urn"));
098: }
099:
100: /**
101: * Creates a wrapper around the specified factory. The supplied factory is given unchanged
102: * to the {@linkplain AuthorityFactoryAdapter#AuthorityFactoryAdapter(AuthorityFactory)
103: * super class constructor}.
104: */
105: public URN_AuthorityFactory(final AllAuthoritiesFactory factory) {
106: super (factory);
107: this .factory = factory;
108: }
109:
110: /**
111: * Returns the authority, which contains {@code "urn:ogc:def"} and {@code "urn:x-ogc:def"}
112: * identifiers.
113: */
114: public Citation getAuthority() {
115: return Citations.URN_OGC;
116: }
117:
118: /**
119: * Parses the specified code. For performance reason, returns the last result if applicable.
120: *
121: * @param code The URN to parse.
122: * @return parser The parser.
123: * @throws NoSuchAuthorityCodeException if the URN syntax is invalid.
124: */
125: private URN_Parser getParser(final String code)
126: throws NoSuchAuthorityCodeException {
127: /*
128: * Take a local copy of the field in order to protect against changes.
129: * This avoid the need for synchronization (URN_Parsers are immutable,
130: * so it doesn't matter if the 'last' reference is changed concurrently).
131: */
132: URN_Parser parser = last;
133: if (parser == null || !parser.urn.equals(code)) {
134: last = parser = new URN_Parser(code);
135: }
136: return parser;
137: }
138:
139: /**
140: * Returns an object factory for the specified code. This method invokes one of the
141: * <code>get</code><var>Type</var><code>AuthorityFactory</code> methods where
142: * <var>Type</var> is inferred from the code.
143: *
144: * @param code The authority code given to this class.
145: * @return A factory for the specified authority code (never {@code null}).
146: * @throws FactoryException if no suitable factory were found.
147: */
148: protected AuthorityFactory getAuthorityFactory(final String code)
149: throws FactoryException {
150: if (code != null) {
151: return getAuthorityFactory(getParser(code).type.type, code);
152: } else {
153: return super .getAuthorityFactory(code);
154: }
155: }
156:
157: /**
158: * Returns the datum factory to use for the specified URN. If the URN contains a version
159: * string, then this method will try to fetch a factory for that particular version. The
160: * {@link #createVersionedFactory} method may be invoked for that purpose. If no factory
161: * is provided for that specific version, then the
162: * {@linkplain AuthorityFactoryAdapter#getDatumAuthorityFactory default one} is used.
163: *
164: * @param code The URN given to this class.
165: * @return A factory for the specified URN (never {@code null}).
166: * @throws FactoryException if no datum factory is available.
167: */
168: protected DatumAuthorityFactory getDatumAuthorityFactory(
169: final String code) throws FactoryException {
170: if (code != null) {
171: final URN_Parser parser = getParser(code);
172: parser
173: .logWarningIfTypeMismatch(DatumAuthorityFactory.class);
174: final AuthorityFactory factory = getVersionedFactory(parser);
175: if (factory instanceof DatumAuthorityFactory) {
176: return (DatumAuthorityFactory) factory;
177: }
178: }
179: return super .getDatumAuthorityFactory(code);
180: }
181:
182: /**
183: * Returns the coordinate system factory to use for the specified URN. If the URN contains a
184: * version string, then this method will try to fetch a factory for that particular version.
185: * The {@link #createVersionedFactory} method may be invoked for that purpose. If no factory
186: * is provided for that specific version, then the
187: * {@linkplain AuthorityFactoryAdapter#getCSAuthorityFactory default one} is used.
188: *
189: * @param code The URN given to this class.
190: * @return A factory for the specified URN (never {@code null}).
191: * @throws FactoryException if no coordinate system factory is available.
192: */
193: protected CSAuthorityFactory getCSAuthorityFactory(final String code)
194: throws FactoryException {
195: if (code != null) {
196: final URN_Parser parser = getParser(code);
197: parser.logWarningIfTypeMismatch(CSAuthorityFactory.class);
198: final AuthorityFactory factory = getVersionedFactory(parser);
199: if (factory instanceof CSAuthorityFactory) {
200: return (CSAuthorityFactory) factory;
201: }
202: }
203: return super .getCSAuthorityFactory(code);
204: }
205:
206: /**
207: * Returns the coordinate reference system factory to use for the specified URN.
208: * If the URN contains a version string, then this method will try to fetch a factory
209: * for that particular version. The {@link #createVersionedFactory} method may be
210: * invoked for that purpose. If no factory is provided for that specific version, then
211: * the {@linkplain AuthorityFactoryAdapter#getCRSAuthorityFactory default one} is used.
212: *
213: * @param code The URN given to this class.
214: * @return A factory for the specified URN (never {@code null}).
215: * @throws FactoryException if no coordinate reference system factory is available.
216: */
217: protected CRSAuthorityFactory getCRSAuthorityFactory(
218: final String code) throws FactoryException {
219: if (code != null) {
220: final URN_Parser parser = getParser(code);
221: parser.logWarningIfTypeMismatch(CRSAuthorityFactory.class);
222: final AuthorityFactory factory = getVersionedFactory(parser);
223: if (factory instanceof CRSAuthorityFactory) {
224: return (CRSAuthorityFactory) factory;
225: }
226: }
227: return super .getCRSAuthorityFactory(code);
228: }
229:
230: /**
231: * Returns the coordinate operation factory to use for the specified URN. If the URN
232: * contains a version string, then this method will try to fetch a factory for that
233: * particular version. The {@link #createVersionedFactory} method may be invoked for
234: * that purpose. If no factory is provided for that specific version, then the
235: * {@linkplain AuthorityFactoryAdapter#getCoordinateOperationAuthorityFactory default one}
236: * is used.
237: *
238: * @param code The URN given to this class.
239: * @return A factory for the specified URN (never {@code null}).
240: * @throws FactoryException if no coordinate operation factory is available.
241: */
242: protected CoordinateOperationAuthorityFactory getCoordinateOperationAuthorityFactory(
243: final String code) throws FactoryException {
244: if (code != null) {
245: final URN_Parser parser = getParser(code);
246: parser
247: .logWarningIfTypeMismatch(CoordinateOperationAuthorityFactory.class);
248: final AuthorityFactory factory = getVersionedFactory(parser);
249: if (factory instanceof CoordinateOperationAuthorityFactory) {
250: return (CoordinateOperationAuthorityFactory) factory;
251: }
252: }
253: return super .getCoordinateOperationAuthorityFactory(code);
254: }
255:
256: /**
257: * Returns an authority factory for the specified version, or {@code null} if none.
258: * This method invokes {@link #createVersionedFactory} the first time it is invoked
259: * for a given version and cache the factory.
260: *
261: * @throws FactoryException if an error occured while creating the factory.
262: */
263: private AuthorityFactory getVersionedFactory(final URN_Parser parser)
264: throws FactoryException {
265: final Version version = parser.version;
266: if (version == null) {
267: return null;
268: }
269: AuthorityFactory factory;
270: synchronized (byVersions) {
271: factory = (AuthorityFactory) byVersions.get(version);
272: if (factory == null) {
273: factory = createVersionedFactory(version);
274: if (factory != null) {
275: byVersions.put(version, factory);
276: }
277: }
278: }
279: return factory;
280: }
281:
282: /**
283: * Invoked when a factory is requested for a specific version. This method should create
284: * a factory for the exact version specified by the argument, or return {@code null} if
285: * no such factory is available. In the later case, this class will fallback on the factory
286: * specified at {@linkplain #URN_AuthorityFactory(AuthorityFactory, String, Citation)
287: * construction time}.
288: *
289: * @param version The version for the factory to create.
290: * @return The factory, of {@code null} if there is none for the specified version.
291: * @throws FactoryException if an error occured while creating the factory.
292: */
293: protected AuthorityFactory createVersionedFactory(
294: final Version version) throws FactoryException {
295: final Hints hints = new Hints(factory.getImplementationHints());
296: hints.put(Hints.VERSION, version);
297: final List factories = Arrays.asList(new AuthorityFactory[] {
298: new AllAuthoritiesFactory(hints), factory });
299: return FallbackAuthorityFactory.create(factories);
300: }
301:
302: /**
303: * Removes the URN base ({@code "urn:ogc:def"}) from the specified code
304: * before to pass it to the wrapped factories.
305: *
306: * @param code The code given to this factory.
307: * @return The code to give to the underlying factories.
308: * @throws FactoryException if the code can't be converted.
309: */
310: protected String toBackingFactoryCode(final String code)
311: throws FactoryException {
312: return getParser(code).getAuthorityCode();
313: }
314: }
|