예제 #1
0
 /**
  * Scans for factory plug-ins of the given category, with guard against recursivities. The
  * recursivity check make debugging easier than inspecting a {@link StackOverflowError}.
  *
  * @param loader The class loader to use.
  * @param category The category to scan for plug-ins.
  */
 private <T> void scanForPlugins(final Collection<ClassLoader> loaders, final Class<T> category) {
   if (!scanningCategories.addAndCheck(category)) {
     throw new RecursiveSearchException(category);
   }
   try {
     final StringBuilder message = getLogHeader(category);
     boolean newServices = false;
     /*
      * First, scan META-INF/services directories (the default mechanism).
      */
     for (final ClassLoader loader : loaders) {
       newServices |= register(lookupProviders(category, loader), category, message);
       newServices |= registerFromSystemProperty(loader, category, message);
     }
     /*
      * Next, query the user-provider iterators, if any.
      */
     final FactoryIteratorProvider[] fip = FactoryIteratorProviders.getIteratorProviders();
     for (int i = 0; i < fip.length; i++) {
       final Iterator<T> it = fip[i].iterator(category);
       if (it != null) {
         newServices |= register(it, category, message);
       }
     }
     /*
      * Finally, log the list of registered factories.
      */
     if (newServices) {
       log("scanForPlugins", message);
     }
   } finally {
     scanningCategories.removeAndCheck(category);
   }
 }
예제 #2
0
 /** Returns {@code true} if the specified factory is available. */
 private boolean isAvailable(final Object provider) {
   if (!(provider instanceof OptionalFactory)) {
     return true;
   }
   final OptionalFactory factory = (OptionalFactory) provider;
   final Class<? extends OptionalFactory> type = factory.getClass();
   if (!testingAvailability.addAndCheck(type)) {
     throw new RecursiveSearchException(type);
   }
   try {
     return factory.isAvailable();
   } finally {
     testingAvailability.removeAndCheck(type);
   }
 }
예제 #3
0
 /**
  * Returns {@code true} is the specified {@code factory} meets the requirements specified by a map
  * of {@code hints}. This method checks only the hints; it doesn't check the {@link Filter}, the
  * {@linkplain OptionalFactory#isAvailable availability} or the user-overrideable {@link
  * #isAcceptable(Object, Class, Hints)} method. This method invokes itself recursively.
  *
  * @param factory The factory to checks.
  * @param category The factory category. Usually an interface.
  * @param hints The user requirements ({@code null} not allowed).
  * @param alreadyDone Should be {@code null} except on recursive calls (for internal use only).
  * @return {@code true} if the {@code factory} meets the hints requirements.
  */
 private boolean usesAcceptableHints(
     final Factory factory, final Class<?> category, final Hints hints, Set<Factory> alreadyDone) {
   /*
    * Ask for implementation hints with special care against infinite recursivity.
    * Some implementations use deferred algorithms fetching dependencies only when
    * first needed. The call to getImplementationHints() is sometime a trigger for
    * fetching dependencies (in order to return accurate hints).   For example the
    * BufferedCoordinateOperationFactory implementation asks for an other instance
    * of CoordinateOperationFactory, the instance to cache behind a buffer,  which
    * should not be itself. Of course BufferedCoordinateOperation will checks that
    * it is not caching itself, but its test happen too late for preventing a never-
    * ending loop if we don't put a 'testingHints' guard here. It is also a safety
    * against broken factory implementations.
    */
   if (!testingHints.addAndCheck(factory)) {
     return false;
   }
   final Map<RenderingHints.Key, ?> implementationHints;
   try {
     implementationHints = Hints.stripNonKeys(factory.getImplementationHints());
   } finally {
     testingHints.removeAndCheck(factory);
   }
   if (implementationHints == null) {
     // factory was bad and did not meet contract - assume it used no Hints
     return true;
   }
   /*
    * We got the implementation hints. Now tests their compatibility.
    */
   Hints remaining = null;
   for (final Map.Entry<?, ?> entry : implementationHints.entrySet()) {
     final Object key = entry.getKey();
     final Object value = entry.getValue();
     final Object expected = hints.get(key);
     if (expected != null) {
       /*
        * We have found a hint that matter. Check if the
        * available factory meets the user's criterions.
        */
       if (expected instanceof Class<?>) {
         if (!((Class<?>) expected).isInstance(value)) {
           return false;
         }
       } else if (expected instanceof Class<?>[]) {
         final Class<?>[] types = (Class<?>[]) expected;
         int i = 0;
         do if (i >= types.length) return false;
         while (!types[i++].isInstance(value));
       } else if (!expected.equals(value)) {
         return false;
       }
     }
     /*
      * Checks recursively in factory dependencies, if any. Note that the dependencies
      * will be checked against a subset of user's hints. More specifically, all hints
      * processed by the current pass will NOT be passed to the factories dependencies.
      * This is because the same hint may appears in the "parent" factory and a "child"
      * dependency with different value. For example the FORCE_LONGITUDE_FIRST_AXIS_ORDER
      * hint has the value TRUE in OrderedAxisAuthorityFactory, but the later is basically
      * a wrapper around the ThreadedEpsgFactory (typically), which has the value FALSE
      * for the same hint.
      *
      * Additional note: The 'alreadyDone' set is a safety against cyclic dependencies,
      * in order to protect ourself against never-ending loops. This is not the same
      * kind of dependencies than 'testingHints'. It is a "factory A depends on factory
      * B which depends on factory A" loop, which is legal.
      */
     if (value instanceof Factory) {
       final Factory dependency = (Factory) value;
       if (alreadyDone == null) {
         alreadyDone = new HashSet<Factory>();
       }
       if (!alreadyDone.contains(dependency)) {
         alreadyDone.add(factory);
         if (remaining == null) {
           remaining = new Hints(hints);
           remaining.keySet().removeAll(implementationHints.keySet());
         }
         final Class<?> type;
         if (key instanceof Hints.Key) {
           type = ((Hints.Key) key).getValueClass();
         } else {
           type = Factory.class; // Kind of unknown factory type...
         }
         // Recursive call to this method for scanning dependencies.
         if (!usesAcceptableHints(dependency, type, remaining, alreadyDone)) {
           return false;
         }
       }
     }
   }
   return true;
 }