001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2007, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.factory;
017:
018: // J2SE dependencies
019: import java.util.Iterator;
020: import java.util.Set;
021: import java.util.LinkedHashSet;
022:
023: // Geotools dependencies
024: import org.geotools.resources.XArray;
025:
026: /**
027: * Utility methods that apply to all {@linkplain FactoryRegistry factory registries}.
028: *
029: * @since 2.4 PENDING PROPOSAL
030: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/factory/Factories.java $
031: * @version $Id: Factories.java 25406 2007-05-03 18:08:10Z desruisseaux $
032: * @author Martin Desruisseaux
033: *
034: * @deprecated Consider moving those methods to {@link GeoTools}. We should also remove
035: * {@link FactoryRegistry#globalConfiguration} and relies on listeners instead.
036: */
037: public final class Factories {
038: /**
039: * The system-wide configuration. This is the instance configured by
040: * the public static methods provided in this class.
041: */
042: private static final Factories GLOBAL = new Factories();
043:
044: /**
045: * Incremented every time a modification is performed.
046: */
047: private int modifications = 0;
048:
049: /**
050: * Alternative scanning methods used by {@link FactoryRegistry#scanForPlugins(Collection,Class)}
051: * in addition of the default lookup mechanism. Will be created only when first needed.
052: */
053: private Set/*<FactoryIteratorProvider>*/iteratorProviders;
054:
055: /**
056: * Creates an initially empty set of factories.
057: */
058: Factories() {
059: }
060:
061: /**
062: * Synchronizes the content of the {@link #iteratorProviders} map with the {@linkplain #GLOBAL
063: * global} one. New providers are returned for later {@linkplain FactoryRegistry#register
064: * registration}. Note that this method is typically invoked in a different thread than
065: * {@link Factories} public static method calls.
066: *
067: * @return The new iterators providers {@linkplain #addFactoryIteratorProvider added} since
068: * the last time this method was invoked, or {@code null} if none.
069: */
070: final FactoryIteratorProvider[] synchronizeIteratorProviders() {
071: FactoryIteratorProvider[] newProviders = null;
072: int count = 0;
073: synchronized (GLOBAL) {
074: if (modifications == GLOBAL.modifications) {
075: return null;
076: }
077: modifications = GLOBAL.modifications;
078: if (GLOBAL.iteratorProviders == null) {
079: /*
080: * Should never happen. If GLOBAL.iteratorProviders was null, then every
081: * 'modifications' count should be 0 and this method should have returned 'null'.
082: */
083: throw new AssertionError(modifications);
084: }
085: /*
086: * If 'Factories.removeFactoryIteratorProvider(...)' has been invoked since the last
087: * time this method was run, then synchronize 'iteratorProviders' accordingly. Current
088: * implementation do not unregister the factories that were created by those iterators.
089: */
090: if (iteratorProviders != null) {
091: iteratorProviders.retainAll(GLOBAL.iteratorProviders);
092: } else if (!GLOBAL.iteratorProviders.isEmpty()) {
093: iteratorProviders = new LinkedHashSet();
094: }
095: /*
096: * If 'Factories.addFactoryIteratorProvider(...)' has been invoked since the last
097: * time this method was run, then synchronize 'iteratorProviders' accordingly. We
098: * keep trace of new providers in order to allow 'FactoryRegistry' to use them for
099: * a immediate scanning.
100: */
101: int remaining = GLOBAL.iteratorProviders.size();
102: for (final Iterator it = GLOBAL.iteratorProviders
103: .iterator(); it.hasNext();) {
104: final FactoryIteratorProvider candidate = (FactoryIteratorProvider) it
105: .next();
106: if (iteratorProviders.add(candidate)) {
107: if (newProviders == null) {
108: newProviders = new FactoryIteratorProvider[remaining];
109: }
110: newProviders[count++] = candidate;
111: }
112: remaining--;
113: }
114: }
115: // Note: newProviders may be null.
116: return (FactoryIteratorProvider[]) XArray.resize(newProviders,
117: count);
118: }
119:
120: /**
121: * Adds an alternative way to search for factory implementations. {@link FactoryRegistry} has
122: * a default mechanism bundled in it, which uses the content of all {@code META-INF/services}
123: * directories found on the classpath. This {@code addFactoryIteratorProvider} method allows
124: * to specify additional discovery algorithms. It may be useful in the context of some
125: * frameworks that use the <cite>constructor injection</cite> pattern, like the
126: * <a href="http://www.springframework.org/">Spring framework</a>.
127: *
128: * @deprecated Moved to {@link GeoTools} class.
129: */
130: public static void addFactoryIteratorProvider(
131: FactoryIteratorProvider provider) {
132: synchronized (GLOBAL) {
133: if (GLOBAL.iteratorProviders == null) {
134: GLOBAL.iteratorProviders = new LinkedHashSet();
135: }
136: if (GLOBAL.iteratorProviders.add(provider)) {
137: GLOBAL.modifications++;
138: }
139: }
140: }
141:
142: /**
143: * Removes a provider that was previously {@linkplain #addFactoryIteratorProvider added}.
144: * Note that factories already obtained from the specified provider will not be
145: * {@linkplain FactoryRegistry#deregisterServiceProvider deregistered} by this method.
146: *
147: * @deprecated Moved to {@link GeoTools} class.
148: */
149: public static void removeFactoryIteratorProvider(
150: FactoryIteratorProvider provider) {
151: synchronized (GLOBAL) {
152: if (GLOBAL.iteratorProviders != null) {
153: if (GLOBAL.iteratorProviders.remove(provider)) {
154: GLOBAL.modifications++;
155: }
156: }
157: }
158: }
159:
160: /**
161: * Returns all iterator providers. This method do not returns any live collection
162: * since the array will be used outside the synchronized block.
163: */
164: static FactoryIteratorProvider[] getIteratorProviders() {
165: synchronized (GLOBAL) {
166: if (GLOBAL.iteratorProviders == null) {
167: return new FactoryIteratorProvider[0];
168: }
169: return (FactoryIteratorProvider[]) GLOBAL.iteratorProviders
170: .toArray(new FactoryIteratorProvider[GLOBAL.iteratorProviders
171: .size()]);
172: }
173: }
174: }
|