Source Code Cross Referenced for FactoryRegistry.java in  » GIS » GeoTools-2.4.1 » org » geotools » factory » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.factory 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.