/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-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.factory;
import java.util.Arrays;
import java.util.Set;
import org.geotools.data.FeatureLockFactory;
import org.geotools.data.FileDataStoreFactorySpi;
import org.geotools.feature.FeatureCollections;
import org.geotools.filter.FunctionFactory;
import org.geotools.resources.LazySet;
import org.geotools.styling.StyleFactory;
import org.opengis.feature.FeatureFactory;
import org.opengis.feature.type.FeatureTypeFactory;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Function;
/**
* Defines static methods used to access the application's default implementation for some
* common factories. Those "common" factories comprise the {@linkplain StyleFactory style}
* and {@linkplain FilterFactory filter} factories. Note that some specialized factories
* finder like {@linkplain org.geotools.referencing.ReferencingFactoryFinder referencing} and
* {@linkplain org.geotools.coverage.GeometryFactoryFinder coverage} are defined in specialized
* classes.
* <p>
* <b>Tip:</b> The {@link BasicFactories} classes provides an other way to access the various
* factories from a central point.
*
* @since 2.4
*
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux
* @author Jody Garnett
*/
public final class CommonFactoryFinder extends FactoryFinder {
/**
* The service registry for this manager.
* Will be initialized only when first needed.
*/
private static FactoryRegistry registry;
/**
* Do not allows any instantiation of this class.
*/
private CommonFactoryFinder() {
// singleton
}
/**
* Returns the service registry. The registry will be created the first
* time this method is invoked.
*/
@SuppressWarnings("deprecation")
private static FactoryRegistry getServiceRegistry() {
assert Thread.holdsLock(CommonFactoryFinder.class);
if (registry == null) {
registry = new FactoryCreator(Arrays.asList(new Class<?>[] {
StyleFactory.class,
FilterFactory.class,
FeatureLockFactory.class,
FileDataStoreFactorySpi.class,
// FunctionImpl.class, // TODO: remove
// FunctionExpression.class,//TODO: remove
Function.class,
FunctionFactory.class,
FeatureFactory.class,
FeatureTypeFactory.class,
FeatureCollections.class}));
}
return registry;
}
/**
* Returns the first implementation of {@link StyleFactory} matching the specified hints.
* If no implementation matches, a new one is created if possible or an exception is thrown
* otherwise.
*
* @param hints An optional map of hints, or {@code null} if none.
* @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.
*
* @see Hints#STYLE_FACTORY
*/
public static StyleFactory getStyleFactory(Hints hints)
throws FactoryRegistryException
{
hints = mergeSystemHints(hints);
return (StyleFactory) lookup(StyleFactory.class, hints, Hints.STYLE_FACTORY);
}
/**
* Returns a set of all available implementations for the {@link StyleFactory} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available style factory implementations.
*/
public static synchronized Set<StyleFactory> getStyleFactories(Hints hints) {
hints = mergeSystemHints(hints);
return new LazySet<StyleFactory>(getServiceRegistry().getServiceProviders(
StyleFactory.class, null, hints));
}
/**
* Returns a set of all available implementations for the {@link Function} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available function expression implementations.
*/
public static synchronized Set<Function> getFunctions(Hints hints) {
hints = mergeSystemHints(hints);
return new LazySet<Function>(getServiceRegistry().getServiceProviders(
Function.class, null, hints));
}
/**
* Returns a set of all available implementations of {@link FunctionFactory}.
*
* @param hints An optional map of hints, or {@code null} if none.
*
* @return Set of available function factory implementations.
*/
public static synchronized Set<FunctionFactory> getFunctionFactories(Hints hints) {
hints = mergeSystemHints(hints);
return new LazySet<FunctionFactory>(getServiceRegistry().getServiceProviders(
FunctionFactory.class, null, hints));
}
/**
* Returns the first implementation of {@link FeatureLockFactory} matching the specified hints.
* If no implementation matches, a new one is created if possible or an exception is thrown
* otherwise.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return The first feature lock factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link FeatureLockFactory} interface.
*
* @see Hints#FEATURE_LOCK_FACTORY
* @deprecated FeautreLockFactory is no longer needed; please create a FeatureLock directly
*/
public static FeatureLockFactory getFeatureLockFactory(Hints hints) {
hints = mergeSystemHints(hints);
return (FeatureLockFactory) lookup(FeatureLockFactory.class, hints, Hints.FEATURE_LOCK_FACTORY);
}
/**
* Returns a set of all available implementations for the {@link FeatureLockFactory} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set<FeatureLockFactory> of available style factory implementations.
* @deprecated FeatureLockFactory is no longer needed
*/
public static synchronized Set<FeatureLockFactory> getFeatureLockFactories(Hints hints) {
hints = mergeSystemHints(hints);
return new LazySet<FeatureLockFactory>(getServiceRegistry().getServiceProviders(
FeatureLockFactory.class, null, hints));
}
/**
* Returns a set of all available implementations for the {@link FileDataStoreFactorySpi} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available file data store factory implementations.
*/
public static synchronized Set<FileDataStoreFactorySpi> getFileDataStoreFactories(Hints hints) {
hints = mergeSystemHints(hints);
return new LazySet<FileDataStoreFactorySpi>(getServiceRegistry().getServiceProviders(
FileDataStoreFactorySpi.class, null, hints));
}
/** Return the first implementation of {@link FeatureFactory} matching the specified hints.
* <p>
* If no implementation matches, a new one is created if possible or an exception is thrown.
*
* @param hints An optional map of hints; or {@code null} if none
* @return Instance of FeatureFactory matching the supplied hints
* @throws FactoryRegistryException if no implementation could be provided
* @see Hints#FEATURE_FACTORY
*/
public static FeatureFactory getFeatureFactory(Hints hints) {
hints = mergeSystemHints(hints);
if(hints.get(Hints.FEATURE_FACTORY) == null){
try {
Class<?> lenient = Class.forName("org.geotools.feature.LenientFeatureFactoryImpl");
hints.put(Hints.FEATURE_FACTORY, lenient );
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return (FeatureFactory) lookup(FeatureFactory.class, hints, Hints.FEATURE_FACTORY);
}
/** Return the first implementation of {@link FeatureTypeFactory} matching the specified hints.
* <p>
* If no implementation matches, a new one is created if possible or an exception is thrown.
*
* @param hints An optional map of hints; or {@code null} if none
* @return Instance of FeatureTypeFactory matching the supplied hints
* @throws FactoryRegistryException if no implementation could be provided
* @see Hints#FEATURE_TYPE_FACTORY
*/
public static FeatureTypeFactory getFeatureTypeFactory(Hints hints) {
hints = mergeSystemHints(hints);
return (FeatureTypeFactory) lookup(FeatureTypeFactory.class, hints, Hints.FEATURE_TYPE_FACTORY);
}
/**
* Returns the first implementation of {@link FeatureCollections} matching the specified hints.
* If no implementation matches, a new one is created if possible or an exception is thrown
* otherwise.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return The first feature collections that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link FeatureCollections} interface.
*
* @see Hints#FEATURE_COLLECTIONS
*/
public static FeatureCollections getFeatureCollections(Hints hints) {
hints = mergeSystemHints(hints);
return (FeatureCollections) lookup(FeatureCollections.class, hints, Hints.FEATURE_COLLECTIONS);
}
/**
* Returns a set of all available implementations for the {@link FeatureCollections} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available feature collections implementations.
*/
public static synchronized Set<FeatureCollections> getFeatureCollectionsSet(Hints hints) {
hints = mergeSystemHints(hints);
return new LazySet<FeatureCollections>(getServiceRegistry().getServiceProviders(
FeatureCollections.class, null, hints));
}
/**
* Returns the first implementation of {@link FilterFactory} matching the specified hints.
* If no implementation matches, a new one is created if possible or an exception is thrown
* otherwise.
*
* @param hints An optional map of hints, or {@code null} if none.
* @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.
*
* @see Hints#FILTER_FACTORY
*/
public static FilterFactory getFilterFactory(Hints hints)
throws FactoryRegistryException
{
hints = mergeSystemHints(hints);
return (FilterFactory) lookup(FilterFactory.class, hints, Hints.FILTER_FACTORY);
}
/**
* Looks up a certain factory using two methods:
* <ul><li>First and un-synchronized lookup in the hints, should the user have provided the
* preferred factroy</li>
* <li>A standard SPI registry scan, which has to be fully synchronized</li>
* @param category
* @param hints
* @param key
* @return
*/
private static <T> T lookup(Class<T> category, Hints hints, Hints.Key key) {
// nulls?
if(hints == null || key == null) {
return null;
}
// see if the user expressed a preference in the hints
final Object hint = hints.get(key);
if (hint != null) {
if (category.isInstance(hint)) {
return category.cast(hint);
}
}
// otherwise do the lousy slow system scan
synchronized (CommonFactoryFinder.class) {
return getServiceRegistry().getServiceProvider(category, null, hints, key);
}
}
/**
* Returns a set of all available implementations for the {@link FilterFactory} interface.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return Set of available filter factory implementations.
*/
public static synchronized Set<FilterFactory> getFilterFactories(Hints hints) {
hints = mergeSystemHints(hints);
return new LazySet<FilterFactory>(getServiceRegistry().getServiceProviders(
FilterFactory.class, null, hints));
}
/**
* Returns the first implementation of {@link FilterFactory2} matching the specified hints.
* This is a convenience method invoking {@link #getFilterFactory} with a hint value set
* for requerying a {@link FactoryFilter2} implementation.
*
* @param hints An optional map of hints, or {@code null} if none.
* @return The first filter factory that matches the supplied hints.
* @throws FactoryRegistryException if no implementation was found or can be created for the
* {@link FilterFactory2} interface.
*
* @see Hints#FILTER_FACTORY
*/
public static FilterFactory2 getFilterFactory2(Hints hints)
throws FactoryRegistryException
{
hints = mergeSystemHints(hints);
final Object h = hints.get(Hints.FILTER_FACTORY);
if (!(h instanceof Class ? FilterFactory2.class.isAssignableFrom((Class<?>) h)
: h instanceof FilterFactory2))
{
/*
* Add the hint value only if the user didn't provided a suitable hint.
* In any case, do not change the user-supplied hints; clone them first.
*/
hints = new Hints(hints);
hints.put(Hints.FILTER_FACTORY, FilterFactory2.class);
}
return (FilterFactory2) getFilterFactory(hints);
}
/**
* 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 synchronized void scanForPlugins() {
if (registry != null) {
registry.scanForPlugins();
}
}
/**
* Resets the factory finder and prepares for a new full scan of the SPI subsystems
*/
public static void reset() {
FactoryRegistry copy = registry;
registry = null;
if(copy != null) {
copy.deregisterAll();
}
}
}