/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2004-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2009-2012, Geomatys
*
* 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.geotoolkit.factory;
import org.opengis.util.Factory;
import org.opengis.util.NameFactory;
import org.opengis.style.StyleFactory;
import org.opengis.filter.FilterFactory;
import org.opengis.referencing.cs.CSFactory;
import org.opengis.referencing.crs.CRSFactory;
import org.opengis.referencing.datum.DatumFactory;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.CoordinateOperationFactory;
import org.opengis.metadata.citation.CitationFactory;
import org.opengis.geometry.PositionFactory;
import org.opengis.geometry.primitive.PrimitiveFactory;
import org.opengis.geometry.coordinate.GeometryFactory;
import org.opengis.geometry.complex.ComplexFactory;
import org.opengis.geometry.aggregate.AggregateFactory;
import org.opengis.temporal.TemporalFactory;
import org.geotoolkit.lang.Static;
import org.geotoolkit.lang.Configuration;
import org.apache.sis.internal.system.DefaultFactories;
/**
* Defines static methods used to access the application {@linkplain Factory factory}
* implementations. This class provide access to the following services:
* <p>
* <ul>
* <li><b>Utilities</b></li><ul>
* <li>{@link NameFactory}</li>
* </ul>
* <li><b>Metadata</b></li><ul>
* <li>{@link CitationFactory} (metadata)</li>
* </ul>
* <li><b>Referencing</b></li><ul>
* <li>{@link CoordinateOperationFactory}</li>
* <li>{@link CRSFactory}</li>
* <li>{@link CSFactory}</li>
* <li>{@link DatumFactory}</li>
* <li>{@link MathTransformFactory}</li>
* </ul>
* <li><b>Geometry</b></li><ul>
* <li>{@link PositionFactory}</li>
* <li>{@link PrimitiveFactory}</li>
* <li>{@link GeometryFactory}</li>
* <li>{@link ComplexFactory}</li>
* <li>{@link AggregateFactory}</li>
* </ul>
* <li><b>Feature</b></li><ul>
* <li>{@link FeatureTypeFactory}</li>
* <li>{@link FeatureFactory}</li>
* <li>{@link FilterFactory}</li>
* <li>{@link StyleFactory}</li>
* </ul>
* </ul>
* <p>
* This class is thread-safe but may have a high contention. Applications (or computational units in
* an application) are encouraged to save references to the factories they need in their own private
* fields. They would gain in performance and in stability, since the set of available factories may
* change during the execution.
* <p>
* Some methods like {@link #setVendorOrdering setVendorOrdering} have a system-wide effect. Most
* applications should not need to invoke them. If an application needs to protect itself against
* configuration changes that may be performed by an other application sharing the Geotk library,
* it shall manage its own instance of {@link FactoryRegistry}. This {@code FactoryFinder} class
* itself is just a convenience wrapper around a {@code FactoryRegistry} instance.
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @module
*
* @deprecated Will be replaced by a more standard dependency injection mechanism.
*/
@Deprecated
public class FactoryFinder extends Static {
static {
org.geotoolkit.internal.io.JNDI.install();
}
/**
* Do not allow instantiation of this class.
*/
FactoryFinder() {
}
/**
* Returns new hints that combine user supplied hints with the default hints.
* If a hint is specified in both user and default hints, then user hints have
* precedence.
* <p>
* In a previous Geotk version, a somewhat convolved lookup was performed here.
* Now that default hints are filled right at {@link Hints} creation time, this
* method just needs to ensure that the given hints are non-null.
* <p>
* This method returns an object on which {@code hints.remove(FILTER_KEY)} can
* be invoked, assuming that the map is not modified in a background thread.
*
* @param hints The user hints, or {@code null} for the default ones.
* @return The hints to use (never {@code null}).
*/
static Hints mergeSystemHints(Hints hints) {
if (hints == null) {
hints = new Hints();
} else if (hints.getClass() != Hints.class) {
hints = hints.clone();
}
return hints;
}
/**
* Returns a provider of the specified category.
*
* @param category The factory category.
* @param hints An optional map of hints, or {@code null} for the default ones.
* @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 <T> T getFactory(final Class<T> category, Hints hints, final Hints.ClassKey key)
throws FactoryRegistryException
{
hints = mergeSystemHints(hints);
final Object factory = hints.get(key);
if (category.isInstance(factory)) {
return (T) factory;
}
return DefaultFactories.forBuildin(category);
}
/**
* Returns the first implementation of {@link NameFactory} matching the specified hints.
*
* @param hints An optional map of hints, or {@code null} for the default ones.
* @return The first name factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link NameFactory} interface.
*
* @since 3.00
* @category Metadata
*
* @see Hints#NAME_FACTORY
*/
public static NameFactory getNameFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(NameFactory.class, hints, Hints.NAME_FACTORY);
}
/**
* Returns the first implementation of {@link CitationFactory} matching the specified hints.
*
* @param hints An optional map of hints, or {@code null} for the default ones.
* @return The first citation factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link CitationFactory} interface.
*
* @since 3.00
* @category Metadata
*
* @see Hints#CITATION_FACTORY
*/
public static CitationFactory getCitationFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(CitationFactory.class, hints, Hints.CITATION_FACTORY);
}
/**
* 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} for the default ones.
* @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.
*
* @category Referencing
*
* @see Hints#DATUM_FACTORY
*/
public static DatumFactory getDatumFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(DatumFactory.class, hints, Hints.DATUM_FACTORY);
}
/**
* 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} for the default ones.
* @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.
*
* @category Referencing
*
* @see Hints#CS_FACTORY
*/
public static CSFactory getCSFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(CSFactory.class, hints, Hints.CS_FACTORY);
}
/**
* 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} for the default ones.
* @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.
*
* @category Referencing
*
* @see Hints#CRS_FACTORY
*/
public static CRSFactory getCRSFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(CRSFactory.class, hints, Hints.CRS_FACTORY);
}
/**
* 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} for the default ones.
* @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.
*
* @category Referencing
*
* @see Hints#COORDINATE_OPERATION_FACTORY
*/
public static CoordinateOperationFactory getCoordinateOperationFactory(final Hints hints)
throws FactoryRegistryException
{
return getFactory(CoordinateOperationFactory.class, hints, Hints.COORDINATE_OPERATION_FACTORY);
}
/**
* 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} for the default ones.
* @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.
*
* @category Referencing
*
* @see Hints#MATH_TRANSFORM_FACTORY
*/
public static MathTransformFactory getMathTransformFactory(final Hints hints)
throws FactoryRegistryException
{
return getFactory(MathTransformFactory.class, hints, Hints.MATH_TRANSFORM_FACTORY);
}
/**
* Returns the first implementation of {@link TemporalFactory} matching the specified hints.
*
* @param hints An optional map of hints, or {@code null} for the default ones.
* @return The first temporal factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link TemporalFactory} interface.
*
* @since 3.18
* @category Temporal
*
* @see Hints#TEMPORAL_FACTORY
*/
public static TemporalFactory getTemporalFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(TemporalFactory.class, hints, Hints.TEMPORAL_FACTORY);
}
/**
* Returns the first implementation of {@link PositionFactory} matching the specified hints.
*
* @param hints An optional map of hints, or {@code null} for the default ones.
* @return The first position factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link PositionFactory} interface.
*
* @since 3.01
* @category Geometry
*
* @see Hints#POSITION_FACTORY
*/
public static PositionFactory getPositionFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(PositionFactory.class, hints, Hints.POSITION_FACTORY);
}
/**
* Returns the first implementation of {@link PrimitiveFactory} matching the specified hints.
*
* @param hints An optional map of hints, or {@code null} for the default ones.
* @return The first primitive factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link PrimitiveFactory} interface.
*
* @since 3.01
* @category Geometry
*
* @see Hints#PRIMITIVE_FACTORY
*/
public static PrimitiveFactory getPrimitiveFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(PrimitiveFactory.class, hints, Hints.PRIMITIVE_FACTORY);
}
/**
* Returns the first implementation of {@link GeometryFactory} matching the specified hints.
*
* @param hints An optional map of hints, or {@code null} for the default ones.
* @return The first geometry factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link GeometryFactory} interface.
*
* @since 3.01
* @category Geometry
*
* @see Hints#GEOMETRY_FACTORY
*/
public static GeometryFactory getGeometryFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(GeometryFactory.class, hints, Hints.GEOMETRY_FACTORY);
}
/**
* Returns the first implementation of {@link ComplexFactory} matching the specified hints.
*
* @param hints An optional map of hints, or {@code null} for the default ones.
* @return The first complex factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link ComplexFactory} interface.
*
* @since 3.01
* @category Geometry
*
* @see Hints#COMPLEX_FACTORY
*/
public static ComplexFactory getComplexFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(ComplexFactory.class, hints, Hints.COMPLEX_FACTORY);
}
/**
* Returns the first implementation of {@link AggregateFactory} matching the specified hints.
*
* @param hints An optional map of hints, or {@code null} for the default ones.
* @return The first aggregate factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link ComplexFactory} interface.
*
* @since 3.01
* @category Geometry
*
* @see Hints#AGGREGATE_FACTORY
*/
public static AggregateFactory getAggregateFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(AggregateFactory.class, hints, Hints.AGGREGATE_FACTORY);
}
/**
* Returns the first implementation of {@link FilterFactory} matching the specified hints.
*
* @param hints An optional map of hints, or {@code null} for the default ones.
* @return The first filter factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link FilterFactory} interface.
*
* @since 3.00
* @category Feature
*
* @see Hints#FILTER_FACTORY
*/
public static FilterFactory getFilterFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(FilterFactory.class, hints, Hints.FILTER_FACTORY);
}
/**
* Returns the first implementation of {@link StyleFactory} matching the specified hints.
*
* @param hints An optional map of hints, or {@code null} for the default ones.
* @return The first style factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link StyleFactory} interface.
*
* @since 3.00
* @category Feature
*
* @see Hints#STYLE_FACTORY
*/
public static StyleFactory getStyleFactory(final Hints hints) throws FactoryRegistryException {
return getFactory(StyleFactory.class, hints, Hints.STYLE_FACTORY);
}
/**
* 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.
*
* @level advanced
*/
@Configuration
public static void scanForPlugins() {
DefaultFactories.fireClasspathChanged();
Factories.fireConfigurationChanged(FactoryFinder.class);
}
}