/* * 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.Set; import java.util.LinkedHashSet; import org.apache.sis.util.ArraysExt; /** * The list of registered {@linkplain FactoryIteratorProvider factory iterator providers}. * * @author Martin Desruisseaux (IRD) * @since 2.4 * * @version 3.00 * @module */ final class FactoryIteratorProviders { /** * The system-wide configuration. This is the instance configured by * the public static methods provided in this class. */ static final FactoryIteratorProviders GLOBAL = new FactoryIteratorProviders(); /** * Incremented every time a modification is performed. There is no need to use * {@link java.util.concurrent.atomic.AtomicInteger} because all access to this * field will be done in a synchronized block. */ private int modifications = 0; /** * Alternative scanning methods used by {@link FactoryRegistry#scanForPlugins(Collection,Class)} * in addition of the default lookup mechanism. Will be created only when first needed. */ private Set<FactoryIteratorProvider> iteratorProviders; /** * Creates an initially empty set of factories. */ FactoryIteratorProviders() { } /** * Synchronizes the content of the {@link #iteratorProviders} map with the {@linkplain #GLOBAL * global} one. New providers are returned for later {@linkplain FactoryRegistry#register * registration}. Note that this method is typically invoked in a different thread than * {@link FactoryIteratorProviders} public static method calls. * * @return The new iterators providers {@linkplain #addFactoryIteratorProvider added} since * the last time this method was invoked, or {@code null} if none. */ final FactoryIteratorProvider[] synchronizeIteratorProviders() { /* * Do not synchronize "this". Only the GLOBAL instance needs to be synchronized. We * make no thread-safety guarantee for the others, as in the FactoryRegistry contract. */ FactoryIteratorProvider[] newProviders = null; int count = 0; synchronized (GLOBAL) { if (modifications == GLOBAL.modifications) { return null; } modifications = GLOBAL.modifications; if (GLOBAL.iteratorProviders == null) { /* * Should never happen. If GLOBAL.iteratorProviders was null, then every * 'modifications' count should be 0 and this method should have returned 'null'. */ throw new AssertionError(modifications); } /* * If 'removeFactoryIteratorProvider(...)' has been invoked since the last time * this method was run, then synchronize 'iteratorProviders' accordingly. Current * implementation do not unregister the factories that were created by those iterators. */ if (iteratorProviders != null) { iteratorProviders.retainAll(GLOBAL.iteratorProviders); } else if (!GLOBAL.iteratorProviders.isEmpty()) { iteratorProviders = new LinkedHashSet<>(); } /* * If 'addFactoryIteratorProvider(...)' has been invoked since the last time * this method was run, then synchronize 'iteratorProviders' accordingly. We * keep trace of new providers in order to allow 'FactoryRegistry' to use them * for an immediate scanning. */ int remaining = GLOBAL.iteratorProviders.size(); for (final FactoryIteratorProvider candidate : GLOBAL.iteratorProviders) { if (iteratorProviders.add(candidate)) { if (newProviders == null) { newProviders = new FactoryIteratorProvider[remaining]; } newProviders[count++] = candidate; } remaining--; } } // Note: newProviders may be null. return ArraysExt.resize(newProviders, count); } /** * Adds an alternative way to search for factory implementations. The public * facade for this method is {@link Factories#addFactoryIteratorProvider}. * * @param provider A new provider for factory iterators. * @return {@code true} if the given provider has been added, or {@code false} * if it was already present. */ synchronized boolean addFactoryIteratorProvider(FactoryIteratorProvider provider) { if (iteratorProviders == null) { iteratorProviders = new LinkedHashSet<>(); } if (iteratorProviders.add(provider)) { modifications++; return true; } return false; } /** * 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. * * @param provider The provider to remove. * @return {@code true} if the given provider has been removed, or {@code false} * if it was not present. */ synchronized boolean removeFactoryIteratorProvider(FactoryIteratorProvider provider) { if (iteratorProviders != null) { if (iteratorProviders.remove(provider)) { modifications++; return true; } } return false; } /** * Returns all iterator providers. This method do not returns any live collection * since the array will be used outside the synchronized block. */ synchronized FactoryIteratorProvider[] getIteratorProviders() { if (iteratorProviders == null) { return new FactoryIteratorProvider[0]; } return iteratorProviders.toArray(new FactoryIteratorProvider[iteratorProviders.size()]); } }