0001: /*
0002: * GeoTools - OpenSource mapping toolkit
0003: * http://geotools.org
0004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation;
0009: * version 2.1 of the License.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: */
0016: package org.geotools.factory;
0017:
0018: // J2SE dependencies
0019: import java.util.*;
0020: import java.util.logging.Level;
0021: import java.util.logging.LogRecord;
0022: import java.util.logging.Logger;
0023: import java.lang.ref.Reference;
0024: import java.awt.RenderingHints;
0025: import javax.imageio.spi.ServiceRegistry;
0026:
0027: // Geotools dependencies
0028: import org.geotools.resources.Utilities;
0029: import org.geotools.resources.i18n.Errors;
0030: import org.geotools.resources.i18n.ErrorKeys;
0031: import org.geotools.resources.i18n.Logging;
0032: import org.geotools.resources.i18n.LoggingKeys;
0033:
0034: /**
0035: * A registry for factories, organized by categories (usualy by <strong>interface</strong>).
0036: * For example <code>{@link org.opengis.referencing.crs.CRSFactory}.class</code> is a category,
0037: * and <code>{@link org.opengis.referencing.operation.MathTransformFactory}.class</code>
0038: * is an other category.
0039: * <p>
0040: * For each category, implementations are registered in a file placed in the
0041: * {@code META-INF/services/} directory, as specified in the {@link ServiceRegistry}
0042: * javadoc. Those files are usually bundled into the JAR file distributed by the vendor.
0043: * If the same {@code META-INF/services/} file appears many time in different JARs,
0044: * they are processed as if their content were merged.
0045: * <p>
0046: * Example use:
0047: * <blockquote><code>
0048: * Set categories = Collections.singleton(new Class[] {MathTransformProvider.class});<br>
0049: * FactoryRegistry registry = new FactoryRegistry(categories);<br>
0050: * <br>
0051: * // get the providers<br>
0052: * Filter filter = null;<br>
0053: * Hints hints = null;<br>
0054: * Iterator<MathTransform> providers =
0055: * registry.getServiceProviders(MathTransformProvider.class, filter, hints);<br>
0056: * </code></blockquote>
0057: * <p>
0058: * <strong>NOTE: This class is not thread safe</strong>. Users are responsable
0059: * for synchronisation. This is usually done in an utility class wrapping this
0060: * service registry (e.g. {@link org.geotools.referencing.ReferencingFactoryFinder}).
0061: *
0062: * @since 2.1
0063: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/factory/FactoryRegistry.java $
0064: * @version $Id: FactoryRegistry.java 29058 2008-02-03 17:47:07Z desruisseaux $
0065: * @author Martin Desruisseaux
0066: * @author Richard Gould
0067: * @author Jody Garnett
0068: *
0069: * @see org.geotools.referencing.FactoryFinder
0070: * @see org.geotools.coverage.FactoryFinder
0071: */
0072: public class FactoryRegistry extends ServiceRegistry {
0073: /**
0074: * The logger for all events related to factory registry.
0075: */
0076: protected static final Logger LOGGER = org.geotools.util.logging.Logging
0077: .getLogger("org.geotools.factory");
0078:
0079: /**
0080: * The logger level for debug messages.
0081: */
0082: private static final Level DEBUG_LEVEL = Level.FINEST;
0083:
0084: /**
0085: * A copy of the global configuration set through {@link Factories} static methods. We keep
0086: * a copy in every {@code FactoryRegistry} instance in order to compare against the master
0087: * {@link Factories#GLOBAL} and detect if the configuration changed since the last time this
0088: * registry was used.
0089: *
0090: * @see #synchronizeIteratorProviders
0091: *
0092: * @deprecated Use listeners instead.
0093: */
0094: private final Factories globalConfiguration = new Factories();
0095:
0096: /**
0097: * Categories under scanning. This is used by {@link #scanForPlugins(Collection,Class)}
0098: * as a guard against infinite recursivity (i.e. when a factory to be scanned request
0099: * an other dependency of the same category).
0100: */
0101: private final Set/*<Class>*/scanningCategories = new HashSet();
0102:
0103: /**
0104: * Factories under testing for availability. This is used by
0105: * {@link #isAvailable} as a guard against infinite recursivity.
0106: */
0107: private final Set/*<Class<? extends OptionalFactory>>*/testingAvailability = new HashSet();
0108:
0109: /**
0110: * Factories under testing for hints compatibility. This is used by
0111: * {@link #usesAcceptableHints} as a guard against infinite recursivity.
0112: */
0113: private final Set/*<Class<? extends Factory>>*/testingHints = new HashSet();
0114:
0115: /**
0116: * Constructs a new registry for the specified category.
0117: *
0118: * @param category The single category.
0119: *
0120: * @since 2.4
0121: */
0122: public FactoryRegistry(final Class category) {
0123: this ((Collection) Collections.singleton(category));
0124: }
0125:
0126: /**
0127: * Constructs a new registry for the specified categories.
0128: *
0129: * @param categories The categories.
0130: *
0131: * @since 2.4
0132: */
0133: public FactoryRegistry(final Class[] categories) {
0134: this (Arrays.asList(categories));
0135: }
0136:
0137: /**
0138: * Constructs a new registry for the specified categories.
0139: *
0140: * @param categories The categories.
0141: */
0142: public FactoryRegistry(final Collection categories) {
0143: // TODO: remove the cast when we will be allowed to compile for J2SE 1.5.
0144: super ((Iterator) categories.iterator());
0145: }
0146:
0147: /**
0148: * Returns the providers in the registry for the specified category. Providers that are
0149: * not {@linkplain OptionalFactory#isAvailable available} will be ignored. This method
0150: * will {@linkplain #scanForPlugins() scan for plugins} the first time it is invoked for
0151: * the given category.
0152: *
0153: * @param category The category to look for. Usually an interface class
0154: * (not the actual implementation class).
0155: * @return Factories ready to use for the specified category.
0156: *
0157: * @deprecated Replaced by {@link #getServiceProviders(Class, Filter, Hints)}.
0158: */
0159: public Iterator getServiceProviders(final Class category) {
0160: return getServiceProviders(category, null, null);
0161: }
0162:
0163: /**
0164: * Returns the providers in the registry for the specified category, filter and hints.
0165: * Providers that are not {@linkplain OptionalFactory#isAvailable available} will be
0166: * ignored. This method will {@linkplain #scanForPlugins() scan for plugins} the first
0167: * time it is invoked for the given category.
0168: *
0169: * @param category The category to look for. Usually an interface class
0170: * (not the actual implementation class).
0171: * @param filter The optional filter, or {@code null}.
0172: * @param hints The optional user requirements, or {@code null}.
0173: * @return Factories ready to use for the specified category, filter and hints.
0174: *
0175: * @since 2.3
0176: */
0177: public Iterator getServiceProviders(final Class category,
0178: final Filter filter, final Hints hints) {
0179: /*
0180: * The implementation of this method is very similar to the 'getUnfilteredProviders'
0181: * one except for filter handling. See the comments in 'getUnfilteredProviders' for
0182: * more implementation details.
0183: */
0184: if (scanningCategories.contains(category)) {
0185: // Please note you will get errors here if you accidentally allow
0186: // more than one thread to use your FactoryRegistry at a time.
0187: throw new RecursiveSearchException(category);
0188: }
0189: final Filter hintsFilter = new Filter() {
0190: public boolean filter(final Object provider) {
0191: return isAcceptable(provider, category, hints, filter);
0192: }
0193: };
0194: synchronizeIteratorProviders();
0195: Iterator iterator = getServiceProviders(category, hintsFilter,
0196: true);
0197: if (!iterator.hasNext()) {
0198: scanForPlugins(getClassLoaders(), category);
0199: iterator = getServiceProviders(category, hintsFilter, true);
0200: }
0201: return iterator;
0202: }
0203:
0204: /**
0205: * Implementation of {@link #getServiceProviders(Class, Filter, Hints)} without the filtering
0206: * applied by the {@link #isAcceptable(Object, Class, Hints, Filter)} method. If this filtering
0207: * is not already presents in the filter given to this method, then it must be applied on the
0208: * elements returned by the iterator. The later is preferrable when:
0209: * <p>
0210: * <ul>
0211: * <li>There is some cheaper tests to perform before {@code isAcceptable}.</li>
0212: * <li>We don't want a restrictive filter in order to avoid trigging a classpath
0213: * scan if this method doesn't found any element to iterate.</li>
0214: * </ul>
0215: * <p>
0216: * <b>Note:</b>
0217: * {@link #synchronizeIteratorProviders} should also be invoked once before this method.
0218: */
0219: final Iterator getUnfilteredProviders(final Class category) {
0220: if (!scanningCategories.isEmpty()) {
0221: /*
0222: * The 'scanningCategories' map is almost always empty, so we use the above 'isEmpty()'
0223: * check because it is fast. If the map is not empty, then this mean that a scanning is
0224: * under progress, i.e. 'scanForPlugins' is currently being executed. This is okay as
0225: * long as the user is not asking for one of the categories under scanning. Otherwise,
0226: * the answer returned by 'getServiceProviders' would be incomplete because not all
0227: * plugins have been found yet. This can lead to some bugs hard to spot because this
0228: * methoud could complete normally but return the wrong plugin. It is safer to thrown
0229: * an exception so the user is advised that something is wrong.
0230: */
0231: if (scanningCategories.contains(category)) {
0232: throw new RecursiveSearchException(category);
0233: }
0234: }
0235: Iterator iterator = getServiceProviders(category, true);
0236: if (!iterator.hasNext()) {
0237: /*
0238: * No plugin. This method is probably invoked the first time for the specified
0239: * category, otherwise we should have found at least the Geotools implementation.
0240: * Scans the plugin now, but for this category only.
0241: */
0242: scanForPlugins(getClassLoaders(), category);
0243: iterator = getServiceProviders(category, true);
0244: }
0245: return iterator;
0246: }
0247:
0248: /**
0249: * Returns the first provider in the registry for the specified category, using the specified
0250: * map of hints (if any). This method may {@linkplain #scanForPlugins scan for plugins} the
0251: * first time it is invoked. Except as a result of this scan, no new provider instance is
0252: * created by the default implementation of this method. The {@link FactoryCreator} class
0253: * change this behavior however.
0254: *
0255: * @param category The category to look for. Must be one of the categories declared to the
0256: * constructor. Usually an interface class (not the actual implementation
0257: * class).
0258: * @param filter An optional filter, or {@code null} if none.
0259: * This is used for example in order to select the first factory for some
0260: * {@linkplain org.opengis.referencing.AuthorityFactory#getAuthority authority}.
0261: * @param hints A {@linkplain Hints map of hints}, or {@code null} if none.
0262: * @param key The key to use for looking for a user-provided instance in the hints, or
0263: * {@code null} if none.
0264: * @return A factory {@linkplain OptionalFactory#isAvailable available} for use for the
0265: * specified category and hints. The returns type is {@code Object} instead of
0266: * {@link Factory} because the factory implementation doesn't need to be a Geotools one.
0267: * @throws FactoryNotFoundException if no factory was found for the specified category, filter
0268: * and hints.
0269: * @throws FactoryRegistryException if a factory can't be returned for some other reason.
0270: *
0271: * @see #getServiceProviders(Class, Filter, Hints)
0272: * @see FactoryCreator#getServiceProvider
0273: */
0274: public Object getServiceProvider(final Class category,
0275: final Filter filter, Hints hints, final Hints.Key key)
0276: throws FactoryRegistryException {
0277: synchronizeIteratorProviders();
0278: final boolean debug = LOGGER.isLoggable(DEBUG_LEVEL);
0279: if (debug) {
0280: /*
0281: * We are not required to insert the method name ("GetServiceProvider") in the
0282: * message because it is part of the informations already stored by LogRecord,
0283: * and formatted by the default java.util.logging.SimpleFormatter.
0284: *
0285: * Conventions for the message part according java.util.logging.Logger javadoc:
0286: * - "ENTRY" at the begining of a method.
0287: * - "RETURN" at the end of a method, if successful.
0288: * - "THROW" in case of failure.
0289: * - "CHECK" ... is our own addition to Sun's convention for this method ...
0290: */
0291: debug("ENTRY", category, key, null, null);
0292: }
0293: Class implementation = null;
0294: if (key != null) {
0295: /*
0296: * Sanity check: make sure that the key class is appropriate for the category.
0297: */
0298: final Class valueClass = key.getValueClass();
0299: if (!category.isAssignableFrom(valueClass)) {
0300: if (debug) {
0301: debug("THROW", category, key, "unexpected type:",
0302: valueClass);
0303: }
0304: throw new IllegalArgumentException(Errors.format(
0305: ErrorKeys.ILLEGAL_KEY_$1, key));
0306: }
0307: if (hints != null) {
0308: final Object hint = hints.get(key);
0309: if (hint != null) {
0310: if (debug) {
0311: debug("CHECK", category, key,
0312: "user provided a", hint.getClass());
0313: }
0314: if (category.isInstance(hint)) {
0315: /*
0316: * The factory implementation was given explicitly by the user.
0317: * Nothing to do; we are done.
0318: */
0319: if (debug) {
0320: debug("RETURN", category, key,
0321: "return hint as provided.", null);
0322: }
0323: return hint;
0324: }
0325: /*
0326: * Before to pass the hints to the private 'getServiceImplementation' method,
0327: * remove the hint for the user-supplied key. This is because this hint has
0328: * been processed by this public 'getServiceProvider' method, and the policy
0329: * is to remove the processed hints before to pass them to child dependencies
0330: * (see the "Check recursively in factory dependencies" comment elswhere in
0331: * this class).
0332: *
0333: * Use case: DefaultDataSourceTest invokes indirectly 'getServiceProvider'
0334: * with a "CRS_AUTHORITY_FACTORY = ThreadedEpsgFactory.class" hint. However
0335: * ThreadedEpsgFactory (in the org.geotools.referencing.factory.epsg package)
0336: * is a wrapper around DirectEpsgFactory, and defines this dependency through
0337: * a "CRS_AUTHORITY_FACTORY = DirectEpsgFactory.class" hint. There is no way
0338: * to match this hint for both factories in same time. Since we must choose
0339: * one, we assume that the user is interrested in the most top level one and
0340: * discart this particular hint for the dependencies.
0341: */
0342: hints = new Hints(hints);
0343: if (hints.remove(key) != hint) {
0344: // Should never happen except on concurrent modification in an other thread.
0345: throw new AssertionError(key);
0346: }
0347: /*
0348: * If the user accepts many implementation classes, then try all of them in
0349: * the preference order given by the user. The last class (or the singleton
0350: * if the hint was not an array) will be tried using the "normal" path
0351: * (oustide the loop) in order to get the error message in case of failure.
0352: */
0353: if (hint instanceof Class[]) {
0354: final Class[] types = (Class[]) hint;
0355: final int length = types.length;
0356: for (int i = 0; i < length - 1; i++) {
0357: final Class type = types[i];
0358: if (debug) {
0359: debug("CHECK", category, key,
0360: "consider hint[" + i + ']',
0361: type);
0362: }
0363: final Object candidate = getServiceImplementation(
0364: category, type, filter, hints);
0365: if (candidate != null) {
0366: if (debug) {
0367: debug("RETURN", category, key,
0368: "found implementation",
0369: candidate.getClass());
0370: }
0371: return candidate;
0372: }
0373: }
0374: if (length != 0) {
0375: implementation = types[length - 1]; // Last try to be done below.
0376: }
0377: } else {
0378: implementation = (Class) hint;
0379: }
0380: }
0381: }
0382: }
0383: if (debug && implementation != null) {
0384: debug("CHECK", category, key, "consider hint[last]",
0385: implementation);
0386: }
0387: final Object candidate = getServiceImplementation(category,
0388: implementation, filter, hints);
0389: if (candidate != null) {
0390: if (debug) {
0391: debug("RETURN", category, key, "found implementation",
0392: candidate.getClass());
0393: }
0394: return candidate;
0395: }
0396: if (debug) {
0397: debug("THROW", category, key,
0398: "could not find implementation.", null);
0399: }
0400: throw new FactoryNotFoundException(
0401: Errors
0402: .format(
0403: ErrorKeys.FACTORY_NOT_FOUND_$1,
0404: Utilities
0405: .getShortName(implementation != null ? implementation
0406: : category)));
0407: }
0408:
0409: /**
0410: * Log a debug message for {@link #getServiceProvider} method. Note: we are not required
0411: * to insert the method name ({@code "GetServiceProvider"}) in the message because it is
0412: * part of the informations already stored by {@link LogRecord}, and formatted by the
0413: * default {@link java.util.logging.SimpleFormatter}.
0414: *
0415: * @param status {@code "ENTRY"}, {@code "RETURN"} or {@code "THROW"},
0416: * according {@link Logger} conventions.
0417: * @param category The category given to the {@link #getServiceProvider} method.
0418: * @param key The key being examined, or {@code null}.
0419: * @param message Optional message, or {@code null} if none.
0420: * @param type Optional class to format after the message, or {@code null}.
0421: */
0422: private static void debug(final String status,
0423: final Class category, final Hints.Key key,
0424: final String message, final Class type) {
0425: final StringBuffer buffer = new StringBuffer(status);
0426: buffer.append(
0427: Utilities.spaces(Math.max(1, 7 - status.length())))
0428: .append('(').append(Utilities.getShortName(category));
0429: if (key != null) {
0430: buffer.append(", ").append(key);
0431: }
0432: buffer.append(')');
0433: if (message != null) {
0434: buffer.append(": ").append(message);
0435: }
0436: if (type != null) {
0437: buffer.append(' ').append(Utilities.getShortName(type))
0438: .append('.');
0439: }
0440: final LogRecord record = new LogRecord(DEBUG_LEVEL, buffer
0441: .toString());
0442: record.setSourceClassName(FactoryRegistry.class.getName());
0443: record.setSourceMethodName("getServiceProvider");
0444: LOGGER.log(record);
0445: }
0446:
0447: /**
0448: * Search the first implementation in the registery matching the specified conditions.
0449: * This method is invoked only by the {@link #getServiceProvider(Class, Filter, Hints,
0450: * Hints.Key)} public method above; there is no recursivity there. This method do not
0451: * creates new instance if no matching factory is found.
0452: *
0453: * @param category The category to look for. Usually an interface class.
0454: * @param implementation The desired class for the implementation, or {@code null} if none.
0455: * @param filter An optional filter, or {@code null} if none.
0456: * @param hints A {@linkplain Hints map of hints}, or {@code null} if none.
0457: * @return A factory for the specified category and hints, or {@code null} if none.
0458: */
0459: private Object getServiceImplementation(final Class category,
0460: final Class implementation, final Filter filter,
0461: final Hints hints) {
0462: for (final Iterator/*<Object>*/it = getUnfilteredProviders(category); it
0463: .hasNext();) {
0464: final Object candidate = it.next();
0465: // Implementation class must be tested before 'isAcceptable'
0466: // in order to avoid StackOverflowError in some situations.
0467: if (implementation != null
0468: && !implementation.isInstance(candidate)) {
0469: continue;
0470: }
0471: if (!isAcceptable(candidate, category, hints, filter)) {
0472: continue;
0473: }
0474: return candidate;
0475: }
0476: final List/*<Reference>*/cached = getCachedProviders(category);
0477: if (cached != null) {
0478: /*
0479: * Checks if a factory previously created by FactoryCreator could fit. This
0480: * block should never be executed if this instance is not a FactoryCreator.
0481: */
0482: for (final Iterator/*<Reference>*/it = cached.iterator(); it
0483: .hasNext();) {
0484: final Object candidate = ((Reference) it.next()).get();
0485: if (candidate == null) {
0486: it.remove();
0487: continue;
0488: }
0489: if (implementation != null
0490: && !implementation.isInstance(candidate)) {
0491: continue;
0492: }
0493: if (!isAcceptable(candidate, category, hints, filter)) {
0494: continue;
0495: }
0496: return candidate;
0497: }
0498: }
0499: return null;
0500: }
0501:
0502: /**
0503: * Returns the providers available in the cache, or {@code null} if none.
0504: * To be overridden by {@link FactoryCreator} only.
0505: */
0506: List/*<Reference>*/getCachedProviders(final Class category) {
0507: return null;
0508: }
0509:
0510: /**
0511: * Returns {@code true} is the specified {@code factory} meets the requirements specified by
0512: * a map of {@code hints} and the filter. This method is the entry point for the following
0513: * public methods:
0514: * <ul>
0515: * <li>Singleton {@link #getServiceProvider (Class category, Filter, Hints, Hints.Key)}</li>
0516: * <li>Iterator {@link #getServiceProviders(Class category, Filter, Hints)}</li>
0517: * </ul>
0518: *
0519: * @param candidate The factory to checks.
0520: * @param category The factory category. Usually an interface.
0521: * @param hints The optional user requirements, or {@code null}.
0522: * @param filter The optional filter, or {@code null}.
0523: * @return {@code true} if the {@code factory} meets the user requirements.
0524: */
0525: final boolean isAcceptable(final Object candidate,
0526: final Class category, final Hints hints, final Filter filter) {
0527: if (filter != null && !filter.filter(candidate)) {
0528: return false;
0529: }
0530: /*
0531: * Note: isAvailable(...) must be tested before checking the hints, because in current
0532: * Geotools implementation (especially DeferredAuthorityFactory), some hints computation
0533: * are deferred until a connection to the database is etablished (which 'isAvailable'
0534: * does in order to test the connection).
0535: */
0536: if (!isAvailable(candidate)) {
0537: return false;
0538: }
0539: if (hints != null) {
0540: if (candidate instanceof Factory) {
0541: if (!usesAcceptableHints((Factory) candidate, category,
0542: hints, (Set) null)) {
0543: return false;
0544: }
0545: }
0546: }
0547: /*
0548: * Checks for optional user conditions supplied in FactoryRegistry subclasses.
0549: */
0550: return isAcceptable(candidate, category, hints);
0551: }
0552:
0553: /**
0554: * Returns {@code true} is the specified {@code factory} meets the requirements specified
0555: * by a map of {@code hints}. This method checks only the hints; it doesn't check the
0556: * {@link Filter}, the {@linkplain OptionalFactory#isAvailable availability} or the
0557: * user-overrideable {@link #isAcceptable(Object, Class, Hints)} method. This method
0558: * invokes itself recursively.
0559: *
0560: * @param factory The factory to checks.
0561: * @param category The factory category. Usually an interface.
0562: * @param hints The user requirements ({@code null} not allowed).
0563: * @param alreadyDone Should be {@code null} except on recursive calls (for internal use only).
0564: * @return {@code true} if the {@code factory} meets the hints requirements.
0565: */
0566: private boolean usesAcceptableHints(final Factory factory,
0567: final Class category, final Hints hints,
0568: Set/*<Factory>*/alreadyDone) {
0569: /*
0570: * Ask for implementation hints with special care against infinite recursivity.
0571: * Some implementations use deferred algorithms fetching dependencies only when
0572: * first needed. The call to getImplementationHints() is sometime a trigger for
0573: * fetching dependencies (in order to return accurate hints). For example the
0574: * BufferedCoordinateOperationFactory implementation asks for an other instance
0575: * of CoordinateOperationFactory, the instance to cache behind a buffer, which
0576: * should not be itself. Of course BufferedCoordinateOperation will checks that
0577: * it is not caching itself, but its test happen too late for preventing a never-
0578: * ending loop if we don't put a 'testingHints' guard here. It is also a safety
0579: * against broken factory implementations.
0580: */
0581: if (!testingHints.add(factory)) {
0582: return false;
0583: }
0584: final Map implementationHints;
0585: try {
0586: implementationHints = Hints.stripNonKeys(factory
0587: .getImplementationHints());
0588: } finally {
0589: if (!testingHints.remove(factory)) {
0590: throw new AssertionError(factory); // Should never happen.
0591: }
0592: }
0593: if (implementationHints == null) {
0594: // factory was bad and did not meet contract - assume it used no Hints
0595: return true;
0596: }
0597: /*
0598: * We got the implementation hints. Now tests their compatibility.
0599: */
0600: Hints remaining = null;
0601: for (final Iterator it = implementationHints.entrySet()
0602: .iterator(); it.hasNext();) {
0603: final Map.Entry entry = (Map.Entry) it.next();
0604: final Object key = entry.getKey();
0605: final Object value = entry.getValue();
0606: final Object expected = hints.get(key);
0607: if (expected != null) {
0608: /*
0609: * We have found a hint that matter. Check if the
0610: * available factory meets the user's criterions.
0611: */
0612: if (expected instanceof Class) {
0613: if (!((Class) expected).isInstance(value)) {
0614: return false;
0615: }
0616: } else if (expected instanceof Class[]) {
0617: final Class[] types = (Class[]) expected;
0618: int i = 0;
0619: do
0620: if (i >= types.length)
0621: return false;
0622: while (!types[i++].isInstance(value));
0623: } else if (!expected.equals(value)) {
0624: return false;
0625: }
0626: }
0627: /*
0628: * Checks recursively in factory dependencies, if any. Note that the dependencies
0629: * will be checked against a subset of user's hints. More specifically, all hints
0630: * processed by the current pass will NOT be passed to the factories dependencies.
0631: * This is because the same hint may appears in the "parent" factory and a "child"
0632: * dependency with different value. For example the FORCE_LONGITUDE_FIRST_AXIS_ORDER
0633: * hint has the value TRUE in OrderedAxisAuthorityFactory, but the later is basically
0634: * a wrapper around the ThreadedEpsgFactory (typically), which has the value FALSE
0635: * for the same hint.
0636: *
0637: * Additional note: The 'alreadyDone' set is a safety against cyclic dependencies,
0638: * in order to protect ourself against never-ending loops. This is not the same
0639: * kind of dependencies than 'testingHints'. It is a "factory A depends on factory
0640: * B which depends on factory A" loop, which is legal.
0641: */
0642: if (value instanceof Factory) {
0643: final Factory dependency = (Factory) value;
0644: if (alreadyDone == null) {
0645: alreadyDone = new HashSet();
0646: }
0647: if (!alreadyDone.contains(dependency)) {
0648: alreadyDone.add(factory);
0649: if (remaining == null) {
0650: remaining = new Hints(hints);
0651: remaining.keySet().removeAll(
0652: implementationHints.keySet());
0653: }
0654: final Class type;
0655: if (key instanceof Hints.Key) {
0656: type = ((Hints.Key) key).getValueClass();
0657: } else {
0658: type = Factory.class; // Kind of unknown factory type...
0659: }
0660: // Recursive call to this method for scanning dependencies.
0661: if (!usesAcceptableHints(dependency, type,
0662: remaining, alreadyDone)) {
0663: return false;
0664: }
0665: }
0666: }
0667: }
0668: return true;
0669: }
0670:
0671: /**
0672: * Returns {@code true} if the specified {@code provider} meets the requirements specified by
0673: * a map of {@code hints}. The default implementation always returns {@code true}. There is no
0674: * need to override this method for {@link AbstractFactory} implementations, since their hints
0675: * are automatically checked. Override this method for non-Geotools implementations.
0676: * For example a JTS geometry factory finder may overrides this method in order to check
0677: * if a {@link com.vividsolutions.jts.geom.GeometryFactory} uses the required
0678: * {@link com.vividsolutions.jts.geom.CoordinateSequenceFactory}. Such method should be
0679: * implemented as below, since this method may be invoked for various kind of objects:
0680: *
0681: * <blockquote><pre>
0682: * if (provider instanceof GeometryFactory) {
0683: * // ... Check the GeometryFactory state here.
0684: * }
0685: * </pre></blockquote>
0686: *
0687: * @param provider The provider to checks.
0688: * @param category The factory category. Usually an interface.
0689: * @param hints The user requirements, or {@code null} if none.
0690: * @return {@code true} if the {@code provider} meets the user requirements.
0691: */
0692: protected boolean isAcceptable(final Object provider,
0693: final Class category, final Hints hints) {
0694: return true;
0695: }
0696:
0697: /**
0698: * Returns {@code true} if the specified factory is available.
0699: */
0700: private boolean isAvailable(final Object provider) {
0701: if (!(provider instanceof OptionalFactory)) {
0702: return true;
0703: }
0704: final OptionalFactory factory = (OptionalFactory) provider;
0705: final Class type = factory.getClass();
0706: if (!testingAvailability.add(type)) {
0707: throw new RecursiveSearchException(type);
0708: }
0709: try {
0710: return factory.isAvailable();
0711: } finally {
0712: if (!testingAvailability.remove(type)) {
0713: throw new AssertionError(type); // Should never happen.
0714: }
0715: }
0716: }
0717:
0718: /**
0719: * Returns all class loaders to be used for scanning plugins. Current implementation
0720: * returns the following class loaders:
0721: * <p>
0722: * <ul>
0723: * <li>{@linkplain Class#getClassLoader This object class loader}</li>
0724: * <li>{@linkplain Thread#getContextClassLoader The thread context class loader}</li>
0725: * <li>{@linkplain ClassLoader#getSystemClassLoader The system class loader}</li>
0726: * </ul>
0727: *
0728: * The actual number of class loaders may be smaller if redundancies was found.
0729: * If some more classloaders should be scanned, they shall be added into the code
0730: * of this method.
0731: */
0732: public final Set getClassLoaders() {
0733: final Set loaders = new HashSet();
0734: for (int i = 0; i < 4; i++) {
0735: final ClassLoader loader;
0736: try {
0737: switch (i) {
0738: case 0:
0739: loader = getClass().getClassLoader();
0740: break;
0741: case 1:
0742: loader = FactoryRegistry.class.getClassLoader();
0743: break;
0744: case 2:
0745: loader = Thread.currentThread()
0746: .getContextClassLoader();
0747: break;
0748: case 3:
0749: loader = ClassLoader.getSystemClassLoader();
0750: break;
0751: // Add any supplementary class loaders here, if needed.
0752: default:
0753: throw new AssertionError(i); // Should never happen.
0754: }
0755: } catch (SecurityException exception) {
0756: // We are not allowed to get a class loader.
0757: // Continue; some other class loader may be available.
0758: continue;
0759: }
0760: loaders.add(loader);
0761: }
0762: loaders.remove(null);
0763: /*
0764: * We now have a set of class loaders with duplicated object already removed
0765: * (e.g. system classloader == context classloader). However, we may still
0766: * have an other form of redundancie. A class loader may be the parent of an
0767: * other one. Try to remove those dependencies.
0768: */
0769: final ClassLoader[] asArray = (ClassLoader[]) loaders
0770: .toArray(new ClassLoader[loaders.size()]);
0771: final int length = asArray.length;
0772: for (int i = 0; i < length; i++) {
0773: ClassLoader loader = asArray[i];
0774: try {
0775: while ((loader = loader.getParent()) != null) {
0776: loaders.remove(loader);
0777: }
0778: } catch (SecurityException exception) {
0779: // We are not allowed to fetch the parent class loader.
0780: // Ignore (some redundancies may remains).
0781: }
0782: }
0783: if (loaders.isEmpty()) {
0784: LOGGER.warning("No class loaders available");
0785: }
0786: return loaders;
0787: }
0788:
0789: /**
0790: * Scans for factory plug-ins on the application class path. This method is
0791: * needed because the application class path can theoretically change, or
0792: * additional plug-ins may become available. Rather than re-scanning the
0793: * classpath on every invocation of the API, the class path is scanned
0794: * automatically only on the first invocation. Clients can call this
0795: * method to prompt a re-scan. Thus this method need only be invoked by
0796: * sophisticated applications which dynamically make new plug-ins
0797: * available at runtime.
0798: */
0799: public void scanForPlugins() {
0800: final Set loaders = getClassLoaders();
0801: for (final Iterator categories = getCategories(); categories
0802: .hasNext();) {
0803: final Class category = (Class) categories.next();
0804: scanForPlugins(loaders, category);
0805: }
0806: }
0807:
0808: /**
0809: * Scans for factory plug-ins of the given category, with guard against recursivities.
0810: * The recursivity check make debugging easier than inspecting a {@link StackOverflowError}.
0811: *
0812: * @param loader The class loader to use.
0813: * @param category The category to scan for plug-ins.
0814: */
0815: private void scanForPlugins(
0816: final Collection/*<ClassLoader>*/loaders,
0817: final Class category) {
0818: if (!scanningCategories.add(category)) {
0819: throw new RecursiveSearchException(category);
0820: }
0821: try {
0822: final StringBuffer message = getLogHeader(category);
0823: boolean newServices = false;
0824: /*
0825: * First, scan META-INF/services directories (the default mechanism).
0826: */
0827: for (final Iterator it = loaders.iterator(); it.hasNext();) {
0828: final ClassLoader loader = (ClassLoader) it.next();
0829: newServices |= register(lookupProviders(category,
0830: loader), category, message);
0831: newServices |= registerFromSystemProperty(loader,
0832: category, message);
0833: }
0834: /*
0835: * Next, query the user-provider iterators, if any.
0836: */
0837: final FactoryIteratorProvider[] fip = Factories
0838: .getIteratorProviders();
0839: for (int i = 0; i < fip.length; i++) {
0840: final Iterator it = fip[i].iterator(category);
0841: if (it != null) {
0842: newServices |= register(it, category, message);
0843: }
0844: }
0845: /*
0846: * Finally, log the list of registered factories.
0847: */
0848: if (newServices) {
0849: log("scanForPlugins", message);
0850: }
0851: } finally {
0852: if (!scanningCategories.remove(category)) {
0853: throw new AssertionError(category);
0854: }
0855: }
0856: }
0857:
0858: /**
0859: * {@linkplain #registerServiceProvider Registers} all factories given by the
0860: * supplied iterator.
0861: *
0862: * @param factories The factories (or "service providers") to register.
0863: * @param category the category under which to register the providers.
0864: * @param message A buffer where to write the logging message.
0865: * @return {@code true} if at least one factory has been registered.
0866: */
0867: private boolean register(final Iterator/*<T>*/factories,
0868: final Class/*<T>*/category, final StringBuffer message) {
0869: boolean newServices = false;
0870: final String lineSeparator = System.getProperty(
0871: "line.separator", "\n");
0872: while (factories.hasNext()) {
0873: Object factory;
0874: try {
0875: factory = factories.next();
0876: } catch (OutOfMemoryError error) {
0877: // Makes sure that we don't try to handle this error.
0878: throw error;
0879: } catch (NoClassDefFoundError error) {
0880: /*
0881: * A provider can't be registered because of some missing dependencies.
0882: * This occurs for example when trying to register the WarpTransform2D
0883: * math transform on a machine without JAI installation. Since the factory
0884: * may not be essential (this is the case of WarpTransform2D), just skip it.
0885: */
0886: loadingFailure(category, error, false);
0887: continue;
0888: } catch (ExceptionInInitializerError error) {
0889: /*
0890: * If an exception occured during class initialization, log the cause.
0891: * The ExceptionInInitializerError alone doesn't help enough.
0892: */
0893: final Throwable cause = error.getCause();
0894: if (cause != null) {
0895: loadingFailure(category, cause, true);
0896: }
0897: throw error;
0898: } catch (Error error) {
0899: if (!Utilities.getShortClassName(error).equals(
0900: "ServiceConfigurationError")) {
0901: // We want to handle sun.misc.ServiceConfigurationError only. Unfortunatly, we
0902: // need to rely on reflection because this error class is not a commited API.
0903: // TODO: Check if the error is catchable with JSE 6.
0904: throw error;
0905: }
0906: /*
0907: * Failed to register a factory for a reason probably related to the plugin
0908: * initialisation. It may be some factory-dependent missing resources.
0909: */
0910: loadingFailure(category, error, true);
0911: continue;
0912: }
0913: final Class factoryClass = factory.getClass();
0914: /*
0915: * If the factory implements more than one interface and an instance were
0916: * already registered, reuse the same instance instead of duplicating it.
0917: */
0918: final Object replacement = getServiceProviderByClass(factoryClass);
0919: if (replacement != null) {
0920: factory = replacement;
0921: // Need to register anyway, because the category may not be the same.
0922: }
0923: if (registerServiceProvider(factory, category)) {
0924: /*
0925: * The factory is now registered. Add it to the message to be logged. We will log
0926: * all factories together in a single log event because some registration (e.g.
0927: * MathTransformProviders) would be otherwise quite verbose.
0928: */
0929: message.append(lineSeparator);
0930: message.append(" ");
0931: message.append(factoryClass.getName());
0932: newServices = true;
0933: }
0934: }
0935: return newServices;
0936: }
0937:
0938: /**
0939: * If a system property was setup, load the class (if not already registered)
0940: * and move it in front of any other factory. This is done for compatibility
0941: * with legacy {@code FactoryFinder} implementation.
0942: *
0943: * @param loader The class loader to use.
0944: * @param category The category to scan for plug-ins.
0945: * @param message A buffer where to write the logging message.
0946: * @return {@code true} if at least one factory has been registered.
0947: */
0948: private boolean registerFromSystemProperty(
0949: final ClassLoader loader, final Class category,
0950: final StringBuffer message) {
0951: boolean newServices = false;
0952: try {
0953: final String classname = System.getProperty(category
0954: .getName());
0955: if (classname != null)
0956: try {
0957: final Class factoryClass = loader
0958: .loadClass(classname);
0959: Object factory = getServiceProviderByClass(factoryClass);
0960: if (factory == null)
0961: try {
0962: factory = factoryClass.newInstance();
0963: if (registerServiceProvider(factory,
0964: category)) {
0965: message.append(System.getProperty(
0966: "line.separator", "\n"));
0967: message.append(" ");
0968: message.append(factoryClass.getName());
0969: newServices = true;
0970: }
0971: } catch (IllegalAccessException exception) {
0972: throw new FactoryRegistryException(
0973: Errors
0974: .format(
0975: ErrorKeys.CANT_CREATE_FACTORY_$1,
0976: classname),
0977: exception);
0978: } catch (InstantiationException exception) {
0979: throw new FactoryRegistryException(
0980: Errors
0981: .format(
0982: ErrorKeys.CANT_CREATE_FACTORY_$1,
0983: classname),
0984: exception);
0985: }
0986: /*
0987: * Put this factory in front of every other factories (including the ones loaded
0988: * in previous class loaders, which is why we don't inline this ordering in the
0989: * 'register' loop). Note: if some factories were not yet registered, they will
0990: * not be properly ordered. Since this code exists more for compatibility reasons
0991: * than as a commited API, we ignore this short comming for now.
0992: */
0993: for (final Iterator it = getServiceProviders(
0994: category, false); it.hasNext();) {
0995: final Object other = it.next();
0996: if (other != factory) {
0997: setOrdering(category, factory, other);
0998: }
0999: }
1000: } catch (ClassNotFoundException exception) {
1001: // The class has not been found, maybe because we are not using the appropriate
1002: // class loader. Ignore (do not thrown an exception), in order to give a chance
1003: // to the caller to invokes this method again with a different class loader.
1004: }
1005: } catch (SecurityException exception) {
1006: // We are not allowed to read property, probably
1007: // because we are running in an applet. Ignore...
1008: }
1009: return newServices;
1010: }
1011:
1012: /**
1013: * Invoked when a factory can't be loaded. Log a warning, but do not stop the process.
1014: */
1015: private static void loadingFailure(final Class category,
1016: final Throwable error, final boolean showStackTrace) {
1017: final String name = Utilities.getShortName(category);
1018: final StringBuffer cause = new StringBuffer(Utilities
1019: .getShortClassName(error));
1020: final String message = error.getLocalizedMessage();
1021: if (message != null) {
1022: cause.append(": ");
1023: cause.append(message);
1024: }
1025: final LogRecord record = Logging.format(Level.WARNING,
1026: LoggingKeys.CANT_LOAD_SERVICE_$2, name, cause
1027: .toString());
1028: if (showStackTrace) {
1029: record.setThrown(error);
1030: }
1031: record.setSourceClassName(FactoryRegistry.class.getName());
1032: record.setSourceMethodName("scanForPlugins");
1033: LOGGER.log(record);
1034: }
1035:
1036: /**
1037: * Prepares a message to be logged if any provider has been registered.
1038: */
1039: private static StringBuffer getLogHeader(final Class category) {
1040: return new StringBuffer(Logging.getResources(null).getString(
1041: LoggingKeys.FACTORY_IMPLEMENTATIONS_$1,
1042: Utilities.getShortName(category)));
1043: }
1044:
1045: /**
1046: * Log the specified message after all provider for a given category have been registered.
1047: */
1048: private static void log(final String method,
1049: final StringBuffer message) {
1050: final LogRecord record = new LogRecord(Level.CONFIG, message
1051: .toString());
1052: record.setSourceClassName(FactoryRegistry.class.getName());
1053: record.setSourceMethodName(method);
1054: LOGGER.log(record);
1055: }
1056:
1057: /**
1058: * Synchronizes the content of the {@link #globalConfiguration} with {@link Factories#GLOBAL}.
1059: * New providers are {@linkplain #register registered} immediately. Note that this method is
1060: * typically invoked in a different thread than {@link Factories} method calls.
1061: *
1062: * @see Factories#addFactoryIteratorProvider
1063: */
1064: private void synchronizeIteratorProviders() {
1065: final FactoryIteratorProvider[] newProviders = globalConfiguration
1066: .synchronizeIteratorProviders();
1067: if (newProviders == null) {
1068: return;
1069: }
1070: for (final Iterator categories = getCategories(); categories
1071: .hasNext();) {
1072: final Class category = (Class) categories.next();
1073: if (getServiceProviders(category, false).hasNext()) {
1074: /*
1075: * Register immediately the factories only if some other factories were already
1076: * registered for this category, because in such case scanForPlugin() will not
1077: * be invoked automatically. If no factory are registered for this category, do
1078: * nothing - we will rely on the lazy invocation of scanForPlugins() when first
1079: * needed. We perform this check because getServiceProviders(category).hasNext()
1080: * is the criterion used by FactoryRegistry in order to decide if it should invoke
1081: * automatically scanForPlugins().
1082: */
1083: for (int i = 0; i < newProviders.length; i++) {
1084: final FactoryIteratorProvider provider = newProviders[i];
1085: final Iterator it = provider.iterator(category);
1086: if (it != null) {
1087: final StringBuffer message = getLogHeader(category);
1088: if (register(it, category, message)) {
1089: log("synchronizeIteratorProviders", message);
1090: }
1091: }
1092: }
1093: }
1094: }
1095: }
1096:
1097: /**
1098: * Set pairwise ordering between all factories according a comparator. Calls to
1099: * <code>{@linkplain Comparator#compare compare}(factory1, factory2)</code> should returns:
1100: * <ul>
1101: * <li>{@code -1} if {@code factory1} is preferred to {@code factory2}</li>
1102: * <li>{@code +1} if {@code factory2} is preferred to {@code factory1}</li>
1103: * <li>{@code 0} if there is no preferred order between {@code factory1} and
1104: * {@code factory2}</li>
1105: * </ul>
1106: *
1107: * @param category The category to set ordering.
1108: * @param comparator The comparator to use for ordering.
1109: * @return {@code true} if at least one ordering setting has been modified as a consequence
1110: * of this call.
1111: */
1112: public boolean setOrdering(final Class category,
1113: final Comparator comparator) {
1114: boolean set = false;
1115: final List previous = new ArrayList();
1116: for (final Iterator it = getServiceProviders(category, false); it
1117: .hasNext();) {
1118: final Object f1 = it.next();
1119: for (int i = previous.size(); --i >= 0;) {
1120: final Object f2 = previous.get(i);
1121: final int c;
1122: try {
1123: c = comparator.compare(f1, f2);
1124: } catch (ClassCastException exception) {
1125: /*
1126: * This exception is expected if the user-supplied comparator follows strictly
1127: * the java.util.Comparator specification and has determined that it can't
1128: * compare the supplied factories. From ServiceRegistry point of view, it just
1129: * means that the ordering between those factories will stay undeterminated.
1130: */
1131: continue;
1132: }
1133: if (c > 0) {
1134: set |= setOrdering(category, f1, f2);
1135: } else if (c < 0) {
1136: set |= setOrdering(category, f2, f1);
1137: }
1138: }
1139: previous.add(f1);
1140: }
1141: return set;
1142: }
1143:
1144: /**
1145: * Sets or unsets a pairwise ordering between all factories meeting a criterion. For example
1146: * in the CRS framework ({@link org.geotools.referencing.FactoryFinder}), this is used for
1147: * setting ordering between all factories provided by two vendors, or for two authorities.
1148: * If one or both factories are not currently registered, or if the desired ordering is
1149: * already set/unset, nothing happens and false is returned.
1150: *
1151: * @param base The base category. Only categories {@linkplain Class#isAssignableFrom
1152: * assignable} to {@code base} will be processed.
1153: * @param set {@code true} for setting the ordering, or {@code false} for unsetting.
1154: * @param service1 Filter for the preferred factory.
1155: * @param service2 Filter for the factory to which {@code service1} is preferred.
1156: */
1157: public boolean setOrdering(final Class base, final boolean set,
1158: final Filter service1, final Filter service2) {
1159: boolean done = false;
1160: for (final Iterator categories = getCategories(); categories
1161: .hasNext();) {
1162: final Class category = (Class) categories.next();
1163: if (base.isAssignableFrom(category)) {
1164: Object impl1 = null;
1165: Object impl2 = null;
1166: for (final Iterator it = getServiceProviders(category,
1167: false); it.hasNext();) {
1168: final Object factory = it.next();
1169: if (service1.filter(factory))
1170: impl1 = factory;
1171: if (service2.filter(factory))
1172: impl2 = factory;
1173: if (impl1 != null && impl2 != null
1174: && impl1 != impl2) {
1175: if (set)
1176: done |= setOrdering(category, impl1, impl2);
1177: else
1178: done |= unsetOrdering(category, impl1,
1179: impl2);
1180: }
1181: }
1182: }
1183: }
1184: return done;
1185: }
1186: }
|