/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2007-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 java.util.Locale; import java.util.Iterator; import java.util.Collection; import java.io.Writer; import java.io.IOException; import java.awt.RenderingHints; // For javadoc import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.geotoolkit.lang.Configuration; import org.geotoolkit.lang.Static; import org.geotoolkit.lang.Debug; import org.geotoolkit.internal.Listeners; /** * Static methods relative to the factories. There are many aspects in the way Geotk manages * factories on a system-wide basis: * * <ul> * <li><p><b>Default settings:</b> They are handled as the default hint values set on a system-wide * basis by {@link Hints#getSystemDefault Hints.get}/{@link Hints#putSystemDefault put}/{@link * Hints#removeSystemDefault removeSystemDefault} methods. The default values can be provided * in application code.</p></li> * * <li><p><b>Integration plugins:</b> If hosting Geotk in a alternate plugin system such as * Spring or OSGi, application may needs to register additional "Factory Iterators" for Geotk * to search using the {@link #addFactoryIteratorProvider addFactoryIteratorProvider} method.</p></li> * </ul> * * @author Martin Desruisseaux (IRD, Geomatys) * @author Jody Garnett (Refractions) * @version 3.20 * * @since 2.4 * @module * * @deprecated Will be replaced by a more standard dependency injection mechanism. */ @Deprecated public final class Factories extends Static { /** * Object to inform about hints changes. * We use the Swing utility listener list since it is lightweight and thread-safe. * Note that it doesn't involve any dependency to the remaining of Swing library. * (Note: this assumption may change with JDK8 modularization) */ private static ChangeListener[] listeners; /** * Do not allow instantiation of this class. */ private Factories() { } /** * Adds the specified listener to the list of objects to inform when a * system-wide configuration changed. The methods which may fire a * {@linkplain ChangeEvent change event} are: * <p> * <ul> * <li>{@link Hints#putSystemDefault(RenderingHints.Key, Object)}</li> * <li>{@link Hints#removeSystemDefault(RenderingHints.Key)}</li> * <li>{@link #addFactoryIteratorProvider(FactoryIteratorProvider)}</li> * <li>{@link #removeFactoryIteratorProvider(FactoryIteratorProvider)}</li> * </ul> * * @param listener The listener to add. */ public static synchronized void addChangeListener(final ChangeListener listener) { listeners = Listeners.addListener(listener, listeners); } /** * Removes the specified listener from the list of objects to inform when a system-wide * configuration changed. * * @param listener The listener to remove. */ public static synchronized void removeChangeListener(final ChangeListener listener) { listeners = Listeners.removeListener(listener, listeners); } /** * Informs every listeners that a system-wide configuration changed. * This method is invoked by the static methods that are annotated * with {@link Configuration}. Users should not need to invoke this * method themselves. * * @param source The source of this event. */ static void fireConfigurationChanged(final Class<?> source) { final ChangeListener[] list; synchronized (Factories.class) { list = listeners; } Listeners.fireChanged(source, list); } /** * Adds an alternative way to search for factory implementations. {@link FactoryRegistry} has * a default mechanism bundled in it, which uses the content of all {@code META-INF/services} * directories found on the classpath. This {@code addFactoryIteratorProvider} method allows * to specify additional discovery algorithms. It may be useful in the context of some * frameworks that use the <cite>constructor injection</cite> pattern, like the * <a href="http://www.springframework.org/">Spring framework</a>. * <p> * If the given provider was not already registered, then this method notifies * every listeners registered with {@link #addChangeListener(ChangeListener)}. * * @param provider A new provider for factory iterators. * * @level advanced */ @Configuration public static void addFactoryIteratorProvider(final FactoryIteratorProvider provider) { if (FactoryIteratorProviders.GLOBAL.addFactoryIteratorProvider(provider)) { fireConfigurationChanged(Factories.class); } } /** * Removes a provider that was previously {@linkplain #addFactoryIteratorProvider added}. * Note that factories already obtained from the specified provider will not be * {@linkplain FactoryRegistry#deregisterServiceProvider deregistered} by this method. * <p> * If the given provider was found, then this method notifies every listeners * registered with {@link #addChangeListener(ChangeListener)}. * * @param provider The provider to remove. * * @level advanced */ @Configuration public static void removeFactoryIteratorProvider(final FactoryIteratorProvider provider) { if (FactoryIteratorProviders.GLOBAL.removeFactoryIteratorProvider(provider)) { fireConfigurationChanged(Factories.class); } } /** * Lists 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 registries Where the factories are registered. * @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 writing to {@code out}. * * @see FactoryFinder#listProviders * * @since 3.00 */ @Debug public static void listProviders(final Collection<FactoryRegistry> registries, final Writer out, final Locale locale) throws IOException { new FactoryPrinter(registries).list(out, locale); } /** * Returns an iterator giving precedence to classes loaded by the given class loaderĀ or one * of its parents/children. This method is used as a safety when there is a risk that many * copies of the same library (for example in a web container) register the same JDK service. * * {@section Example with Image I/O} * The {@code geotk-coverageio} module defines new {@link javax.imageio.ImageReader} * implementations, which are automatically discovered by the standard JDK through the * {@code META-INF/services/} mechanism. If a web container contains two copies of the * Geotoolkit.org library - one for each web application - then all image formats like * {@link org.geotoolkit.image.io.plugin.NetcdfImageReader} will be registered twice, * because the JVM will find two {@code NetcdfImageReader.Spi} classes loaded by two * different class loaders. * <p> * The service provider instance returned by {@link javax.imageio.spi.IIORegistry} may * be somewhat random in the above scenario. This leads to subtle and hard-to-identify * bugs. This method reduces the risk by giving precedence to SPI classes loaded by the * same class loader than the application. However users are still encouraged to load, * for each running JVM, only one copy of the Geotoolkit.org library to be shared by all * applications. * * @param <T> The type of elements in the iterator. * @param classLoader The desired class loader, or {@code null} for the bootstrap class loader. * @param iterator The iterator to wrap. * @return An iterator giving precedences to classes loaded by the given class loader or * one of its parents/children. * * @since 3.20 */ public static <T> Iterator<T> orderForClassLoader(final ClassLoader classLoader, final Iterator<T> iterator) { if (classLoader == null || iterator == null || (iterator instanceof OrderedIterator<?> && ((OrderedIterator<?>) iterator).classLoader == classLoader)) { return iterator; } return new OrderedIterator<>(classLoader, iterator); } }