001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2007, GeoTools Project Managment Committee (PMC)
005: * (C) 2005, Institut de Recherche pour le D�veloppement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.referencing.factory;
018:
019: // J2SE dependencies
020: import java.util.*;
021: import javax.units.Unit;
022:
023: // OpenGIS dependencies
024: import org.opengis.referencing.*;
025: import org.opengis.referencing.cs.*;
026: import org.opengis.referencing.crs.*;
027: import org.opengis.referencing.datum.*;
028: import org.opengis.referencing.operation.*;
029: import org.opengis.util.InternationalString;
030: import org.opengis.metadata.citation.Citation;
031:
032: // Geotools dependencies
033: import org.geotools.factory.Hints;
034: import org.geotools.factory.Factory;
035: import org.geotools.factory.FactoryRegistryException;
036: import org.geotools.metadata.iso.citation.Citations;
037: import org.geotools.util.GenericName;
038: import org.geotools.resources.i18n.ErrorKeys;
039: import org.geotools.resources.i18n.Errors;
040: import org.geotools.resources.i18n.Vocabulary;
041: import org.geotools.resources.i18n.VocabularyKeys;
042:
043: /**
044: * An authority factory that delegates the object creation to an other factory determined from the
045: * authority name in the code. This factory requires that every codes given to a {@code createFoo}
046: * method are prefixed by the authority name, for example {@code "EPSG:4326"}. This is different
047: * from using a factory from a known authority, in which case the authority part was optional (for
048: * example when using the {@linkplain org.geotools.referencing.factory.epsg EPSG authority factory},
049: * the {@code "EPSG:"} part in {@code "EPSG:4326"} is optional).
050: * <p>
051: * This class parses the authority name and delegates the work the corresponding factory. For
052: * example if any {@code createFoo(...)} method in this class is invoked with a code starting
053: * by {@code "EPSG:"}, then this class delegates the object creation to one of the authority
054: * factories provided to the constructor.
055: * <p>
056: * This class is not registered in {@link ReferencingFactoryFinder}, because it is not a real
057: * authority factory. There is not a single authority name associated to this factory, but rather
058: * a set of names determined from all available authority factories.
059: *
060: * @since 2.4
061: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/factory/ManyAuthoritiesFactory.java $
062: * @version $Id: ManyAuthoritiesFactory.java 29058 2008-02-03 17:47:07Z desruisseaux $
063: * @author Martin Desruisseaux
064: */
065: public class ManyAuthoritiesFactory extends AuthorityFactoryAdapter
066: implements CRSAuthorityFactory, CSAuthorityFactory,
067: DatumAuthorityFactory, CoordinateOperationAuthorityFactory {
068: /**
069: * The types to be recognized for the {@code factories} argument in
070: * constructors. Must be consistent with the types expected by the
071: * {@link AllAuthoritiesFactory#fromFactoryRegistry(String, Class)} method.
072: */
073: private static final Class[] FACTORY_TYPES = new Class[] {
074: CRSAuthorityFactory.class, DatumAuthorityFactory.class,
075: CSAuthorityFactory.class,
076: CoordinateOperationAuthorityFactory.class };
077:
078: /**
079: * The types created by {@link #FACTORY_TYPES}. For each type {@code OBJECT_TYPES[i]},
080: * the factory to be used must be {@code FACTORY_TYPES[i]}.
081: */
082: private static final Class[] OBJECT_TYPES = new Class[] {
083: CoordinateReferenceSystem.class, Datum.class,
084: CoordinateSystem.class, CoordinateOperation.class };
085:
086: /**
087: * The set of user-specified factories, or {@code null} if none.
088: * This field should be modified by {@link #setFactories} only.
089: */
090: private Collection/*<AuthorityFactory>*/factories;
091:
092: /**
093: * The separator between the authority name and the code.
094: *
095: * @deprecated Remove this field after we removed the deprecated constructor.
096: */
097: private final char separator;
098:
099: /**
100: * Guard against infinite recursivity in {@link #getAuthorityCodes}.
101: */
102: private final ThreadLocal/*<Boolean>*/inProgress = new ThreadLocal();
103:
104: /**
105: * Creates a new factory using the specified hints.
106: *
107: * @param userHints An optional set of hints, or {@code null} if none.
108: *
109: * @deprecated Use {@link #ManyAuthoritiesFactory(Collection)}.
110: */
111: public ManyAuthoritiesFactory(final Hints userHints) {
112: this (userHints, null);
113: }
114:
115: /**
116: * Creates a new factory using the specified set of user factories. Any call to a
117: * {@code createFoo(code)} method will scan the supplied factories in their iteration
118: * order. The first factory implementing the appropriate interface and having the expected
119: * {@linkplain AuthorityFactory#getAuthority authority name} will be used.
120: * <p>
121: * If the {@code factories} collection contains more than one factory for the same authority
122: * and interface, then all additional factories will be {@linkplain FallbackAuthorityFactory
123: * fallbacks}, to be tried in iteration order only if the first acceptable factory failed to
124: * create the requested object.
125: *
126: * @param factories A set of user-specified factories to try before to delegate
127: * to {@link GeometryFactoryFinder}.
128: */
129: public ManyAuthoritiesFactory(
130: final Collection/*<? extends AuthorityFactory>*/factories) {
131: this (null, factories, (char) 0);
132: }
133:
134: /**
135: * Creates a new factory using the specified hints and a set of user factories.
136: *
137: * @param userHints An optional set of hints, or {@code null} if none.
138: * @param factories A set of user-specified factories to try before to delegate
139: * to {@link ReferencingFactoryFinder}.
140: *
141: * @deprecated Use {@link #ManyAuthoritiesFactory(Collection)}.
142: */
143: public ManyAuthoritiesFactory(final Hints userHints,
144: final Collection/*<? extends AuthorityFactory>*/factories) {
145: this (userHints, factories, (char) 0);
146: }
147:
148: /**
149: * Creates a new factory using the specified hints, user factories and name
150: * separator.
151: *
152: * @deprecated Override the {@link #getSeparator} method instead.
153: */
154: ManyAuthoritiesFactory(final Hints userHints,
155: final Collection/*<? extends AuthorityFactory>*/factories,
156: final char separator) {
157: super (NORMAL_PRIORITY);
158: this .separator = separator;
159: if (factories != null && !factories.isEmpty()) {
160: for (final Iterator it = factories.iterator(); it.hasNext();) {
161: final Object factory = it.next();
162: if (factory instanceof Factory) {
163: hints.putAll(((Factory) factory)
164: .getImplementationHints());
165: }
166: }
167: this .factories = createFallbacks(factories);
168: }
169: }
170:
171: /**
172: * Returns the factories. This method should not be public since it returns directly the
173: * internal instance. This method is to be overriden by {@link AllAuthoritiesFactory} only.
174: */
175: Collection/*<AuthorityFactory>*/getFactories() {
176: return factories;
177: }
178:
179: /**
180: * Sets the factories. This method is invoked by the {@link AllAuthoritiesFactory} subclass
181: * only. No one else should invoke this method, since factories should be immutable.
182: */
183: final void setFactories(
184: final Collection/*<AuthorityFactory>*/factories) {
185: assert Thread.holdsLock(this );
186: this .factories = createFallbacks(factories);
187: }
188:
189: /**
190: * If more than one factory is found for the same authority and interface,
191: * then wraps them as a chain of {@link FallbackAuthorityFactory}.
192: */
193: private static Collection/*<AuthorityFactory>*/createFallbacks(
194: final Collection/*<? extends AuthorityFactory>*/factories) {
195: /*
196: * 'authorities' Will contains the set of all authorities found without duplicate values
197: * in the sense of Citations.identifierMatches(...). 'factoriesByAuthority' will contains
198: * the collection of factories for each authority.
199: */
200: int authorityCount = 0;
201: final Citation[] authorities = new Citation[factories.size()];
202: final List[] factoriesByAuthority = new List[authorities.length];
203: for (final Iterator it = factories.iterator(); it.hasNext();) {
204: final AuthorityFactory factory = (AuthorityFactory) it
205: .next();
206: /*
207: * Check if the authority has already been meet previously. If the authority is found
208: * then 'authorityIndex' is set to its index. Otherwise the new authority is added to
209: * the 'authorities' list.
210: */
211: Citation authority = factory.getAuthority();
212: int authorityIndex;
213: for (authorityIndex = 0; authorityIndex < authorityCount; authorityIndex++) {
214: final Citation candidate = authorities[authorityIndex];
215: if (Citations.identifierMatches(candidate, authority)) {
216: authority = candidate;
217: break;
218: }
219: }
220: final List/*<AuthorityFactory>*/list;
221: if (authorityIndex == authorityCount) {
222: authorities[authorityCount++] = authority;
223: factoriesByAuthority[authorityIndex] = list = new ArrayList(
224: 4);
225: } else {
226: list = factoriesByAuthority[authorityIndex];
227: }
228: if (!list.contains(factory)) {
229: list.add(factory);
230: }
231: }
232: /*
233: * For each authority, chains the factories into a FallbackAuthorityFactory object.
234: */
235: final ArrayList/*<AuthorityFactory>*/result = new ArrayList();
236: final List/*<AuthorityFactory>*/buffer = new ArrayList(4);
237: for (int i = 0; i < authorityCount; i++) {
238: final Collection list = factoriesByAuthority[i];
239: while (!list.isEmpty()) {
240: AuthorityFactory primary = null;
241: boolean needOtherChains = false;
242: for (final Iterator it = list.iterator(); it.hasNext();) {
243: final AuthorityFactory fallback = (AuthorityFactory) it
244: .next();
245: if (primary == null) {
246: primary = fallback;
247: } else if (!FallbackAuthorityFactory.chainable(
248: primary, fallback)) {
249: needOtherChains = true;
250: continue;
251: }
252: buffer.add(fallback);
253: if (!needOtherChains) {
254: it.remove();
255: }
256: }
257: result.add(FallbackAuthorityFactory.create(buffer));
258: buffer.clear();
259: }
260: }
261: result.trimToSize();
262: return result;
263: }
264:
265: /**
266: * If this factory is a wrapper for the specified factory that do not add any additional
267: * {@linkplain #getAuthorityCodes authority codes}, returns {@code true}. This method is
268: * for {@link FallbackAuthorityFactory} internal use only.
269: */
270: //@Override
271: boolean sameAuthorityCodes(final AuthorityFactory factory) {
272: // We don't want to inherit AuthorityFactoryAdapter implementation here.
273: return factory == this ;
274: }
275:
276: /**
277: * Returns the character separator for the specified code. The default implementation returns
278: * the {@linkplain GenericName#DEFAULT_SEPARATOR default name separator} {@code ':'}, except
279: * if the code looks like a URL (e.g. {@code "http://www.opengis.net/"}), in which case this
280: * method returns {@code '/'}.
281: * <p>
282: * In the current implementation, "looks like a URL" means that the first
283: * non-{@linkplain Character#isLetterOrDigit(char) aplhanumeric} characters
284: * are {@code "://"}. But this heuristic rule may change in future implementations.
285: */
286: protected char getSeparator(String code) {
287: if (separator != 0) {
288: // Remove this block after we removed the deprecated separator field.
289: return separator;
290: }
291: code = code.trim();
292: final int length = code.length();
293: for (int i = 0; i < length; i++) {
294: if (!Character.isLetterOrDigit(code.charAt(i))) {
295: if (code.regionMatches(i, "://", 0, 3)) {
296: return '/';
297: }
298: break;
299: }
300: }
301: return GenericName.DEFAULT_SEPARATOR;
302: }
303:
304: /**
305: * Returns {@code true} if the specified code can be splitted in a (<cite>authority</cite>,
306: * <cite>code</cite>) pair at the specified index. The default implementation returns
307: * {@code true} if the first non-whitespace character on the left and right side are
308: * valid Java identifiers.
309: * <p>
310: * The purpose of this method is to avoid considering the {@code "//"} part in
311: * {@code "http://www.opengis.net/gml/srs/epsg.xml"} as separators. In case of
312: * failure to parse the code, this restriction will produce and error message
313: * like "<cite>Unknown <code>http://www.opengis.net</code> authority</cite>"
314: * instead of "<cite>Unknown <code>http:</code> authority</cite>".
315: * <p>
316: * We may consider to turn this method into a protected one if the users need to override it.
317: */
318: private static boolean canSeparateAt(final String code,
319: final int index) {
320: char c;
321: int i = index;
322: do {
323: if (--i < 0) {
324: return false;
325: }
326: c = code.charAt(i);
327: } while (Character.isWhitespace(c));
328: if (!Character.isJavaIdentifierPart(c)) {
329: return false;
330: }
331: final int length = code.length();
332: i = index;
333: do {
334: if (++i >= length) {
335: return false;
336: }
337: c = code.charAt(i);
338: } while (Character.isWhitespace(c));
339: return Character.isJavaIdentifierPart(c);
340: }
341:
342: /**
343: * Returns the vendor responsible for creating this factory implementation.
344: * The default implementation returns {@linkplain Citations#GEOTOOLS Geotools}.
345: */
346: public Citation getVendor() {
347: return Citations.GEOTOOLS;
348: }
349:
350: /**
351: * Returns the organization or party responsible for definition and maintenance of the
352: * database. The default implementation returns a citation with title "All".
353: */
354: public Citation getAuthority() {
355: return ALL;
356: }
357:
358: /**
359: * Returns the authority names of every factories given at construction time.
360: */
361: public Set/*<String>*/getAuthorityNames() {
362: final Set names = new HashSet();
363: final Collection/*<AuthorityFactory>*/factories = getFactories();
364: if (factories != null) {
365: for (final Iterator it = factories.iterator(); it.hasNext();) {
366: final AuthorityFactory factory = (AuthorityFactory) it
367: .next();
368: names.addAll(factory.getAuthority().getIdentifiers());
369: }
370: }
371: return names;
372: }
373:
374: /**
375: * Returns a description of the underlying backing store, or {@code null} if unknow.
376: *
377: * @throws FactoryException if a failure occured while fetching the engine description.
378: */
379: public String getBackingStoreDescription() throws FactoryException {
380: // We have no authority code, so we can't pick a particular factory.
381: return null;
382: }
383:
384: /**
385: * Returns the direct dependencies. Current implementation returns the internal structure
386: * because we know that this package will not modifies it. But if the method become public,
387: * we will need to returns a unmodifiable view.
388: */
389: //@Override
390: Collection/*<?>*/dependencies() {
391: return getFactories();
392: }
393:
394: /**
395: * Returns {@code true} if the specified factory should be excluded from the search.
396: * We exclude adapters around {@link AllAuthoritiesFactory}. This code actually aims
397: * to exclude {@link URN_AuthorityFactory} and similar adapters around all factories,
398: * since it leads to duplicated search and innacurate identifier to be returned by
399: * {@link #findIdentifier}.
400: */
401: private static boolean exclude(final AuthorityFactory factory) {
402: if (ManyAuthoritiesFactory.class.isInstance(factory)) {
403: return true;
404: }
405: if (factory instanceof AuthorityFactoryAdapter) {
406: final AuthorityFactoryAdapter adapter = (AuthorityFactoryAdapter) factory;
407: return exclude(adapter.crsFactory)
408: || exclude(adapter.csFactory)
409: || exclude(adapter.datumFactory)
410: || exclude(adapter.operationFactory);
411: }
412: return false;
413: }
414:
415: /**
416: * Same as {@link #fromFactoryRegistry(String, Class)}, but returns every factories
417: * that fit the given type. The factories are added to the specified set.
418: */
419: final void fromFactoryRegistry(final String authority,
420: final Class/*<? extends AuthorityFactory>*/type,
421: final Set/*<AuthorityFactory>*/addTo) {
422: for (int i = 0; i < OBJECT_TYPES.length; i++) {
423: if (OBJECT_TYPES[i].isAssignableFrom(type)) {
424: final AuthorityFactory factory;
425: try {
426: factory = fromFactoryRegistry(authority,
427: FACTORY_TYPES[i]);
428: } catch (FactoryRegistryException e) {
429: // No factory for the given authority. It may be normal.
430: continue;
431: }
432: if (!exclude(factory)) {
433: addTo.add(factory);
434: }
435: }
436: }
437: }
438:
439: /**
440: * Returns a factory for the specified authority, or {@code null} if none.
441: * To be overriden by {@link AllAuthoritiesFactory} in order to search among
442: * factories registered on a system-wide basis.
443: *
444: * @param authority The authority to query.
445: * @param type The interface to be implemented.
446: * @return The factory.
447: * @throws FactoryRegistryException if there is no factory registered for the supplied
448: * authority and hints.
449: */
450: AuthorityFactory fromFactoryRegistry(final String authority,
451: final Class/*<? extends AuthorityFactory>*/type)
452: throws FactoryRegistryException {
453: return null;
454: }
455:
456: /**
457: * Searchs for a factory of the given type. This method first search in user-supplied
458: * factories. If no user factory is found, then this method request for a factory using
459: * {@link ReferencingFactoryFinder}. The authority name is inferred from the specified code.
460: *
461: * @param type The interface to be implemented.
462: * @param code The code of the object to create.
463: * @return The factory.
464: * @throws NoSuchAuthorityCodeException if no suitable factory were found.
465: */
466: //@Override
467: final AuthorityFactory getAuthorityFactory(
468: final Class/*<T extends AuthorityFactory>*/type,
469: final String code) throws NoSuchAuthorityCodeException {
470: ensureNonNull("code", code);
471: String authority = null;
472: FactoryRegistryException cause = null;
473: final Collection/*<AuthorityFactory>*/factories = getFactories();
474: final char separator = getSeparator(code);
475: for (int split = code.lastIndexOf(separator); split >= 0; split = code
476: .lastIndexOf(separator, split - 1)) {
477: if (!canSeparateAt(code, split)) {
478: continue;
479: }
480: /*
481: * Try all possible authority names, begining with the most specific ones.
482: * For example if the code is "urn:ogc:def:crs:EPSG:6.8:4326", then we will
483: * try "urn:ogc:def:crs:EPSG:6.8" first, "urn:ogc:def:crs:EPSG" next, etc.
484: * until a suitable factory is found (searching into user-supplied factories
485: * first).
486: */
487: authority = code.substring(0, split).trim();
488: if (factories != null) {
489: for (final Iterator it = factories.iterator(); it
490: .hasNext();) {
491: final AuthorityFactory factory = (AuthorityFactory) it
492: .next();
493: if (type.isAssignableFrom(factory.getClass())) {
494: if (Citations.identifierMatches(factory
495: .getAuthority(), authority)) {
496: return factory;
497: }
498: }
499: }
500: }
501: /*
502: * No suitable user-supplied factory. Now query FactoryFinder.
503: */
504: final AuthorityFactory factory;
505: try {
506: factory = fromFactoryRegistry(authority, type);
507: } catch (FactoryRegistryException exception) {
508: cause = exception;
509: continue;
510: }
511: if (factory != null) {
512: return /*type.cast*/(factory);
513: // TODO: uncomment when we will be allowed to compile for J2SE 1.5.
514: }
515: }
516: /*
517: * No factory found. Creates an error message from the most global authority name
518: * (for example "urn" if the code was "urn:ogc:def:crs:EPSG:6.8:4326") and the
519: * corresponding cause. Both the authority and cause may be null if the code didn't
520: * had any authority part.
521: */
522: throw noSuchAuthority(code, authority, cause);
523: }
524:
525: /**
526: * Formats the exception to be throw when the user asked for a code from an unknown authority.
527: *
528: * @param code The code with an unknown authority.
529: * @param authority The authority, or {@code null} if none.
530: * @param cause The cause for the exception to be formatted, or {@code null} if none.
531: * @return The formatted exception to be throw.
532: */
533: private NoSuchAuthorityCodeException noSuchAuthority(
534: final String code, String authority,
535: final FactoryRegistryException cause) {
536: final String message;
537: if (authority == null) {
538: authority = Vocabulary.format(VocabularyKeys.UNKNOW);
539: message = Errors.format(ErrorKeys.MISSING_AUTHORITY_$1,
540: code);
541: } else {
542: message = Errors.format(ErrorKeys.UNKNOW_AUTHORITY_$1,
543: authority);
544: }
545: final NoSuchAuthorityCodeException exception;
546: exception = new NoSuchAuthorityCodeException(message,
547: authority, code);
548: exception.initCause(cause);
549: return exception;
550: }
551:
552: /**
553: * Returns a generic object authority factory for the specified {@code "AUTHORITY:NUMBER"}
554: * code.
555: *
556: * @param code The code to parse.
557: * @return The authority factory.
558: * @throws NoSuchAuthorityCodeException if no authority name has been found.
559: */
560: //@Override
561: protected AuthorityFactory getAuthorityFactory(final String code)
562: throws NoSuchAuthorityCodeException {
563: return getAuthorityFactory(AuthorityFactory.class, code);
564: }
565:
566: /**
567: * Returns the datum authority factory for the specified {@code "AUTHORITY:NUMBER"} code.
568: *
569: * @param code The code to parse.
570: * @return The authority factory.
571: * @throws NoSuchAuthorityCodeException if no authority name has been found.
572: */
573: //@Override
574: protected DatumAuthorityFactory getDatumAuthorityFactory(
575: final String code) throws NoSuchAuthorityCodeException {
576: return (DatumAuthorityFactory) // TODO: remove cast with J2SE 1.5.
577: getAuthorityFactory(DatumAuthorityFactory.class, code);
578: }
579:
580: /**
581: * Returns the CS authority factory for the specified {@code "AUTHORITY:NUMBER"} code.
582: *
583: * @param code The code to parse.
584: * @return The authority factory.
585: * @throws NoSuchAuthorityCodeException if no authority name has been found.
586: */
587: //@Override
588: protected CSAuthorityFactory getCSAuthorityFactory(final String code)
589: throws NoSuchAuthorityCodeException {
590: return (CSAuthorityFactory) // TODO: remove cast with J2SE 1.5.
591: getAuthorityFactory(CSAuthorityFactory.class, code);
592: }
593:
594: /**
595: * Returns the CRS authority factory for the specified {@code "AUTHORITY:NUMBER"} code.
596: *
597: * @param code The code to parse.
598: * @return The authority factory.
599: * @throws NoSuchAuthorityCodeException if no authority name has been found.
600: */
601: //@Override
602: protected CRSAuthorityFactory getCRSAuthorityFactory(
603: final String code) throws NoSuchAuthorityCodeException {
604: return (CRSAuthorityFactory) // TODO: remove cast with J2SE 1.5.
605: getAuthorityFactory(CRSAuthorityFactory.class, code);
606: }
607:
608: /**
609: * Returns the operation authority factory for the specified {@code "AUTHORITY:NUMBER"} code.
610: *
611: * @param code The code to parse.
612: * @return The authority factory.
613: * @throws NoSuchAuthorityCodeException if no authority name has been found.
614: */
615: //@Override
616: protected CoordinateOperationAuthorityFactory getCoordinateOperationAuthorityFactory(
617: final String code) throws NoSuchAuthorityCodeException {
618: return (CoordinateOperationAuthorityFactory) // TODO: remove cast with J2SE 1.5.
619: getAuthorityFactory(CoordinateOperationAuthorityFactory.class,
620: code);
621: }
622:
623: /**
624: * Returns the set of authority codes of the given type.
625: *
626: * @param type The spatial reference objects type (may be {@code IdentifiedObject.class}).
627: * @return The set of authority codes for spatial reference objects of the given type.
628: * If this factory doesn't contains any object of the given type, then this method
629: * returns an {@linkplain java.util.Collections#EMPTY_SET empty set}.
630: * @throws FactoryException if access to the underlying database failed.
631: */
632: public Set/*<String>*/getAuthorityCodes(final Class type)
633: throws FactoryException {
634: if (Boolean.TRUE.equals(inProgress.get())) {
635: /*
636: * 'getAuthorityCodes' is invoking itself (indirectly). Returns an empty set in order
637: * to avoid infinite recursivity. Note that the end result (the output of the caller)
638: * will usually not be empty.
639: */
640: return Collections.EMPTY_SET;
641: }
642: final Set/*<String>*/codes = new LinkedHashSet();
643: final Set/*<AuthorityFactory>*/done = new HashSet();
644: done.add(this ); // Safety for avoiding recursive calls.
645: inProgress.set(Boolean.TRUE);
646: try {
647: for (final Iterator it = getAuthorityNames().iterator(); it
648: .hasNext();) {
649: final String authority = ((String) it.next()).trim();
650: final char separator = getSeparator(authority);
651: /*
652: * Prepares a buffer with the "AUTHORITY:" part in "AUTHORITY:NUMBER".
653: * We will reuse this buffer in order to prefix the authority name in
654: * front of every codes.
655: */
656: final StringBuffer code = new StringBuffer(authority);
657: int codeBase = code.length();
658: if (codeBase != 0
659: && code.charAt(codeBase - 1) != separator) {
660: code.append(separator);
661: codeBase = code.length();
662: }
663: code.append("all");
664: final String dummyCode = code.toString();
665: /*
666: * Now scan over all factories. We will process a factory only if this particular
667: * factory has not already been done in a previous iteration (some implementation
668: * apply to more than one factory).
669: */
670: scanForType: for (int i = 0; i < FACTORY_TYPES.length; i++) {
671: if (!OBJECT_TYPES[i].isAssignableFrom(type)) {
672: continue;
673: }
674: final Class factoryType = FACTORY_TYPES[i];
675: final AuthorityFactory factory;
676: try {
677: factory = getAuthorityFactory(factoryType,
678: dummyCode);
679: } catch (NoSuchAuthorityCodeException e) {
680: continue;
681: }
682: if (!done.add(factory)) {
683: continue;
684: }
685: AuthorityFactory wrapped = factory;
686: while (wrapped instanceof AuthorityFactoryAdapter) {
687: final AuthorityFactoryAdapter adapter = (AuthorityFactoryAdapter) wrapped;
688: try {
689: wrapped = adapter.getAuthorityFactory(
690: factoryType, dummyCode);
691: } catch (NoSuchAuthorityCodeException exception) {
692: /*
693: * The factory doesn't understand our dummy code. It happen with
694: * URN_AuthorityFactory, which expect the type ("CRS", etc.) in the URN.
695: */
696: continue scanForType;
697: }
698: if (!done.add(wrapped)) {
699: /*
700: * Avoid the factories that are wrapper around an other factory already
701: * done. If we don't do that, we will duplicate the whole set of EPSG
702: * identifiers (more than 3000 codes) for OrderedAuthorityFactory,
703: * HTTP_AuthorityFactory, URN_AuthorityFactory, etc.
704: */
705: continue scanForType;
706: }
707: }
708: for (final Iterator it2 = factory
709: .getAuthorityCodes(type).iterator(); it2
710: .hasNext();) {
711: String candidate = ((String) it2.next()).trim();
712: if (candidate.length() < codeBase
713: || Character.isLetterOrDigit(candidate
714: .charAt(codeBase - 1))
715: || !authority
716: .equalsIgnoreCase(candidate
717: .substring(0,
718: codeBase - 1))) {
719: // Prepend the authority code if it was not already presents.
720: code.setLength(codeBase);
721: code.append(candidate);
722: candidate = code.toString();
723: }
724: codes.add(candidate);
725: }
726: }
727: }
728: } finally {
729: inProgress.set(Boolean.FALSE);
730: // TODO: use inProgress.remove() when we will be allowed to compile for J2SE 1.5.
731: }
732: return codes;
733: }
734:
735: /**
736: * Gets a description of the object corresponding to a code.
737: *
738: * @param code Value allocated by authority.
739: * @return A description of the object, or {@code null} if the object
740: * corresponding to the specified {@code code} has no description.
741: * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
742: * @throws FactoryException if the query failed for some other reason.
743: */
744: public InternationalString getDescriptionText(final String code)
745: throws FactoryException {
746: final Set/*<AuthorityFactory>*/done = new HashSet();
747: done.add(this ); // Safety for avoiding recursive calls.
748: FactoryException failure = null;
749: for (int type = 0; type < FACTORY_TYPES.length; type++) {
750: /*
751: * Try all factories, starting with the CRS factory because it is the only one most
752: * users care about. If the CRS factory doesn't know about the specified object, then
753: * we will try the other factories (datum, CS, ...) before to rethrow the exception.
754: */
755: final AuthorityFactory factory;
756: try {
757: factory = getAuthorityFactory(FACTORY_TYPES[type], code);
758: } catch (NoSuchAuthorityCodeException exception) {
759: if (failure == null) {
760: failure = exception;
761: }
762: continue;
763: }
764: if (done.add(factory))
765: try {
766: return factory.getDescriptionText(code);
767: } catch (FactoryException exception) {
768: /*
769: * Failed to creates an object using the current factory. We will retain only the
770: * first exception and discart all other ones, except if the first exceptions were
771: * due to unknown authority (we will prefer exception due to unknown code instead).
772: * The first exception is usually thrown by the CRS factory, which is the only
773: * factory most users care about.
774: */
775: if (failure == null
776: || failure.getCause() instanceof FactoryRegistryException) {
777: failure = exception;
778: }
779: }
780: }
781: if (failure == null) {
782: failure = noSuchAuthorityCode(IdentifiedObject.class, code);
783: }
784: throw failure;
785: }
786:
787: /**
788: * Returns an arbitrary object from a code.
789: *
790: * @see #createCoordinateReferenceSystem
791: * @see #createDatum
792: * @see #createEllipsoid
793: * @see #createUnit
794: */
795: public IdentifiedObject createObject(final String code)
796: throws FactoryException {
797: final Set/*<AuthorityFactory>*/done = new HashSet();
798: done.add(this ); // Safety for avoiding recursive calls.
799: FactoryException failure = null;
800: for (int type = 0; type < FACTORY_TYPES.length; type++) {
801: /*
802: * Try all factories, starting with the CRS factory because it is the only one most
803: * users care about. If the CRS factory doesn't know about the specified object, then
804: * we will try the other factories (datum, CS, ...) before to rethrow the exception.
805: */
806: final AuthorityFactory factory;
807: try {
808: factory = getAuthorityFactory(FACTORY_TYPES[type], code);
809: } catch (NoSuchAuthorityCodeException exception) {
810: if (failure == null) {
811: failure = exception;
812: }
813: continue;
814: }
815: if (done.add(factory))
816: try {
817: return factory.createObject(code);
818: } catch (FactoryException exception) {
819: /*
820: * Failed to creates an object using the current factory. We will retain only the
821: * first exception and discart all other ones, except if the first exceptions were
822: * due to unknown authority (we will prefer exception due to unknown code instead).
823: * The first exception is usually thrown by the CRS factory, which is the only
824: * factory most users care about.
825: */
826: if (failure == null
827: || failure.getCause() instanceof FactoryRegistryException) {
828: failure = exception;
829: }
830: }
831: }
832: if (failure == null) {
833: failure = noSuchAuthorityCode(IdentifiedObject.class, code);
834: }
835: throw failure;
836: }
837:
838: /**
839: * Returns a finder which can be used for looking up unidentified objects.
840: * The default implementation delegates the lookups to the underlying factories.
841: */
842: //@Override
843: public IdentifiedObjectFinder getIdentifiedObjectFinder(
844: final Class/*<? extends IdentifiedObject>*/type)
845: throws FactoryException {
846: return new Finder(this , type);
847: }
848:
849: /**
850: * A {@link IdentifiedObjectFinder} which tests every factories.
851: */
852: static class Finder extends IdentifiedObjectFinder {
853: /**
854: * Creates a finder for the specified type.
855: */
856: protected Finder(final ManyAuthoritiesFactory factory,
857: final Class/*<? extends IdentifiedObject>*/type) {
858: super (factory, type);
859: }
860:
861: /**
862: * Returns the user-supplied factories.
863: */
864: final Collection getFactories() {
865: return ((ManyAuthoritiesFactory) proxy
866: .getAuthorityFactory()).getFactories();
867: }
868:
869: /**
870: * Returns the next finder in the specified set of factories, or {@code null} if none.
871: */
872: final IdentifiedObjectFinder next(
873: final Iterator/*<AuthorityFactory>*/it)
874: throws FactoryException {
875: while (it.hasNext()) {
876: final AuthorityFactory factory = (AuthorityFactory) it
877: .next();
878: if (exclude(factory)) {
879: continue;
880: }
881: if (factory instanceof AbstractAuthorityFactory) {
882: final IdentifiedObjectFinder finder = ((AbstractAuthorityFactory) factory)
883: .getIdentifiedObjectFinder(proxy.getType());
884: if (finder != null) {
885: finder.setFullScanAllowed(isFullScanAllowed());
886: return finder;
887: }
888: }
889: }
890: return null;
891: }
892:
893: /**
894: * Lookups for the specified object.
895: */
896: //@Override
897: public IdentifiedObject find(final IdentifiedObject object)
898: throws FactoryException {
899: /*
900: * Try to create from the identifier before to scan over every factories,
901: * because the identifier may contains the authority name, in which case
902: * we can pickup directly the right factory instead of trying them all.
903: */
904: IdentifiedObject candidate = createFromIdentifiers(object);
905: if (candidate != null) {
906: return candidate;
907: }
908: final Collection factories = getFactories();
909: if (factories != null) {
910: IdentifiedObjectFinder finder;
911: final Iterator it = factories.iterator();
912: while ((finder = next(it)) != null) {
913: candidate = finder.find(object);
914: if (candidate != null) {
915: break;
916: }
917: }
918: }
919: return candidate;
920: }
921:
922: /**
923: * Returns the identifier of the specified object, or {@code null} if none.
924: */
925: //@Override
926: public String findIdentifier(final IdentifiedObject object)
927: throws FactoryException {
928: /*
929: * Try to create from the identifier for the same reason than find(IdentifiedObject).
930: * Note that we returns directly the primary name; we don't try to locate a name for
931: * a given authority since the "All" authority do not really exists.
932: */
933: IdentifiedObject candidate = createFromIdentifiers(object);
934: if (candidate != null) {
935: return candidate.getName().toString();
936: }
937: final Collection factories = getFactories();
938: if (factories != null) {
939: IdentifiedObjectFinder finder;
940: final Iterator it = factories.iterator();
941: while ((finder = next(it)) != null) {
942: final String id = finder.findIdentifier(object);
943: if (id != null) {
944: return id;
945: }
946: }
947: }
948: return null;
949: }
950: }
951: }
|