/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2004-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.referencing;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;
import java.util.Locale;
import java.util.Collections;
import java.util.LinkedHashSet;
import javax.imageio.spi.ServiceRegistry;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.citation.Citation;
import org.opengis.referencing.Factory;
import org.opengis.referencing.AuthorityFactory;
import org.opengis.referencing.crs.CRSFactory;
import org.opengis.referencing.crs.CRSAuthorityFactory;
import org.opengis.referencing.cs.CSFactory;
import org.opengis.referencing.cs.CSAuthorityFactory;
import org.opengis.referencing.datum.DatumFactory;
import org.opengis.referencing.datum.DatumAuthorityFactory;
import org.opengis.referencing.operation.CoordinateOperationFactory;
import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
import org.opengis.referencing.operation.MathTransformFactory;
import org.geotools.factory.Hints;
import org.geotools.factory.GeoTools;
import org.geotools.factory.FactoryFinder;
import org.geotools.factory.FactoryCreator;
import org.geotools.factory.FactoryRegistry;
import org.geotools.factory.FactoryRegistryException;
import org.geotools.metadata.iso.citation.Citations;
import org.geotools.resources.Arguments;
import org.geotools.resources.LazySet;
/**
* Defines static methods used to access the application's default {@linkplain Factory
* factory} implementation.
*
* <P>To declare a factory implementation, a services subdirectory is placed within the
* {@code META-INF} directory that is present in every JAR file. This directory
* contains a file for each factory interface that has one or more implementation classes
* present in the JAR file. For example, if the JAR file contained a class named
* {@code com.mycompany.DatumFactoryImpl} which implements the {@link DatumFactory}
* interface, the JAR file would contain a file named:</P>
*
* <blockquote><pre>META-INF/services/org.opengis.referencing.datum.DatumFactory</pre></blockquote>
*
* <P>containing the line:</P>
*
* <blockquote><pre>com.mycompany.DatumFactoryImpl</pre></blockquote>
*
* <P>If the factory classes implements {@link javax.imageio.spi.RegisterableService}, it will
* be notified upon registration and deregistration. Note that the factory classes should be
* lightweight and quick to load. Implementations of these interfaces should avoid complex
* dependencies on other classes and on native code. The usual pattern for more complex services
* is to register a lightweight proxy for the heavyweight service.</P>
*
* <H2>Note on factory ordering</H2>
* <P>This class is thread-safe. However, calls to any {@link #setAuthorityOrdering} or
* {@link #setVendorOrdering} methods have a system-wide effect. If two threads or two
* applications need a different ordering, they shall manage their own instance of
* {@link FactoryRegistry}. This {@code FactoryFinder} class is simply a convenience
* wrapper around a {@code FactoryRegistry} instance.</P>
*
* @since 2.4
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux (IRD)
*/
public final class ReferencingFactoryFinder extends FactoryFinder {
/**
* The service registry for this manager.
* Will be initialized only when first needed.
*/
private static FactoryRegistry registry;
/**
* The authority names. Will be created only when first needed.
*/
private static Set<String> authorityNames;
/**
* Do not allows any instantiation of this class.
*/
private ReferencingFactoryFinder() {
}
/**
* Returns the service registry. The registry will be created the first
* time this method is invoked.
*/
private static FactoryRegistry getServiceRegistry() {
assert Thread.holdsLock(ReferencingFactoryFinder.class);
if (registry == null) {
registry = new FactoryCreator(new Class<?>[] {
DatumFactory.class,
CSFactory.class,
CRSFactory.class,
DatumAuthorityFactory.class,
CSAuthorityFactory.class,
CRSAuthorityFactory.class,
MathTransformFactory.class,
CoordinateOperationFactory.class,
CoordinateOperationAuthorityFactory.class});
}
return registry;
}
/**
* Returns the names of all currently registered authorities.
*/
public static synchronized Set<String> getAuthorityNames() {
/*
* IMPORTANT: Return the same Set instance (unmodifiable) as long as there is no change
* in the list of registered factories, and create a new instance in case of changes.
* 'add/removeAuthorityFactory(...)' and 'scanForPlugins()' methods reset 'authorityNames'
* to null, which will cause the creation of a new Set instance. Some implementations like
* AllAuthoritiesFactory rely on this behavior as a way to be notified of registration
* changes for clearing their cache.
*/
if (authorityNames == null) {
authorityNames = new LinkedHashSet<String>();
final Hints hints = EMPTY_HINTS;
loop: for (int i=0; ; i++) {
final Set<? extends AuthorityFactory> factories;
switch (i) {
case 0: factories = getCRSAuthorityFactories(hints); break;
case 1: factories = getCSAuthorityFactories(hints); break;
case 2: factories = getDatumAuthorityFactories(hints); break;
case 3: factories = getCoordinateOperationAuthorityFactories(hints); break;
default: break loop;
}
for (final AuthorityFactory factory : factories) {
final Citation authority = factory.getAuthority();
if (authority != null) {
authorityNames.add(Citations.getIdentifier(authority));
for (final Identifier id : authority.getIdentifiers()) {
authorityNames.add(id.getCode());
}
}
}
}
authorityNames = Collections.unmodifiableSet(authorityNames);
}
return authorityNames;
}
/**
* Returns all providers of the specified category.
*
* @param category The factory category.
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available factory implementations.
*/
private static synchronized <T extends Factory>
Set<T> getFactories(final Class<T> category, Hints hints)
{
hints = mergeSystemHints(hints);
return new LazySet<T>(getServiceRegistry().getServiceProviders(category, null, hints));
}
/**
* Returns a provider of the specified category.
*
* @param category The factory category.
* @param hints An optional map of hints, or {@code null} if none.
* @param key The hint key to use for searching an implementation.
* @return The first factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* specified interface.
*/
private static synchronized <T extends Factory> T getFactory(final Class<T> category,
Hints hints, final Hints.Key key) throws FactoryRegistryException
{
hints = mergeSystemHints(hints);
return getServiceRegistry().getServiceProvider(category, null, hints, key);
}
/**
* Returns the first implementation of a factory matching the specified hints. If no
* implementation matches, a new one is created if possible or an exception is thrown
* otherwise. If more than one implementation is registered and an
* {@linkplain #setVendorOrdering ordering is set}, then the preferred
* implementation is returned. Otherwise an arbitrary one is selected.
*
* @param category The authority factory type.
* @param authority The desired authority (e.g. "EPSG").
* @param hints An optional map of hints, or {@code null} if none.
* @param key The hint key to use for searching an implementation.
* @return The first authority factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* specfied interface.
*/
private static synchronized <T extends AuthorityFactory> T getAuthorityFactory(
final Class<T> category, final String authority, Hints hints, final Hints.Key key)
throws FactoryRegistryException
{
hints = mergeSystemHints(hints);
return getServiceRegistry().getServiceProvider(category, new AuthorityFilter(authority), hints, key);
}
/**
* Returns the first implementation of {@link DatumFactory} matching the specified hints.
* If no implementation matches, a new one is created if possible or an exception is thrown
* otherwise. If more than one implementation is registered and an
* {@linkplain #setVendorOrdering ordering is set}, then the preferred
* implementation is returned. Otherwise an arbitrary one is selected.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return The first datum factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link DatumFactory} interface.
*/
public static DatumFactory getDatumFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(DatumFactory.class, hints, Hints.DATUM_FACTORY);
}
/**
* Returns a set of all available implementations for the {@link DatumFactory} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available datum factory implementations.
*/
public static Set<DatumFactory> getDatumFactories(final Hints hints) {
return getFactories(DatumFactory.class, hints);
}
/**
* Returns the first implementation of {@link CSFactory} matching the specified hints.
* If no implementation matches, a new one is created if possible or an exception is thrown
* otherwise. If more than one implementation is registered and an
* {@linkplain #setVendorOrdering ordering is set}, then the preferred
* implementation is returned. Otherwise an arbitrary one is selected.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return The first coordinate system factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link CSFactory} interface.
*/
public static CSFactory getCSFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(CSFactory.class, hints, Hints.CS_FACTORY);
}
/**
* Returns a set of all available implementations for the {@link CSFactory} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available coordinate system factory implementations.
*/
public static Set<CSFactory> getCSFactories(final Hints hints) {
return getFactories(CSFactory.class, hints);
}
/**
* Returns the first implementation of {@link CRSFactory} matching the specified hints.
* If no implementation matches, a new one is created if possible or an exception is thrown
* otherwise. If more than one implementation is registered and an
* {@linkplain #setVendorOrdering ordering is set}, then the preferred
* implementation is returned. Otherwise an arbitrary one is selected.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return The first coordinate reference system factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link CRSFactory} interface.
*/
public static CRSFactory getCRSFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(CRSFactory.class, hints, Hints.CRS_FACTORY);
}
/**
* Returns a set of all available implementations for the {@link CRSFactory} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available coordinate reference system factory implementations.
*/
public static Set<CRSFactory> getCRSFactories(final Hints hints) {
return getFactories(CRSFactory.class, hints);
}
/**
* Returns the first implementation of {@link CoordinateOperationFactory} matching the specified
* hints. If no implementation matches, a new one is created if possible or an exception is
* thrown otherwise. If more than one implementation is registered and an
* {@linkplain #setVendorOrdering ordering is set}, then the preferred
* implementation is returned. Otherwise an arbitrary one is selected.
* <p>
* Hints that may be understood includes
* {@link Hints#MATH_TRANSFORM_FACTORY MATH_TRANSFORM_FACTORY},
* {@link Hints#DATUM_SHIFT_METHOD DATUM_SHIFT_METHOD},
* {@link Hints#LENIENT_DATUM_SHIFT LENIENT_DATUM_SHIFT} and
* {@link Hints#VERSION VERSION}.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return The first coordinate operation factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link CoordinateOperationFactory} interface.
*/
public static CoordinateOperationFactory getCoordinateOperationFactory(final Hints hints)
throws FactoryRegistryException
{
return getFactory(CoordinateOperationFactory.class, hints,
Hints.COORDINATE_OPERATION_FACTORY);
}
/**
* Returns a set of all available implementations for the
* {@link CoordinateOperationFactory} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available coordinate operation factory implementations.
*/
public static Set<CoordinateOperationFactory> getCoordinateOperationFactories(final Hints hints) {
return getFactories(CoordinateOperationFactory.class, hints);
}
/**
* Returns the first implementation of {@link DatumAuthorityFactory} matching the specified
* hints. If no implementation matches, a new one is created if possible or an exception is
* thrown otherwise. If more than one implementation is registered and an
* {@linkplain #setVendorOrdering ordering is set}, then the preferred
* implementation is returned. Otherwise an arbitrary one is selected.
*
* @param authority The desired authority (e.g. "EPSG").
* @param hints An optional map of hints, or {@code null} if none.
* @return The first datum authority factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link DatumAuthorityFactory} interface.
*/
public static DatumAuthorityFactory getDatumAuthorityFactory(final String authority,
final Hints hints)
throws FactoryRegistryException
{
return getAuthorityFactory(DatumAuthorityFactory.class, authority, hints,
Hints.DATUM_AUTHORITY_FACTORY);
}
/**
* Returns a set of all available implementations for the {@link DatumAuthorityFactory}
* interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available datum authority factory implementations.
*/
public static Set<DatumAuthorityFactory> getDatumAuthorityFactories(final Hints hints) {
return getFactories(DatumAuthorityFactory.class, hints);
}
/**
* Returns the first implementation of {@link CSAuthorityFactory} matching the specified
* hints. If no implementation matches, a new one is created if possible or an exception is
* thrown otherwise. If more than one implementation is registered and an
* {@linkplain #setVendorOrdering ordering is set}, then the preferred
* implementation is returned. Otherwise an arbitrary one is selected.
* <p>
* Hints that may be understood includes
* {@link Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER FORCE_LONGITUDE_FIRST_AXIS_ORDER},
* {@link Hints#FORCE_STANDARD_AXIS_UNITS FORCE_STANDARD_AXIS_UNITS} and
* {@link Hints#FORCE_STANDARD_AXIS_DIRECTIONS FORCE_STANDARD_AXIS_DIRECTIONS} and
* {@link Hints#VERSION VERSION}.
*
* @param authority The desired authority (e.g. "EPSG").
* @param hints An optional map of hints, or {@code null} if none.
* @return The first coordinate system authority factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link CSAuthorityFactory} interface.
*/
public static CSAuthorityFactory getCSAuthorityFactory(final String authority,
final Hints hints)
throws FactoryRegistryException
{
return getAuthorityFactory(CSAuthorityFactory.class, authority, hints,
Hints.CS_AUTHORITY_FACTORY);
}
/**
* Returns a set of all available implementations for the {@link CSAuthorityFactory} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available coordinate system authority factory implementations.
*/
public static Set<CSAuthorityFactory> getCSAuthorityFactories(final Hints hints) {
return getFactories(CSAuthorityFactory.class, hints);
}
/**
* Returns the first implementation of {@link CRSAuthorityFactory} matching the specified
* hints. If no implementation matches, a new one is created if possible or an exception is
* thrown otherwise. If more than one implementation is registered and an
* {@linkplain #setVendorOrdering ordering is set}, then the preferred
* implementation is returned. Otherwise an arbitrary one is selected.
* <p>
* Hints that may be understood includes
* {@link Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER FORCE_LONGITUDE_FIRST_AXIS_ORDER},
* {@link Hints#FORCE_STANDARD_AXIS_UNITS FORCE_STANDARD_AXIS_UNITS},
* {@link Hints#FORCE_STANDARD_AXIS_DIRECTIONS FORCE_STANDARD_AXIS_DIRECTIONS} and
* {@link Hints#VERSION VERSION}.
* <p>
* <b>TIP:</b> The EPSG official factory and the EPSG extensions (additional CRS provided by
* ESRI and others) are two distinct factories. Call to {@code getCRSAuthorityFactory("EPSG",
* null)} returns only one of those, usually the official EPSG factory. If the union of those
* two factories is wanted, then a chain of fallbacks is wanted. Consider using something like:
*
* <blockquote><code>
* {@linkplain org.geotools.referencing.factory.FallbackAuthorityFactory#create(Class,
* java.util.Collection) FallbackAuthorityFactory.create}(CRSAuthorityFactory.class,
* {@linkplain #getCRSAuthorityFactories getCRSAuthorityFactories}(hints));
* </code></blockquote>
*
* @param authority The desired authority (e.g. "EPSG").
* @param hints An optional map of hints, or {@code null} if none.
* @return The first coordinate reference system authority factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link CRSAuthorityFactory} interface.
*/
public static CRSAuthorityFactory getCRSAuthorityFactory(final String authority,
final Hints hints)
throws FactoryRegistryException
{
return getAuthorityFactory(CRSAuthorityFactory.class, authority, hints,
Hints.CRS_AUTHORITY_FACTORY);
}
/**
* Returns a set of all available implementations for the {@link CRSAuthorityFactory} interface.
* This set can be used to list the available codes known to all authorities.
* In the event that the same code is understood by more then one authority
* you will need to assume both are close enough, or make use of this set directly
* rather than use the {@link CRS#decode} convenience method.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available coordinate reference system authority factory implementations.
*/
public static Set<CRSAuthorityFactory> getCRSAuthorityFactories(final Hints hints) {
return getFactories(CRSAuthorityFactory.class, hints);
}
/**
* Returns the first implementation of {@link CoordinateOperationAuthorityFactory} matching
* the specified hints. If no implementation matches, a new one is created if possible or an
* exception is thrown otherwise. If more than one implementation is registered and an
* {@linkplain #setVendorOrdering ordering is set}, then the preferred
* implementation is returned. Otherwise an arbitrary one is selected.
*
* @param authority The desired authority (e.g. "EPSG").
* @param hints An optional map of hints, or {@code null} if none.
* @return The first coordinate operation authority factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link CoordinateOperationAuthorityFactory} interface.
*/
public static CoordinateOperationAuthorityFactory getCoordinateOperationAuthorityFactory(
final String authority, final Hints hints)
throws FactoryRegistryException
{
return getAuthorityFactory(CoordinateOperationAuthorityFactory.class, authority, hints,
Hints.COORDINATE_OPERATION_AUTHORITY_FACTORY);
}
/**
* Returns a set of all available implementations for the
* {@link CoordinateOperationAuthorityFactory} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available coordinate operation authority factory implementations.
*/
public static Set<CoordinateOperationAuthorityFactory> getCoordinateOperationAuthorityFactories(
final Hints hints)
{
return getFactories(CoordinateOperationAuthorityFactory.class, hints);
}
/**
* Returns the first implementation of {@link MathTransformFactory} matching the specified
* hints. If no implementation matches, a new one is created if possible or an exception is
* thrown otherwise. If more than one implementation is registered and an
* {@linkplain #setVendorOrdering ordering is set}, then the preferred
* implementation is returned. Otherwise an arbitrary one is selected.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return The first math transform factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link MathTransformFactory} interface.
*/
public static MathTransformFactory getMathTransformFactory(final Hints hints)
throws FactoryRegistryException
{
return getFactory(MathTransformFactory.class, hints, Hints.MATH_TRANSFORM_FACTORY);
}
/**
* Returns a set of all available implementations for the
* {@link MathTransformFactory} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available math transform factory implementations.
*/
public static Set<MathTransformFactory> getMathTransformFactories(final Hints hints) {
return getFactories(MathTransformFactory.class, hints);
}
/**
* Sets a pairwise ordering between two vendors. If one or both vendors are not
* currently registered, or if the desired ordering is already set, nothing happens
* and {@code false} is returned.
* <p>
* The example below said that an ESRI implementation (if available) is
* preferred over the Geotools one:
*
* <blockquote><code>FactoryFinder.setVendorOrdering("ESRI", "Geotools");</code></blockquote>
*
* @param vendor1 The preferred vendor.
* @param vendor2 The vendor to which {@code vendor1} is preferred.
* @return {@code true} if the ordering was set for at least one category.
*/
public static synchronized boolean setVendorOrdering(final String vendor1,
final String vendor2)
{
return getServiceRegistry().setOrdering(Factory.class, true,
new VendorFilter(vendor1),
new VendorFilter(vendor2));
}
/**
* Unsets a pairwise ordering between two vendors. If one or both vendors are not
* currently registered, or if the desired ordering is already unset, nothing happens
* and {@code false} is returned.
*
* @param vendor1 The preferred vendor.
* @param vendor2 The vendor to which {@code vendor1} is preferred.
* @return {@code true} if the ordering was unset for at least one category.
*/
public static synchronized boolean unsetVendorOrdering(final String vendor1,
final String vendor2)
{
return getServiceRegistry().setOrdering(Factory.class, false,
new VendorFilter(vendor1),
new VendorFilter(vendor2));
}
/**
* A filter for factories provided by a given vendor.
*/
private static final class VendorFilter implements ServiceRegistry.Filter {
/** The vendor to filter. */
private final String vendor;
/** Constructs a filter for the given vendor. */
public VendorFilter(final String vendor) {
this.vendor = vendor;
}
/** Returns {@code true} if the specified provider is built by the vendor. */
public boolean filter(final Object provider) {
return Citations.titleMatches(((Factory)provider).getVendor(), vendor);
}
}
/**
* Sets a pairwise ordering between two authorities. If one or both authorities are not
* currently registered, or if the desired ordering is already set, nothing happens
* and {@code false} is returned.
* <p>
* The example below said that EPSG {@linkplain AuthorityFactory authority factories}
* are preferred over ESRI ones:
*
* <blockquote><code>FactoryFinder.setAuthorityOrdering("EPSG", "ESRI");</code></blockquote>
*
* @param authority1 The preferred authority.
* @param authority2 The authority to which {@code authority1} is preferred.
* @return {@code true} if the ordering was set for at least one category.
*/
public static synchronized boolean setAuthorityOrdering(final String authority1,
final String authority2)
{
return getServiceRegistry().setOrdering(AuthorityFactory.class, true,
new AuthorityFilter(authority1),
new AuthorityFilter(authority2));
}
/**
* Unsets a pairwise ordering between two authorities. If one or both authorities are not
* currently registered, or if the desired ordering is already unset, nothing happens
* and {@code false} is returned.
*
* @param authority1 The preferred authority.
* @param authority2 The vendor to which {@code authority1} is preferred.
* @return {@code true} if the ordering was unset for at least one category.
*/
public static synchronized boolean unsetAuthorityOrdering(final String authority1,
final String authority2)
{
return getServiceRegistry().setOrdering(AuthorityFactory.class, false,
new AuthorityFilter(authority1),
new AuthorityFilter(authority2));
}
/**
* A filter for factories provided for a given authority.
*/
private static final class AuthorityFilter implements ServiceRegistry.Filter {
/** The authority to filter. */
private final String authority;
/** Constructs a filter for the given authority. */
public AuthorityFilter(final String authority) {
this.authority = authority;
}
/** Returns {@code true} if the specified provider is for the authority. */
public boolean filter(final Object provider) {
if (authority == null) {
// If the user didn't specified an authority name, then the factory to use must
// be specified explicitly through a hint (e.g. Hints.CRS_AUTHORITY_FACTORY).
return false;
}
return Citations.identifierMatches(((AuthorityFactory)provider).getAuthority(), authority);
}
}
/**
* Programmatic management of authority factories.
* Needed for user managed, not plug-in managed, authority factory.
* Also useful for test cases.
*
* @param authority The authority factory to add.
*/
public static synchronized void addAuthorityFactory(final AuthorityFactory authority) {
if (registry == null) {
scanForPlugins();
}
getServiceRegistry().registerServiceProvider(authority);
authorityNames = null;
}
/**
* Programmatic management of authority factories.
* Needed for user managed, not plug-in managed, authority factory.
* Also useful for test cases.
*
* @param authority The authority factory to remove.
*/
public static synchronized void removeAuthorityFactory(final AuthorityFactory authority) {
getServiceRegistry().deregisterServiceProvider(authority);
authorityNames = null;
}
/**
* Returns {@code true} if the specified factory is registered. A factory may have been
* registered by {@link #scanForPlugins()} if it was declared in a {@code META-INF/services}
* file, or it may have been {@linkplain #addAuthorityFactory added programmatically}.
*
* @since 2.4
*/
public static synchronized boolean isRegistered(final Factory factory) {
return factory.equals(getServiceRegistry().getServiceProviderByClass(factory.getClass()));
}
/**
* Scans for factory plug-ins on the application class path. This method is needed because the
* application class path can theoretically change, or additional plug-ins may become available.
* Rather than re-scanning the classpath on every invocation of the API, the class path is
* scanned automatically only on the first invocation. Clients can call this method to prompt
* a re-scan. Thus this method need only be invoked by sophisticated applications which
* dynamically make new plug-ins available at runtime.
*/
public static void scanForPlugins() {
synchronized (ReferencingFactoryFinder.class) {
authorityNames = null;
if (registry != null) {
registry.scanForPlugins();
}
}
GeoTools.fireConfigurationChanged();
}
/**
* List all available factory implementations in a tabular format. For each factory interface,
* the first implementation listed is the default one. This method provides a way to check the
* state of a system, usually for debugging purpose.
*
* @param out The output stream where to format the list.
* @param locale The locale for the list, or {@code null}.
* @throws IOException if an error occurs while writting to {@code out}.
*/
public static synchronized void listProviders(final Writer out, final Locale locale)
throws IOException
{
final FactoryRegistry registry = getServiceRegistry();
new FactoryPrinter().list(registry, out, locale);
}
/**
* Resets the factory finder and prepares for a new full scan of the SPI subsystems
*/
public static void reset() {
registry = null;
}
/**
* Dump to the standard output stream a list of available factory implementations.
* This method can be invoked from the command line. It provides a mean to verify
* if some implementations were found in the classpath. The syntax is:
* <BR>
* <BLOCKQUOTE><CODE>
* java org.geotools.referencing.FactoryFinder <VAR><options></VAR>
* </CODE></BLOCKQUOTE>
*
* <P>where options are:</P>
*
* <TABLE CELLPADDING='0' CELLSPACING='0'>
* <TR><TD NOWRAP><CODE>-encoding</CODE> <VAR><code></VAR></TD>
* <TD NOWRAP> Set the character encoding</TD></TR>
* <TR><TD NOWRAP><CODE>-locale</CODE> <VAR><language></VAR></TD>
* <TD NOWRAP> Set the language for the output (e.g. "fr" for French)</TD></TR>
* </TABLE>
*
* <P><strong>Note for Windows users:</strong> If the output contains strange
* symbols, try to supply an "{@code -encoding}" argument. Example:</P>
*
* <blockquote><code>
* java org.geotools.referencing.FactoryFinder -encoding Cp850
* </code></blockquote>
*
* <P>The codepage number (850 in the previous example) can be obtained from the DOS
* commande line using the "{@code chcp}" command with no arguments.</P>
*
* @param args Command line arguments.
*/
public static void main(String[] args) {
final Arguments arguments = new Arguments(args);
args = arguments.getRemainingArguments(0);
try {
listProviders(arguments.out, arguments.locale);
} catch (Exception exception) {
exception.printStackTrace(arguments.err);
}
}
}