< prev index next >

src/java.xml.ws/share/classes/com/sun/xml/internal/ws/policy/privateutil/ServiceFinder.java

Print this page




  49  * in the service itself.  Service providers may be installed in an
  50  * implementation of the Java platform in the form of extensions, that is, jar
  51  * files placed into any of the usual extension directories.  Providers may
  52  * also be made available by adding them to the applet or application class
  53  * path or by some other platform-specific means.
  54  * <p/>
  55  * <p> In this lookup mechanism a service is represented by an interface or an
  56  * abstract class.  (A concrete class may be used, but this is not
  57  * recommended.)  A provider of a given service contains one or more concrete
  58  * classes that extend this <i>service class</i> with data and code specific to
  59  * the provider.  This <i>provider class</i> will typically not be the entire
  60  * provider itself but rather a proxy that contains enough information to
  61  * decide whether the provider is able to satisfy a particular request together
  62  * with code that can create the actual provider on demand.  The details of
  63  * provider classes tend to be highly service-specific; no single class or
  64  * interface could possibly unify them, so no such class has been defined.  The
  65  * only requirement enforced here is that provider classes must have a
  66  * zero-argument constructor so that they may be instantiated during lookup.
  67  * <p/>
  68  * <p> A service provider identifies itself by placing a provider-configuration
  69  * file in the resource directory <tt>META-INF/services</tt>.  The file's name
  70  * should consist of the fully-qualified name of the abstract service class.
  71  * The file should contain a list of fully-qualified concrete provider-class
  72  * names, one per line.  Space and tab characters surrounding each name, as
  73  * well as blank lines, are ignored.  The comment character is <tt>'#'</tt>
  74  * (<tt>0x23</tt>); on each line all characters following the first comment
  75  * character are ignored.  The file must be encoded in UTF-8.
  76  * <p/>
  77  * <p> If a particular concrete provider class is named in more than one
  78  * configuration file, or is named in the same configuration file more than
  79  * once, then the duplicates will be ignored.  The configuration file naming a
  80  * particular provider need not be in the same jar file or other distribution
  81  * unit as the provider itself.  The provider must be accessible from the same
  82  * class loader that was initially queried to locate the configuration file;
  83  * note that this is not necessarily the class loader that found the file.
  84  * <p/>
  85  * <p> <b>Example:</b> Suppose we have a service class named
  86  * <tt>java.io.spi.CharCodec</tt>.  It has two abstract methods:
  87  * <p/>
  88  * <pre>
  89  *   public abstract CharEncoder getEncoder(String encodingName);
  90  *   public abstract CharDecoder getDecoder(String encodingName);
  91  * </pre>
  92  * <p/>
  93  * Each method returns an appropriate object or <tt>null</tt> if it cannot
  94  * translate the given encoding.  Typical <tt>CharCodec</tt> providers will
  95  * support more than one encoding.
  96  * <p/>
  97  * <p> If <tt>sun.io.StandardCodec</tt> is a provider of the <tt>CharCodec</tt>
  98  * service then its jar file would contain the file
  99  * <tt>META-INF/services/java.io.spi.CharCodec</tt>.  This file would contain
 100  * the single line:
 101  * <p/>
 102  * <pre>
 103  *   sun.io.StandardCodec    # Standard codecs for the platform
 104  * </pre>
 105  * <p/>
 106  * To locate an encoder for a given encoding name, the internal I/O code would
 107  * do something like this:
 108  * <p/>
 109  * <pre>
 110  *   CharEncoder getEncoder(String encodingName) {
 111  *       for( CharCodec cc : ServiceFinder.find(CharCodec.class) ) {
 112  *           CharEncoder ce = cc.getEncoder(encodingName);
 113  *           if (ce != null)
 114  *               return ce;
 115  *       }
 116  *       return null;
 117  *   }
 118  * </pre>
 119  * <p/>


 122  * class from within a privileged security context.
 123  *
 124  * @author Mark Reinhold
 125  * @version 1.11, 03/12/19
 126  * @since 1.3
 127  */
 128 final class ServiceFinder<T> implements Iterable<T> {
 129     private static final PolicyLogger LOGGER = PolicyLogger.getLogger(ServiceFinder.class);
 130 
 131     private static final String prefix = "META-INF/services/";
 132 
 133     private final Class<T> serviceClass;
 134     private final ClassLoader classLoader;
 135 
 136     /**
 137      * Locates and incrementally instantiates the available providers of a
 138      * given service using the given class loader.
 139      * <p/>
 140      * <p> This method transforms the name of the given service class into a
 141      * provider-configuration filename as described above and then uses the
 142      * <tt>getResources</tt> method of the given class loader to find all
 143      * available files with that name.  These files are then read and parsed to
 144      * produce a list of provider-class names.  The iterator that is returned
 145      * uses the given class loader to lookup and then instantiate each element
 146      * of the list.
 147      * <p/>
 148      * <p> Because it is possible for extensions to be installed into a running
 149      * Java virtual machine, this method may return different results each time
 150      * it is invoked. <p>
 151      *
 152      * @param service The service's abstract service class
 153      * @param loader  The class loader to be used to load provider-configuration files
 154      *                and instantiate provider classes, or <tt>null</tt> if the system
 155      *                class loader (or, failing that the bootstrap class loader) is to
 156      *                be used
 157      * @throws ServiceConfigurationError If a provider-configuration file violates the specified format
 158      *                                   or names a provider class that cannot be found and instantiated
 159      * @see #find(Class)
 160      */
 161     static <T> ServiceFinder<T> find(final Class<T> service, final ClassLoader loader) {
 162         if (null==service) {
 163             throw LOGGER.logSevereException(new NullPointerException(LocalizationMessages.WSP_0032_SERVICE_CAN_NOT_BE_NULL()));
 164         }
 165         return new ServiceFinder<T>(service,loader);
 166     }
 167 
 168     /**
 169      * Locates and incrementally instantiates the available providers of a
 170      * given service using the context class loader.  This convenience method
 171      * is equivalent to
 172      * <p/>
 173      * <pre>
 174      *   ClassLoader cl = Thread.currentThread().getContextClassLoader();


 176      * </pre>
 177      *
 178      * @param service The service's abstract service class
 179      *
 180      * @throws ServiceConfigurationError If a provider-configuration file violates the specified format
 181      *                                   or names a provider class that cannot be found and instantiated
 182      * @see #find(Class, ClassLoader)
 183      */
 184     public static <T> ServiceFinder<T> find(final Class<T> service) {
 185         return find(service,Thread.currentThread().getContextClassLoader());
 186     }
 187 
 188     private ServiceFinder(Class<T> service, ClassLoader loader) {
 189         this.serviceClass = service;
 190         this.classLoader = loader;
 191     }
 192 
 193     /**
 194      * Returns discovered objects incrementally.
 195      *
 196      * @return An <tt>Iterator</tt> that yields provider objects for the given
 197      *         service, in some arbitrary order.  The iterator will throw a
 198      *         <tt>ServiceConfigurationError</tt> if a provider-configuration
 199      *         file violates the specified format or if a provider class cannot
 200      *         be found and instantiated.
 201      */
 202     public Iterator<T> iterator() {
 203         return new LazyIterator<T>(serviceClass,classLoader);
 204     }
 205 
 206     /**
 207      * Returns discovered objects all at once.
 208      *
 209      * @return
 210      *      can be empty but never null.
 211      *
 212      * @throws ServiceConfigurationError
 213      */
 214     @SuppressWarnings({"unchecked"})
 215     public T[] toArray() {
 216         List<T> result = new ArrayList<T>();
 217         for (T t : this) {
 218             result.add(t);


 267                 cp = ln.codePointAt(i);
 268                 if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
 269                     fail(service, u, lc, LocalizationMessages.WSP_0066_ILLEGAL_PROVIDER_CLASSNAME(ln), null);
 270             }
 271             if (!returned.contains(ln)) {
 272                 names.add(ln);
 273                 returned.add(ln);
 274             }
 275         }
 276         return lc + 1;
 277     }
 278 
 279     /**
 280      * Parse the content of the given URL as a provider-configuration file.
 281      *
 282      * @param service  The service class for which providers are being sought;
 283      *                 used to construct error detail strings
 284      * @param u        The URL naming the configuration file to be parsed
 285      * @param returned A Set containing the names of provider classes that have already
 286      *                 been returned.  This set will be updated to contain the names
 287      *                 that will be yielded from the returned <tt>Iterator</tt>.
 288      * @return A (possibly empty) <tt>Iterator</tt> that will yield the
 289      *         provider-class names in the given configuration file that are
 290      *         not yet members of the returned set
 291      * @throws ServiceConfigurationError If an I/O error occurs while reading from the given URL, or
 292      *                                   if a configuration-file format error is detected
 293      */
 294     @SuppressWarnings({"StatementWithEmptyBody"})
 295     private static Iterator<String> parse(Class service, URL u, Set<String> returned)
 296         throws ServiceConfigurationError {
 297         InputStream in = null;
 298         BufferedReader r = null;
 299         ArrayList<String> names = new ArrayList<String>();
 300         try {
 301             in = u.openStream();
 302             r = new BufferedReader(new InputStreamReader(in, "utf-8"));
 303             int lc = 1;
 304             while ((lc = parseLine(service, u, r, lc, names, returned)) >= 0) ;
 305         } catch (IOException x) {
 306             fail(service, ": " + x, x);
 307         } finally {
 308             try {




  49  * in the service itself.  Service providers may be installed in an
  50  * implementation of the Java platform in the form of extensions, that is, jar
  51  * files placed into any of the usual extension directories.  Providers may
  52  * also be made available by adding them to the applet or application class
  53  * path or by some other platform-specific means.
  54  * <p/>
  55  * <p> In this lookup mechanism a service is represented by an interface or an
  56  * abstract class.  (A concrete class may be used, but this is not
  57  * recommended.)  A provider of a given service contains one or more concrete
  58  * classes that extend this <i>service class</i> with data and code specific to
  59  * the provider.  This <i>provider class</i> will typically not be the entire
  60  * provider itself but rather a proxy that contains enough information to
  61  * decide whether the provider is able to satisfy a particular request together
  62  * with code that can create the actual provider on demand.  The details of
  63  * provider classes tend to be highly service-specific; no single class or
  64  * interface could possibly unify them, so no such class has been defined.  The
  65  * only requirement enforced here is that provider classes must have a
  66  * zero-argument constructor so that they may be instantiated during lookup.
  67  * <p/>
  68  * <p> A service provider identifies itself by placing a provider-configuration
  69  * file in the resource directory {@code META-INF/services}.  The file's name
  70  * should consist of the fully-qualified name of the abstract service class.
  71  * The file should contain a list of fully-qualified concrete provider-class
  72  * names, one per line.  Space and tab characters surrounding each name, as
  73  * well as blank lines, are ignored.  The comment character is {@code '#'}
  74  * ({@code 0x23}); on each line all characters following the first comment
  75  * character are ignored.  The file must be encoded in UTF-8.
  76  * <p/>
  77  * <p> If a particular concrete provider class is named in more than one
  78  * configuration file, or is named in the same configuration file more than
  79  * once, then the duplicates will be ignored.  The configuration file naming a
  80  * particular provider need not be in the same jar file or other distribution
  81  * unit as the provider itself.  The provider must be accessible from the same
  82  * class loader that was initially queried to locate the configuration file;
  83  * note that this is not necessarily the class loader that found the file.
  84  * <p/>
  85  * <p> <b>Example:</b> Suppose we have a service class named
  86  * {@code java.io.spi.CharCodec}.  It has two abstract methods:
  87  * <p/>
  88  * <pre>
  89  *   public abstract CharEncoder getEncoder(String encodingName);
  90  *   public abstract CharDecoder getDecoder(String encodingName);
  91  * </pre>
  92  * <p/>
  93  * Each method returns an appropriate object or {@code null} if it cannot
  94  * translate the given encoding.  Typical {@code CharCodec} providers will
  95  * support more than one encoding.
  96  * <p/>
  97  * <p> If {@code sun.io.StandardCodec} is a provider of the {@code CharCodec}
  98  * service then its jar file would contain the file
  99  * {@code META-INF/services/java.io.spi.CharCodec}.  This file would contain
 100  * the single line:
 101  * <p/>
 102  * <pre>
 103  *   sun.io.StandardCodec    # Standard codecs for the platform
 104  * </pre>
 105  * <p/>
 106  * To locate an encoder for a given encoding name, the internal I/O code would
 107  * do something like this:
 108  * <p/>
 109  * <pre>
 110  *   CharEncoder getEncoder(String encodingName) {
 111  *       for( CharCodec cc : ServiceFinder.find(CharCodec.class) ) {
 112  *           CharEncoder ce = cc.getEncoder(encodingName);
 113  *           if (ce != null)
 114  *               return ce;
 115  *       }
 116  *       return null;
 117  *   }
 118  * </pre>
 119  * <p/>


 122  * class from within a privileged security context.
 123  *
 124  * @author Mark Reinhold
 125  * @version 1.11, 03/12/19
 126  * @since 1.3
 127  */
 128 final class ServiceFinder<T> implements Iterable<T> {
 129     private static final PolicyLogger LOGGER = PolicyLogger.getLogger(ServiceFinder.class);
 130 
 131     private static final String prefix = "META-INF/services/";
 132 
 133     private final Class<T> serviceClass;
 134     private final ClassLoader classLoader;
 135 
 136     /**
 137      * Locates and incrementally instantiates the available providers of a
 138      * given service using the given class loader.
 139      * <p/>
 140      * <p> This method transforms the name of the given service class into a
 141      * provider-configuration filename as described above and then uses the
 142      * {@code getResources} method of the given class loader to find all
 143      * available files with that name.  These files are then read and parsed to
 144      * produce a list of provider-class names.  The iterator that is returned
 145      * uses the given class loader to lookup and then instantiate each element
 146      * of the list.
 147      * <p/>
 148      * <p> Because it is possible for extensions to be installed into a running
 149      * Java virtual machine, this method may return different results each time
 150      * it is invoked. <p>
 151      *
 152      * @param service The service's abstract service class
 153      * @param loader  The class loader to be used to load provider-configuration files
 154      *                and instantiate provider classes, or {@code null} if the system
 155      *                class loader (or, failing that the bootstrap class loader) is to
 156      *                be used
 157      * @throws ServiceConfigurationError If a provider-configuration file violates the specified format
 158      *                                   or names a provider class that cannot be found and instantiated
 159      * @see #find(Class)
 160      */
 161     static <T> ServiceFinder<T> find(final Class<T> service, final ClassLoader loader) {
 162         if (null==service) {
 163             throw LOGGER.logSevereException(new NullPointerException(LocalizationMessages.WSP_0032_SERVICE_CAN_NOT_BE_NULL()));
 164         }
 165         return new ServiceFinder<T>(service,loader);
 166     }
 167 
 168     /**
 169      * Locates and incrementally instantiates the available providers of a
 170      * given service using the context class loader.  This convenience method
 171      * is equivalent to
 172      * <p/>
 173      * <pre>
 174      *   ClassLoader cl = Thread.currentThread().getContextClassLoader();


 176      * </pre>
 177      *
 178      * @param service The service's abstract service class
 179      *
 180      * @throws ServiceConfigurationError If a provider-configuration file violates the specified format
 181      *                                   or names a provider class that cannot be found and instantiated
 182      * @see #find(Class, ClassLoader)
 183      */
 184     public static <T> ServiceFinder<T> find(final Class<T> service) {
 185         return find(service,Thread.currentThread().getContextClassLoader());
 186     }
 187 
 188     private ServiceFinder(Class<T> service, ClassLoader loader) {
 189         this.serviceClass = service;
 190         this.classLoader = loader;
 191     }
 192 
 193     /**
 194      * Returns discovered objects incrementally.
 195      *
 196      * @return An {@code Iterator} that yields provider objects for the given
 197      *         service, in some arbitrary order.  The iterator will throw a
 198      *         {@code ServiceConfigurationError} if a provider-configuration
 199      *         file violates the specified format or if a provider class cannot
 200      *         be found and instantiated.
 201      */
 202     public Iterator<T> iterator() {
 203         return new LazyIterator<T>(serviceClass,classLoader);
 204     }
 205 
 206     /**
 207      * Returns discovered objects all at once.
 208      *
 209      * @return
 210      *      can be empty but never null.
 211      *
 212      * @throws ServiceConfigurationError
 213      */
 214     @SuppressWarnings({"unchecked"})
 215     public T[] toArray() {
 216         List<T> result = new ArrayList<T>();
 217         for (T t : this) {
 218             result.add(t);


 267                 cp = ln.codePointAt(i);
 268                 if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
 269                     fail(service, u, lc, LocalizationMessages.WSP_0066_ILLEGAL_PROVIDER_CLASSNAME(ln), null);
 270             }
 271             if (!returned.contains(ln)) {
 272                 names.add(ln);
 273                 returned.add(ln);
 274             }
 275         }
 276         return lc + 1;
 277     }
 278 
 279     /**
 280      * Parse the content of the given URL as a provider-configuration file.
 281      *
 282      * @param service  The service class for which providers are being sought;
 283      *                 used to construct error detail strings
 284      * @param u        The URL naming the configuration file to be parsed
 285      * @param returned A Set containing the names of provider classes that have already
 286      *                 been returned.  This set will be updated to contain the names
 287      *                 that will be yielded from the returned {@code Iterator}.
 288      * @return A (possibly empty) {@code Iterator} that will yield the
 289      *         provider-class names in the given configuration file that are
 290      *         not yet members of the returned set
 291      * @throws ServiceConfigurationError If an I/O error occurs while reading from the given URL, or
 292      *                                   if a configuration-file format error is detected
 293      */
 294     @SuppressWarnings({"StatementWithEmptyBody"})
 295     private static Iterator<String> parse(Class service, URL u, Set<String> returned)
 296         throws ServiceConfigurationError {
 297         InputStream in = null;
 298         BufferedReader r = null;
 299         ArrayList<String> names = new ArrayList<String>();
 300         try {
 301             in = u.openStream();
 302             r = new BufferedReader(new InputStreamReader(in, "utf-8"));
 303             int lc = 1;
 304             while ((lc = parseLine(service, u, r, lc, names, returned)) >= 0) ;
 305         } catch (IOException x) {
 306             fail(service, ": " + x, x);
 307         } finally {
 308             try {


< prev index next >