001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-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.wms;
017:
018: // J2SE dependencies and extensions
019: import java.util.Map;
020: import java.util.HashMap;
021: import java.util.TreeMap;
022: import java.util.Iterator;
023: import java.util.Set;
024: import java.util.LinkedHashSet;
025:
026: // OpenGIS dependencies
027: import org.opengis.metadata.Identifier;
028: import org.opengis.util.InternationalString;
029: import org.opengis.metadata.citation.Citation;
030: import org.opengis.referencing.datum.Ellipsoid;
031: import org.opengis.referencing.datum.GeodeticDatum;
032: import org.opengis.referencing.IdentifiedObject;
033: import org.opengis.referencing.FactoryException;
034: import org.opengis.referencing.NoSuchAuthorityCodeException;
035: import org.opengis.referencing.crs.CoordinateReferenceSystem;
036: import org.opengis.referencing.crs.CRSAuthorityFactory;
037:
038: // Geotools dependencies
039: import org.geotools.factory.Hints;
040: import org.geotools.util.SimpleInternationalString;
041: import org.geotools.metadata.iso.citation.Citations;
042: import org.geotools.referencing.NamedIdentifier;
043: import org.geotools.referencing.cs.DefaultEllipsoidalCS;
044: import org.geotools.referencing.datum.DefaultEllipsoid;
045: import org.geotools.referencing.datum.DefaultPrimeMeridian;
046: import org.geotools.referencing.factory.DirectAuthorityFactory;
047:
048: /**
049: * The factory for {@linkplain CoordinateReferenceSystem coordinate reference systems}
050: * in the {@code CRS} space.
051: *
052: * @since 2.2
053: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/factory/wms/WebCRSFactory.java $
054: * @version $Id: WebCRSFactory.java 27544 2007-10-18 19:16:40Z desruisseaux $
055: * @author Martin Desruisseaux
056: *
057: * @deprecated This class will move in a <code>org.geotools.referencing.factory.<strong>web</strong></code>
058: * package in Geotools 2.5, in order to put together other web-related factories defined
059: * outside the WMS specification. Don't use this class directly. You should not need to
060: * anyway - use {@link org.geotools.referencing.ReferencingFactoryFinder} instead, which
061: * will continue to work no matter where this class is located.
062: */
063: public class WebCRSFactory extends DirectAuthorityFactory implements
064: CRSAuthorityFactory {
065: /**
066: * An optional prefix put in front of code. For example a code may be {@code "CRS84"}
067: * instead of a plain {@code "84"}. This is usefull in order to understand URN syntax
068: * like {@code "urn:ogc:def:crs:OGC:1.3:CRS84"}. Must be uppercase for this implementation
069: * (but parsing will be case-insensitive).
070: */
071: private static final String PREFIX = "CRS";
072:
073: /**
074: * The map of pre-defined CRS.
075: */
076: private final Map/*<Integer,CoordinateReferenceSystem>*/crsMap = new TreeMap();
077:
078: /**
079: * Constructs a default factory for the {@code CRS} authority.
080: */
081: public WebCRSFactory() {
082: this (null);
083: }
084:
085: /**
086: * Constructs a factory for the {@code CRS} authority using the specified hints.
087: */
088: public WebCRSFactory(final Hints hints) {
089: super (hints, NORMAL_PRIORITY);
090: }
091:
092: /**
093: * Ensures that {@link #crsMap} is initialized. This method can't be invoked in the constructor
094: * because the constructor is invoked while {@code FactoryFinder.scanForPlugins()} is still
095: * running. Because the {@link #add} method uses factories for creating CRS objects, invoking
096: * this method during {@code FactoryFinder.scanForPlugins()} execution may result in unexpected
097: * behavior, like GEOT-935.
098: */
099: private synchronized void ensureInitialized()
100: throws FactoryException {
101: if (crsMap.isEmpty()) {
102: add(84, "WGS84", DefaultEllipsoid.WGS84);
103: add(83, "NAD83", DefaultEllipsoid.GRS80);
104: add(27, "NAD27", DefaultEllipsoid.CLARKE_1866);
105: }
106: }
107:
108: /**
109: * Adds a geographic CRS from the specified parameters.
110: *
111: * @param code The CRS code.
112: * @param name The CRS and datum name.
113: * @param ellipsoid The ellipsoid.
114: *
115: * @throws FactoryException if factories failed to creates the CRS.
116: */
117: private void add(final int code, final String name,
118: final Ellipsoid ellipsoid) throws FactoryException {
119: assert Thread.holdsLock(this );
120: final Map properties = new HashMap();
121: final Citation authority = getAuthority();
122: final String text = String.valueOf(code);
123: properties.put(IdentifiedObject.NAME_KEY, name);
124: properties.put(Identifier.AUTHORITY_KEY, authority);
125: final GeodeticDatum datum = factories.getDatumFactory()
126: .createGeodeticDatum(properties, ellipsoid,
127: DefaultPrimeMeridian.GREENWICH);
128:
129: properties
130: .put(IdentifiedObject.IDENTIFIERS_KEY,
131: new NamedIdentifier[] {
132: new NamedIdentifier(authority, text),
133: new NamedIdentifier(authority, PREFIX
134: + text) });
135: final CoordinateReferenceSystem crs = factories.getCRSFactory()
136: .createGeographicCRS(properties, datum,
137: DefaultEllipsoidalCS.GEODETIC_2D);
138: if (crsMap.put(new Integer(code), crs) != null) {
139: throw new IllegalArgumentException(text);
140: }
141: }
142:
143: /**
144: * Returns the authority for this factory, which is {@link Citations#CRS CRS}.
145: */
146: public Citation getAuthority() {
147: return Citations.CRS;
148: }
149:
150: /**
151: * Provides a complete set of the known codes provided by this authority. The returned set
152: * contains only numeric identifiers like {@code "84"}, {@code "27"}, <cite>etc</cite>.
153: * The authority name ({@code "CRS"}) is not included. This is consistent with the
154: * {@linkplain org.geotools.referencing.factory.epsg.DirectEpsgFactory#getAuthorityCodes
155: * codes returned by the EPSG factory} and avoid duplication, since the authority is the
156: * same for every codes returned by this factory. It also make it easier for clients to
157: * prepend whatever authority name they wish, as for example in the
158: * {@linkplain org.geotools.referencing.factory.AllAuthoritiesFactory#getAuthorityCodes
159: * all authorities factory}.
160: */
161: public Set getAuthorityCodes(final Class type)
162: throws FactoryException {
163: ensureInitialized();
164: final Set set = new LinkedHashSet();
165: for (final Iterator it = crsMap.entrySet().iterator(); it
166: .hasNext();) {
167: final Map.Entry entry = (Map.Entry) it.next();
168: final CoordinateReferenceSystem crs = (CoordinateReferenceSystem) entry
169: .getValue();
170: if (type.isAssignableFrom(crs.getClass())) {
171: final Integer code = (Integer) entry.getKey();
172: set.add(String.valueOf(code));
173: }
174: }
175: return set;
176: }
177:
178: /**
179: * Returns the CRS name for the given code.
180: */
181: public InternationalString getDescriptionText(final String code)
182: throws FactoryException {
183: return new SimpleInternationalString(createObject(code)
184: .getName().getCode());
185: }
186:
187: /**
188: * Creates an object from the specified code. The default implementation delegates to
189: * <code>{@linkplain #createCoordinateReferenceSystem createCoordinateReferenceSystem}(code)</code>.
190: */
191: public IdentifiedObject createObject(final String code)
192: throws FactoryException {
193: return createCoordinateReferenceSystem(code);
194: }
195:
196: /**
197: * Creates a coordinate reference system from the specified code.
198: */
199: public CoordinateReferenceSystem createCoordinateReferenceSystem(
200: final String code) throws FactoryException {
201: String c = trimAuthority(code).toUpperCase();
202: if (c.startsWith(PREFIX)) {
203: c = c.substring(PREFIX.length());
204: }
205: final int i;
206: try {
207: i = Integer.parseInt(c);
208: } catch (NumberFormatException exception) {
209: // If a number can't be parsed, then this is an invalid authority code.
210: NoSuchAuthorityCodeException e = noSuchAuthorityCode(
211: CoordinateReferenceSystem.class, code);
212: e.initCause(exception);
213: throw e;
214: }
215: ensureInitialized();
216: final CoordinateReferenceSystem crs = (CoordinateReferenceSystem) crsMap
217: .get(new Integer(i));
218: if (crs != null) {
219: return crs;
220: }
221: throw noSuchAuthorityCode(CoordinateReferenceSystem.class, code);
222: }
223: }
|