001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2004, 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;
018:
019: // J2SE direct dependencies
020: import java.io.IOException;
021: import java.io.Writer;
022: import java.util.Set;
023: import java.util.Locale;
024: import java.util.Iterator;
025: import java.util.Collections;
026: import java.util.LinkedHashSet;
027: import javax.imageio.spi.ServiceRegistry;
028: import javax.imageio.spi.RegisterableService;
029:
030: // OpenGIS dependencies
031: import org.opengis.metadata.citation.Citation;
032: import org.opengis.referencing.Factory;
033: import org.opengis.referencing.AuthorityFactory;
034: import org.opengis.referencing.crs.CRSFactory;
035: import org.opengis.referencing.crs.CRSAuthorityFactory;
036: import org.opengis.referencing.cs.CSFactory;
037: import org.opengis.referencing.cs.CSAuthorityFactory;
038: import org.opengis.referencing.datum.DatumFactory;
039: import org.opengis.referencing.datum.DatumAuthorityFactory;
040: import org.opengis.referencing.operation.CoordinateOperationFactory;
041: import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
042: import org.opengis.referencing.operation.MathTransformFactory;
043:
044: // Geotools dependencies
045: import org.geotools.factory.Hints;
046: import org.geotools.factory.GeoTools;
047: import org.geotools.factory.FactoryFinder;
048: import org.geotools.factory.FactoryCreator;
049: import org.geotools.factory.FactoryRegistry;
050: import org.geotools.factory.FactoryRegistryException;
051: import org.geotools.metadata.iso.citation.Citations;
052: import org.geotools.resources.Arguments;
053: import org.geotools.resources.LazySet;
054:
055: /**
056: * Defines static methods used to access the application's default {@linkplain Factory
057: * factory} implementation.
058: *
059: * <P>To declare a factory implementation, a services subdirectory is placed within the
060: * {@code META-INF} directory that is present in every JAR file. This directory
061: * contains a file for each factory interface that has one or more implementation classes
062: * present in the JAR file. For example, if the JAR file contained a class named
063: * {@code com.mycompany.DatumFactoryImpl} which implements the {@link DatumFactory}
064: * interface, the JAR file would contain a file named:</P>
065: *
066: * <blockquote><pre>META-INF/services/org.opengis.referencing.datum.DatumFactory</pre></blockquote>
067: *
068: * <P>containing the line:</P>
069: *
070: * <blockquote><pre>com.mycompany.DatumFactoryImpl</pre></blockquote>
071: *
072: * <P>If the factory classes implements {@link RegisterableService}, it will be notified upon
073: * registration and deregistration. Note that the factory classes should be lightweight and quick
074: * to load. Implementations of these interfaces should avoid complex dependencies on other classes
075: * and on native code. The usual pattern for more complex services is to register a lightweight
076: * proxy for the heavyweight service.</P>
077: *
078: * <H2>Note on factory ordering</H2>
079: * <P>This class is thread-safe. However, calls to any {@link #setAuthorityOrdering} or
080: * {@link #setVendorOrdering} methods have a system-wide effect. If two threads or two
081: * applications need a different ordering, they shall manage their own instance of
082: * {@link FactoryRegistry}. This {@code FactoryFinder} class is simply a convenience
083: * wrapper around a {@code FactoryRegistry} instance.</P>
084: *
085: * @since 2.4
086: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/ReferencingFactoryFinder.java $
087: * @version $Id: ReferencingFactoryFinder.java 29058 2008-02-03 17:47:07Z desruisseaux $
088: * @author Martin Desruisseaux
089: */
090: public class ReferencingFactoryFinder extends FactoryFinder {
091: /**
092: * The service registry for this manager.
093: * Will be initialized only when first needed.
094: */
095: private static FactoryRegistry registry;
096:
097: /**
098: * The authority names. Will be created only when first needed.
099: */
100: private static Set/*<String>*/authorityNames;
101:
102: /**
103: * Do not allows any instantiation of this class.
104: */
105: ReferencingFactoryFinder() {
106: // singleton
107: }
108:
109: /**
110: * Returns the service registry. The registry will be created the first
111: * time this method is invoked.
112: */
113: private static FactoryRegistry getServiceRegistry() {
114: assert Thread.holdsLock(ReferencingFactoryFinder.class);
115: if (registry == null) {
116: registry = new FactoryCreator(new Class[] {
117: DatumFactory.class, CSFactory.class,
118: CRSFactory.class, DatumAuthorityFactory.class,
119: CSAuthorityFactory.class,
120: CRSAuthorityFactory.class,
121: MathTransformFactory.class,
122: CoordinateOperationFactory.class,
123: CoordinateOperationAuthorityFactory.class });
124: }
125: return registry;
126: }
127:
128: /**
129: * Returns the names of all currently registered authorities.
130: */
131: public static synchronized Set/*<String>*/getAuthorityNames() {
132: /*
133: * IMPORTANT: Return the same Set instance (unmodifiable) as long as there is no change
134: * in the list of registered factories, and create a new instance in case of changes.
135: * 'add/removeAuthorityFactory(...)' and 'scanForPlugins()' methods reset 'authorityNames'
136: * to null, which will cause the creation of a new Set instance. Some implementations like
137: * AllAuthoritiesFactory rely on this behavior as a way to be notified of registration
138: * changes for clearing their cache.
139: */
140: if (authorityNames == null) {
141: authorityNames = new LinkedHashSet();
142: final Hints hints = EMPTY_HINTS;
143: loop: for (int i = 0;; i++) {
144: final Set/*<AuthorityFactory>*/factories;
145: switch (i) {
146: case 0:
147: factories = getCRSAuthorityFactories(hints);
148: break;
149: case 1:
150: factories = getCSAuthorityFactories(hints);
151: break;
152: case 2:
153: factories = getDatumAuthorityFactories(hints);
154: break;
155: case 3:
156: factories = getCoordinateOperationAuthorityFactories(hints);
157: break;
158: default:
159: break loop;
160: }
161: for (final Iterator it = factories.iterator(); it
162: .hasNext();) {
163: final Citation authority = ((AuthorityFactory) it
164: .next()).getAuthority();
165: authorityNames.addAll(authority.getIdentifiers());
166: }
167: }
168: authorityNames = Collections
169: .unmodifiableSet(authorityNames);
170: }
171: return authorityNames;
172: }
173:
174: /**
175: * Returns all providers of the specified category.
176: *
177: * @param category The factory category.
178: * @param hints An optional map of hints, or {@code null} if none.
179: * @return Set of available factory implementations.
180: */
181: private static synchronized Set/*<T>*/getFactories(
182: final Class/*<T extends Factory>*/type, Hints hints) {
183: hints = mergeSystemHints(hints);
184: return new LazySet(getServiceRegistry().getServiceProviders(
185: type, null, hints));
186: }
187:
188: /**
189: * Returns a provider of the specified category.
190: *
191: * @param category The factory category.
192: * @param hints An optional map of hints, or {@code null} if none.
193: * @param key The hint key to use for searching an implementation.
194: * @return The first factory that matches the supplied hints.
195: * @throws FactoryRegistryException if no implementation was found or can be created for the
196: * specified interface.
197: */
198: private static synchronized Factory /*T*/getFactory(
199: final Class/*<T extends Factory>*/type, Hints hints,
200: final Hints.Key key) throws FactoryRegistryException {
201: hints = mergeSystemHints(hints);
202: return (Factory) getServiceRegistry().getServiceProvider(type,
203: null, hints, key);
204: }
205:
206: /**
207: * Returns the first implementation of a factory matching the specified hints. If no
208: * implementation matches, a new one is created if possible or an exception is thrown
209: * otherwise. If more than one implementation is registered and an
210: * {@linkplain #setVendorOrdering ordering is set}, then the preferred
211: * implementation is returned. Otherwise an arbitrary one is selected.
212: *
213: * @param category The authority factory type.
214: * @param authority The desired authority (e.g. "EPSG").
215: * @param hints An optional map of hints, or {@code null} if none.
216: * @param key The hint key to use for searching an implementation.
217: * @return The first authority factory that matches the supplied hints.
218: * @throws FactoryRegistryException if no implementation was found or can be created for the
219: * specfied interface.
220: */
221: private static synchronized AuthorityFactory /*T*/getAuthorityFactory(
222: final Class/*<T extends AuthorityFactory>*/type,
223: final String authority, Hints hints, final Hints.Key key)
224: throws FactoryRegistryException {
225: hints = mergeSystemHints(hints);
226: return (AuthorityFactory) getServiceRegistry()
227: .getServiceProvider(type,
228: new AuthorityFilter(authority), hints, key);
229: }
230:
231: /**
232: * Returns the first implementation of {@link DatumFactory} matching the specified hints.
233: * If no implementation matches, a new one is created if possible or an exception is thrown
234: * otherwise. If more than one implementation is registered and an
235: * {@linkplain #setVendorOrdering ordering is set}, then the preferred
236: * implementation is returned. Otherwise an arbitrary one is selected.
237: *
238: * @param hints An optional map of hints, or {@code null} if none.
239: * @return The first datum factory that matches the supplied hints.
240: * @throws FactoryRegistryException if no implementation was found or can be created for the
241: * {@link DatumFactory} interface.
242: */
243: public static DatumFactory getDatumFactory(final Hints hints)
244: throws FactoryRegistryException {
245: return (DatumFactory) getFactory(DatumFactory.class, hints,
246: Hints.DATUM_FACTORY);
247: }
248:
249: /**
250: * Returns a set of all available implementations for the {@link DatumFactory} interface.
251: *
252: * @param hints An optional map of hints, or {@code null} if none.
253: * @return Set of available datum factory implementations.
254: */
255: public static Set getDatumFactories(final Hints hints) {
256: return getFactories(DatumFactory.class, hints);
257: }
258:
259: /**
260: * Returns the first implementation of {@link CSFactory} matching the specified hints.
261: * If no implementation matches, a new one is created if possible or an exception is thrown
262: * otherwise. If more than one implementation is registered and an
263: * {@linkplain #setVendorOrdering ordering is set}, then the preferred
264: * implementation is returned. Otherwise an arbitrary one is selected.
265: *
266: * @param hints An optional map of hints, or {@code null} if none.
267: * @return The first coordinate system factory that matches the supplied hints.
268: * @throws FactoryRegistryException if no implementation was found or can be created for the
269: * {@link CSFactory} interface.
270: */
271: public static CSFactory getCSFactory(final Hints hints)
272: throws FactoryRegistryException {
273: return (CSFactory) getFactory(CSFactory.class, hints,
274: Hints.CS_FACTORY);
275: }
276:
277: /**
278: * Returns a set of all available implementations for the {@link CSFactory} interface.
279: *
280: * @param hints An optional map of hints, or {@code null} if none.
281: * @return Set of available coordinate system factory implementations.
282: */
283: public static Set getCSFactories(final Hints hints) {
284: return getFactories(CSFactory.class, hints);
285: }
286:
287: /**
288: * Returns the first implementation of {@link CRSFactory} matching the specified hints.
289: * If no implementation matches, a new one is created if possible or an exception is thrown
290: * otherwise. If more than one implementation is registered and an
291: * {@linkplain #setVendorOrdering ordering is set}, then the preferred
292: * implementation is returned. Otherwise an arbitrary one is selected.
293: *
294: * @param hints An optional map of hints, or {@code null} if none.
295: * @return The first coordinate reference system factory that matches the supplied hints.
296: * @throws FactoryRegistryException if no implementation was found or can be created for the
297: * {@link CRSFactory} interface.
298: */
299: public static CRSFactory getCRSFactory(final Hints hints)
300: throws FactoryRegistryException {
301: return (CRSFactory) getFactory(CRSFactory.class, hints,
302: Hints.CRS_FACTORY);
303: }
304:
305: /**
306: * Returns a set of all available implementations for the {@link CRSFactory} interface.
307: *
308: * @param hints An optional map of hints, or {@code null} if none.
309: * @return Set of available coordinate reference system factory implementations.
310: */
311: public static Set getCRSFactories(final Hints hints) {
312: return getFactories(CRSFactory.class, hints);
313: }
314:
315: /**
316: * Returns the first implementation of {@link CoordinateOperationFactory} matching the specified
317: * hints. If no implementation matches, a new one is created if possible or an exception is
318: * thrown otherwise. If more than one implementation is registered and an
319: * {@linkplain #setVendorOrdering ordering is set}, then the preferred
320: * implementation is returned. Otherwise an arbitrary one is selected.
321: * <p>
322: * Hints that may be understood includes
323: * {@link Hints#MATH_TRANSFORM_FACTORY MATH_TRANSFORM_FACTORY},
324: * {@link Hints#DATUM_SHIFT_METHOD DATUM_SHIFT_METHOD},
325: * {@link Hints#LENIENT_DATUM_SHIFT LENIENT_DATUM_SHIFT} and
326: * {@link Hints#VERSION VERSION}.
327: *
328: * @param hints An optional map of hints, or {@code null} if none.
329: * @return The first coordinate operation factory that matches the supplied hints.
330: * @throws FactoryRegistryException if no implementation was found or can be created for the
331: * {@link CoordinateOperationFactory} interface.
332: */
333: public static CoordinateOperationFactory getCoordinateOperationFactory(
334: final Hints hints) throws FactoryRegistryException {
335: return (CoordinateOperationFactory) getFactory(
336: CoordinateOperationFactory.class, hints,
337: Hints.COORDINATE_OPERATION_FACTORY);
338: }
339:
340: /**
341: * Returns a set of all available implementations for the
342: * {@link CoordinateOperationFactory} interface.
343: *
344: * @param hints An optional map of hints, or {@code null} if none.
345: * @return Set of available coordinate operation factory implementations.
346: */
347: public static Set getCoordinateOperationFactories(final Hints hints) {
348: return getFactories(CoordinateOperationFactory.class, hints);
349: }
350:
351: /**
352: * Returns the first implementation of {@link DatumAuthorityFactory} matching the specified
353: * hints. If no implementation matches, a new one is created if possible or an exception is
354: * thrown otherwise. If more than one implementation is registered and an
355: * {@linkplain #setVendorOrdering ordering is set}, then the preferred
356: * implementation is returned. Otherwise an arbitrary one is selected.
357: *
358: * @param authority The desired authority (e.g. "EPSG").
359: * @param hints An optional map of hints, or {@code null} if none.
360: * @return The first datum authority factory that matches the supplied hints.
361: * @throws FactoryRegistryException if no implementation was found or can be created for the
362: * {@link DatumAuthorityFactory} interface.
363: */
364: public static DatumAuthorityFactory getDatumAuthorityFactory(
365: final String authority, final Hints hints)
366: throws FactoryRegistryException {
367: return (DatumAuthorityFactory) getAuthorityFactory(
368: DatumAuthorityFactory.class, authority, hints,
369: Hints.DATUM_AUTHORITY_FACTORY);
370: }
371:
372: /**
373: * Returns a set of all available implementations for the {@link DatumAuthorityFactory}
374: * interface.
375: *
376: * @param hints An optional map of hints, or {@code null} if none.
377: * @return Set of available datum authority factory implementations.
378: */
379: public static Set getDatumAuthorityFactories(final Hints hints) {
380: return getFactories(DatumAuthorityFactory.class, hints);
381: }
382:
383: /**
384: * Returns the first implementation of {@link CSAuthorityFactory} matching the specified
385: * hints. If no implementation matches, a new one is created if possible or an exception is
386: * thrown otherwise. If more than one implementation is registered and an
387: * {@linkplain #setVendorOrdering ordering is set}, then the preferred
388: * implementation is returned. Otherwise an arbitrary one is selected.
389: * <p>
390: * Hints that may be understood includes
391: * {@link Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER FORCE_LONGITUDE_FIRST_AXIS_ORDER},
392: * {@link Hints#FORCE_STANDARD_AXIS_UNITS FORCE_STANDARD_AXIS_UNITS} and
393: * {@link Hints#FORCE_STANDARD_AXIS_DIRECTIONS FORCE_STANDARD_AXIS_DIRECTIONS} and
394: * {@link Hints#VERSION VERSION}.
395: *
396: * @param authority The desired authority (e.g. "EPSG").
397: * @param hints An optional map of hints, or {@code null} if none.
398: * @return The first coordinate system authority factory that matches the supplied hints.
399: * @throws FactoryRegistryException if no implementation was found or can be created for the
400: * {@link CSAuthorityFactory} interface.
401: */
402: public static CSAuthorityFactory getCSAuthorityFactory(
403: final String authority, final Hints hints)
404: throws FactoryRegistryException {
405: return (CSAuthorityFactory) getAuthorityFactory(
406: CSAuthorityFactory.class, authority, hints,
407: Hints.CS_AUTHORITY_FACTORY);
408: }
409:
410: /**
411: * Returns a set of all available implementations for the {@link CSAuthorityFactory} interface.
412: *
413: * @param hints An optional map of hints, or {@code null} if none.
414: * @return Set of available coordinate system authority factory implementations.
415: */
416: public static Set getCSAuthorityFactories(final Hints hints) {
417: return getFactories(CSAuthorityFactory.class, hints);
418: }
419:
420: /**
421: * Returns the first implementation of {@link CRSAuthorityFactory} matching the specified
422: * hints. If no implementation matches, a new one is created if possible or an exception is
423: * thrown otherwise. If more than one implementation is registered and an
424: * {@linkplain #setVendorOrdering ordering is set}, then the preferred
425: * implementation is returned. Otherwise an arbitrary one is selected.
426: * <p>
427: * Hints that may be understood includes
428: * {@link Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER FORCE_LONGITUDE_FIRST_AXIS_ORDER},
429: * {@link Hints#FORCE_STANDARD_AXIS_UNITS FORCE_STANDARD_AXIS_UNITS},
430: * {@link Hints#FORCE_STANDARD_AXIS_DIRECTIONS FORCE_STANDARD_AXIS_DIRECTIONS} and
431: * {@link Hints#VERSION VERSION}.
432: * <p>
433: * <b>TIP:</b> The EPSG official factory and the EPSG extensions (additional CRS provided by
434: * ESRI and others) are two distinct factories. Call to {@code getCRSAuthorityFactory("EPSG",
435: * null)} returns only one of those, usually the official EPSG factory. If the union of those
436: * two factories is wanted, then a chain of fallbacks is wanted. Consider using something like:
437: *
438: * <blockquote><code>
439: * {@linkplain org.geotools.referencing.factory.FallbackAuthorityFactory#create(Class,
440: * java.util.Collection) FallbackAuthorityFactory.create}(CRSAuthorityFactory.class,
441: * {@linkplain #getCRSAuthorityFactories getCRSAuthorityFactories}(hints));
442: * </code></blockquote>
443: *
444: * @param authority The desired authority (e.g. "EPSG").
445: * @param hints An optional map of hints, or {@code null} if none.
446: * @return The first coordinate reference system authority factory that matches the supplied hints.
447: * @throws FactoryRegistryException if no implementation was found or can be created for the
448: * {@link CRSAuthorityFactory} interface.
449: */
450: public static CRSAuthorityFactory getCRSAuthorityFactory(
451: final String authority, final Hints hints)
452: throws FactoryRegistryException {
453: return (CRSAuthorityFactory) getAuthorityFactory(
454: CRSAuthorityFactory.class, authority, hints,
455: Hints.CRS_AUTHORITY_FACTORY);
456: }
457:
458: /**
459: * Returns a set of all available implementations for the {@link CRSAuthorityFactory} interface.
460: * This set can be used to list the available codes known to all authorities.
461: * In the event that the same code is understood by more then one authority
462: * you will need to assume both are close enough, or make use of this set directly
463: * rather than use the {@link CRS#decode} convenience method.
464: *
465: * @param hints An optional map of hints, or {@code null} if none.
466: * @return Set of available coordinate reference system authority factory implementations.
467: */
468: public static Set getCRSAuthorityFactories(final Hints hints) {
469: return getFactories(CRSAuthorityFactory.class, hints);
470: }
471:
472: /**
473: * Returns the first implementation of {@link CoordinateOperationAuthorityFactory} matching
474: * the specified hints. If no implementation matches, a new one is created if possible or an
475: * exception is thrown otherwise. If more than one implementation is registered and an
476: * {@linkplain #setVendorOrdering ordering is set}, then the preferred
477: * implementation is returned. Otherwise an arbitrary one is selected.
478: *
479: * @param authority The desired authority (e.g. "EPSG").
480: * @param hints An optional map of hints, or {@code null} if none.
481: * @return The first coordinate operation authority factory that matches the supplied hints.
482: * @throws FactoryRegistryException if no implementation was found or can be created for the
483: * {@link CoordinateOperationAuthorityFactory} interface.
484: */
485: public static CoordinateOperationAuthorityFactory getCoordinateOperationAuthorityFactory(
486: final String authority, final Hints hints)
487: throws FactoryRegistryException {
488: return (CoordinateOperationAuthorityFactory) getAuthorityFactory(
489: CoordinateOperationAuthorityFactory.class, authority,
490: hints, Hints.COORDINATE_OPERATION_AUTHORITY_FACTORY);
491: }
492:
493: /**
494: * Returns a set of all available implementations for the
495: * {@link CoordinateOperationAuthorityFactory} interface.
496: *
497: * @param hints An optional map of hints, or {@code null} if none.
498: * @return Set of available coordinate operation authority factory implementations.
499: */
500: public static Set getCoordinateOperationAuthorityFactories(
501: final Hints hints) {
502: return getFactories(CoordinateOperationAuthorityFactory.class,
503: hints);
504: }
505:
506: /**
507: * Returns the first implementation of {@link MathTransformFactory} matching the specified
508: * hints. If no implementation matches, a new one is created if possible or an exception is
509: * thrown otherwise. If more than one implementation is registered and an
510: * {@linkplain #setVendorOrdering ordering is set}, then the preferred
511: * implementation is returned. Otherwise an arbitrary one is selected.
512: *
513: * @param hints An optional map of hints, or {@code null} if none.
514: * @return The first math transform factory that matches the supplied hints.
515: * @throws FactoryRegistryException if no implementation was found or can be created for the
516: * {@link MathTransformFactory} interface.
517: */
518: public static MathTransformFactory getMathTransformFactory(
519: final Hints hints) throws FactoryRegistryException {
520: return (MathTransformFactory) getFactory(
521: MathTransformFactory.class, hints,
522: Hints.MATH_TRANSFORM_FACTORY);
523: }
524:
525: /**
526: * Returns a set of all available implementations for the
527: * {@link MathTransformFactory} interface.
528: *
529: * @param hints An optional map of hints, or {@code null} if none.
530: * @return Set of available math transform factory implementations.
531: */
532: public static Set getMathTransformFactories(final Hints hints) {
533: return getFactories(MathTransformFactory.class, hints);
534: }
535:
536: /**
537: * Sets a pairwise ordering between two vendors. If one or both vendors are not
538: * currently registered, or if the desired ordering is already set, nothing happens
539: * and {@code false} is returned.
540: * <p>
541: * The example below said that an ESRI implementation (if available) is
542: * preferred over the Geotools one:
543: *
544: * <blockquote><code>FactoryFinder.setVendorOrdering("ESRI", "Geotools");</code></blockquote>
545: *
546: * @param vendor1 The preferred vendor.
547: * @param vendor2 The vendor to which {@code vendor1} is preferred.
548: * @return {@code true} if the ordering was set for at least one category.
549: */
550: public static synchronized boolean setVendorOrdering(
551: final String vendor1, final String vendor2) {
552: return getServiceRegistry().setOrdering(Factory.class, true,
553: new VendorFilter(vendor1), new VendorFilter(vendor2));
554: }
555:
556: /**
557: * Unsets a pairwise ordering between two vendors. If one or both vendors are not
558: * currently registered, or if the desired ordering is already unset, nothing happens
559: * and {@code false} is returned.
560: *
561: * @param vendor1 The preferred vendor.
562: * @param vendor2 The vendor to which {@code vendor1} is preferred.
563: * @return {@code true} if the ordering was unset for at least one category.
564: */
565: public static synchronized boolean unsetVendorOrdering(
566: final String vendor1, final String vendor2) {
567: return getServiceRegistry().setOrdering(Factory.class, false,
568: new VendorFilter(vendor1), new VendorFilter(vendor2));
569: }
570:
571: /**
572: * A filter for factories provided by a given vendor.
573: */
574: private static final class VendorFilter implements
575: ServiceRegistry.Filter {
576: /** The vendor to filter. */
577: private final String vendor;
578:
579: /** Constructs a filter for the given vendor. */
580: public VendorFilter(final String vendor) {
581: this .vendor = vendor;
582: }
583:
584: /** Returns {@code true} if the specified provider is built by the vendor. */
585: public boolean filter(final Object provider) {
586: return Citations.titleMatches(((Factory) provider)
587: .getVendor(), vendor);
588: }
589: }
590:
591: /**
592: * Sets a pairwise ordering between two authorities. If one or both authorities are not
593: * currently registered, or if the desired ordering is already set, nothing happens
594: * and {@code false} is returned.
595: * <p>
596: * The example below said that EPSG {@linkplain AuthorityFactory authority factories}
597: * are preferred over ESRI ones:
598: *
599: * <blockquote><code>FactoryFinder.setAuthorityOrdering("EPSG", "ESRI");</code></blockquote>
600: *
601: * @param authority1 The preferred authority.
602: * @param authority2 The authority to which {@code authority1} is preferred.
603: * @return {@code true} if the ordering was set for at least one category.
604: */
605: public static synchronized boolean setAuthorityOrdering(
606: final String authority1, final String authority2) {
607: return getServiceRegistry().setOrdering(AuthorityFactory.class,
608: true, new AuthorityFilter(authority1),
609: new AuthorityFilter(authority2));
610: }
611:
612: /**
613: * Unsets a pairwise ordering between two authorities. If one or both authorities are not
614: * currently registered, or if the desired ordering is already unset, nothing happens
615: * and {@code false} is returned.
616: *
617: * @param authority1 The preferred authority.
618: * @param authority2 The vendor to which {@code authority1} is preferred.
619: * @return {@code true} if the ordering was unset for at least one category.
620: */
621: public static synchronized boolean unsetAuthorityOrdering(
622: final String authority1, final String authority2) {
623: return getServiceRegistry().setOrdering(AuthorityFactory.class,
624: false, new AuthorityFilter(authority1),
625: new AuthorityFilter(authority2));
626: }
627:
628: /**
629: * A filter for factories provided for a given authority.
630: */
631: private static final class AuthorityFilter implements
632: ServiceRegistry.Filter {
633: /** The authority to filter. */
634: private final String authority;
635:
636: /** Constructs a filter for the given authority. */
637: public AuthorityFilter(final String authority) {
638: this .authority = authority;
639: }
640:
641: /** Returns {@code true} if the specified provider is for the authority. */
642: public boolean filter(final Object provider) {
643: if (authority == null) {
644: // If the user didn't specified an authority name, then the factory to use must
645: // be specified explicitly through a hint (e.g. Hints.CRS_AUTHORITY_FACTORY).
646: return false;
647: }
648: return Citations.identifierMatches(
649: ((AuthorityFactory) provider).getAuthority(),
650: authority);
651: }
652: }
653:
654: /**
655: * Programmatic management of authority factories.
656: * Needed for user managed, not plug-in managed, authority factory.
657: * Also useful for test cases.
658: *
659: * @param authority The authority factory to add.
660: */
661: public static synchronized void addAuthorityFactory(
662: final AuthorityFactory authority) {
663: if (registry == null) {
664: scanForPlugins();
665: }
666: getServiceRegistry().registerServiceProvider(authority);
667: authorityNames = null;
668: }
669:
670: /**
671: * Programmatic management of authority factories.
672: * Needed for user managed, not plug-in managed, authority factory.
673: * Also useful for test cases.
674: *
675: * @param authority The authority factory to remove.
676: */
677: public static synchronized void removeAuthorityFactory(
678: final AuthorityFactory authority) {
679: getServiceRegistry().deregisterServiceProvider(authority);
680: authorityNames = null;
681: }
682:
683: /**
684: * Returns {@code true} if the specified factory is registered. A factory may have been
685: * registered by {@link #scanForPlugins()} if it was declared in a {@code META-INF/services}
686: * file, or it may have been {@linkplain #addAuthorityFactory added programmatically}.
687: *
688: * @since 2.4
689: */
690: public static synchronized boolean isRegistered(
691: final Factory factory) {
692: return factory.equals(getServiceRegistry()
693: .getServiceProviderByClass(factory.getClass()));
694: }
695:
696: /**
697: * Scans for factory plug-ins on the application class path. This method is needed because the
698: * application class path can theoretically change, or additional plug-ins may become available.
699: * Rather than re-scanning the classpath on every invocation of the API, the class path is
700: * scanned automatically only on the first invocation. Clients can call this method to prompt
701: * a re-scan. Thus this method need only be invoked by sophisticated applications which
702: * dynamically make new plug-ins available at runtime.
703: */
704: public static void scanForPlugins() {
705: synchronized (ReferencingFactoryFinder.class) {
706: authorityNames = null;
707: if (registry != null) {
708: registry.scanForPlugins();
709: }
710: }
711: GeoTools.fireConfigurationChanged();
712: }
713:
714: /**
715: * List all available factory implementations in a tabular format. For each factory interface,
716: * the first implementation listed is the default one. This method provides a way to check the
717: * state of a system, usually for debugging purpose.
718: *
719: * @param out The output stream where to format the list.
720: * @param locale The locale for the list, or {@code null}.
721: * @throws IOException if an error occurs while writting to {@code out}.
722: */
723: public static synchronized void listProviders(final Writer out,
724: final Locale locale) throws IOException {
725: final FactoryRegistry registry = getServiceRegistry();
726: new FactoryPrinter().list(registry, out, locale);
727: }
728:
729: /**
730: * Dump to the standard output stream a list of available factory implementations.
731: * This method can be invoked from the command line. It provides a mean to verify
732: * if some implementations were found in the classpath. The syntax is:
733: * <BR>
734: * <BLOCKQUOTE><CODE>
735: * java org.geotools.referencing.FactoryFinder <VAR><options></VAR>
736: * </CODE></BLOCKQUOTE>
737: *
738: * <P>where options are:</P>
739: *
740: * <TABLE CELLPADDING='0' CELLSPACING='0'>
741: * <TR><TD NOWRAP><CODE>-encoding</CODE> <VAR><code></VAR></TD>
742: * <TD NOWRAP> Set the character encoding</TD></TR>
743: * <TR><TD NOWRAP><CODE>-locale</CODE> <VAR><language></VAR></TD>
744: * <TD NOWRAP> Set the language for the output (e.g. "fr" for French)</TD></TR>
745: * </TABLE>
746: *
747: * <P><strong>Note for Windows users:</strong> If the output contains strange
748: * symbols, try to supply an "{@code -encoding}" argument. Example:</P>
749: *
750: * <blockquote><code>
751: * java org.geotools.referencing.FactoryFinder -encoding Cp850
752: * </code></blockquote>
753: *
754: * <P>The codepage number (850 in the previous example) can be obtained from the DOS
755: * commande line using the "{@code chcp}" command with no arguments.
756: * This {@code -encoding} argument need to be supplied only once.</P>
757: *
758: * @param args Command line arguments.
759: */
760: public static void main(String[] args) {
761: final Arguments arguments = new Arguments(args);
762: args = arguments.getRemainingArguments(0);
763: try {
764: listProviders(arguments.out, arguments.locale);
765: } catch (Exception exception) {
766: exception.printStackTrace(arguments.err);
767: }
768: }
769: }
|