Exemple #1
0
 /**
  * Returns the first provider in the registry for the specified category, using the specified map
  * of hints (if any). This method may {@linkplain #scanForPlugins scan for plugins} the first time
  * it is invoked. Except as a result of this scan, no new provider instance is created by the
  * default implementation of this method. The {@link FactoryCreator} class change this behavior
  * however.
  *
  * @param  <T> The class represented by the {@code category} argument.
  * @param category The category to look for. Must be one of the categories declared to the
  *     constructor. Usually an interface class (not the actual implementation class).
  * @param filter An optional filter, or {@code null} if none. This is used for example in order to
  *     select the first factory for some {@linkplain
  *     org.opengis.referencing.AuthorityFactory#getAuthority authority}.
  * @param hints A {@linkplain Hints map of hints}, or {@code null} if none.
  * @param key The key to use for looking for a user-provided instance in the hints, or {@code
  *     null} if none.
  * @return A factory {@linkplain OptionalFactory#isAvailable available} for use for the specified
  *     category and hints. The returns type is {@code Object} instead of {@link Factory} because
  *     the factory implementation doesn't need to be a Geotools one.
  * @throws FactoryNotFoundException if no factory was found for the specified category, filter and
  *     hints.
  * @throws FactoryRegistryException if a factory can't be returned for some other reason.
  * @see #getServiceProviders(Class, Filter, Hints)
  * @see FactoryCreator#getServiceProvider
  */
 public <T> T getServiceProvider(
     final Class<T> category, final Filter filter, Hints hints, final Hints.Key key)
     throws FactoryRegistryException {
   synchronizeIteratorProviders();
   final boolean debug = LOGGER.isLoggable(DEBUG_LEVEL);
   if (debug) {
     /*
      * We are not required to insert the method name ("GetServiceProvider") in the
      * message because it is part of the informations already stored by LogRecord,
      * and formatted by the default java.util.logging.SimpleFormatter.
      *
      * Conventions for the message part according java.util.logging.Logger javadoc:
      * - "ENTRY"  at the begining of a method.
      * - "RETURN" at the end of a method, if successful.
      * - "THROW"  in case of failure.
      * - "CHECK"  ... is our own addition to Sun's convention for this method ...
      */
     debug("ENTRY", category, key, null, null);
   }
   Class<?> implementation = null;
   if (key != null) {
     /*
      * Sanity check: make sure that the key class is appropriate for the category.
      */
     final Class<?> valueClass = key.getValueClass();
     if (!category.isAssignableFrom(valueClass)) {
       if (debug) {
         debug("THROW", category, key, "unexpected type:", valueClass);
       }
       throw new IllegalArgumentException(Errors.format(ErrorKeys.ILLEGAL_KEY_$1, key));
     }
     if (hints != null) {
       final Object hint = hints.get(key);
       if (hint != null) {
         if (debug) {
           debug("CHECK", category, key, "user provided a", hint.getClass());
         }
         if (category.isInstance(hint)) {
           /*
            * The factory implementation was given explicitly by the user.
            * Nothing to do; we are done.
            */
           if (debug) {
             debug("RETURN", category, key, "return hint as provided.", null);
           }
           return category.cast(hint);
         }
         /*
          * Before to pass the hints to the private 'getServiceImplementation' method,
          * remove the hint for the user-supplied key.  This is because this hint has
          * been processed by this public 'getServiceProvider' method, and the policy
          * is to remove the processed hints before to pass them to child dependencies
          * (see the "Check recursively in factory dependencies" comment elswhere in
          * this class).
          *
          * Use case: DefaultDataSourceTest invokes indirectly 'getServiceProvider'
          * with a "CRS_AUTHORITY_FACTORY = ThreadedEpsgFactory.class" hint. However
          * ThreadedEpsgFactory (in the org.geotools.referencing.factory.epsg package)
          * is a wrapper around DirectEpsgFactory, and defines this dependency through
          * a "CRS_AUTHORITY_FACTORY = DirectEpsgFactory.class" hint. There is no way
          * to match this hint for both factories in same time. Since we must choose
          * one, we assume that the user is interrested in the most top level one and
          * discart this particular hint for the dependencies.
          */
         hints = new Hints(hints);
         if (hints.remove(key) != hint) {
           // Should never happen except on concurrent modification in an other thread.
           throw new AssertionError(key);
         }
         /*
          * If the user accepts many implementation classes, then try all of them in
          * the preference order given by the user. The last class (or the singleton
          * if the hint was not an array) will be tried using the "normal" path
          * (oustide the loop) in order to get the error message in case of failure.
          */
         if (hint instanceof Class<?>[]) {
           final Class<?>[] types = (Class<?>[]) hint;
           final int length = types.length;
           for (int i = 0; i < length - 1; i++) {
             final Class<?> type = types[i];
             if (debug) {
               debug("CHECK", category, key, "consider hint[" + i + ']', type);
             }
             final T candidate = getServiceImplementation(category, type, filter, hints);
             if (candidate != null) {
               if (debug) {
                 debug("RETURN", category, key, "found implementation", candidate.getClass());
               }
               return candidate;
             }
           }
           if (length != 0) {
             implementation = types[length - 1]; // Last try to be done below.
           }
         } else {
           implementation = (Class<?>) hint;
         }
       }
     }
   }
   if (debug && implementation != null) {
     debug("CHECK", category, key, "consider hint[last]", implementation);
   }
   final T candidate = getServiceImplementation(category, implementation, filter, hints);
   if (candidate != null) {
     if (debug) {
       debug("RETURN", category, key, "found implementation", candidate.getClass());
     }
     return candidate;
   }
   if (debug) {
     debug("THROW", category, key, "could not find implementation.", null);
   }
   throw new FactoryNotFoundException(
       Errors.format(
           ErrorKeys.FACTORY_NOT_FOUND_$1, implementation != null ? implementation : category));
 }