diff options
Diffstat (limited to 'libjava/gnu/classpath/ServiceFactory.java')
-rw-r--r-- | libjava/gnu/classpath/ServiceFactory.java | 573 |
1 files changed, 0 insertions, 573 deletions
diff --git a/libjava/gnu/classpath/ServiceFactory.java b/libjava/gnu/classpath/ServiceFactory.java deleted file mode 100644 index 711a9042cbf..00000000000 --- a/libjava/gnu/classpath/ServiceFactory.java +++ /dev/null @@ -1,573 +0,0 @@ -/* ServiceFactory.java -- Factory for plug-in services. - Copyright (C) 2004 Free Software Foundation - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package gnu.classpath; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; - - -/** - * A factory for plug-ins that conform to a service provider - * interface. This is a general mechanism that gets used by a number - * of packages in the Java API. For instance, {@link - * java.nio.charset.spi.CharsetProvider} allows to write custom - * encoders and decoders for character sets, {@link - * javax.imageio.spi.ImageReaderSpi} allows to support custom image - * formats, and {@link javax.print.PrintService} makes it possible to - * write custom printer drivers. - * - * <p>The plug-ins are concrete implementations of the service - * provider interface, which is defined as an interface or an abstract - * class. The implementation classes must be public and have a public - * constructor that takes no arguments. - * - * <p>Plug-ins are usually deployed in JAR files. A JAR that provides - * an implementation of a service must declare this in a resource file - * whose name is the fully qualified service name and whose location - * is the directory <code>META-INF/services</code>. This UTF-8 encoded - * text file lists, on separate lines, the fully qualified names of - * the concrete implementations. Thus, one JAR file can provide an - * arbitrary number of implementations for an arbitrary count of - * service provider interfaces. - * - * <p><b>Example</b> - * - * <p>For example, a JAR might provide two implementations of the - * service provider interface <code>org.foo.ThinkService</code>, - * namely <code>com.acme.QuickThinker</code> and - * <code>com.acme.DeepThinker</code>. The code for <code>QuickThinker</code> - * woud look as follows: - * - * <pre> - * package com.acme; - * - * /** - * * Provices a super-quick, but not very deep implementation of ThinkService. - * */ - * public class QuickThinker - * implements org.foo.ThinkService - * { - * /** - * * Constructs a new QuickThinker. The service factory (which is - * * part of the Java environment) calls this no-argument constructor - * * when it looks up the available implementations of ThinkService. - * * - * * <p>Note that an application might query all available - * * ThinkService providers, but use just one of them. Therefore, - * * constructing an instance should be very inexpensive. For example, - * * large data structures should only be allocated when the service - * * actually gets used. - * */ - * public QuickThinker() - * { - * } - * - * /** - * * Returns the speed of this ThinkService in thoughts per second. - * * Applications can choose among the available service providers - * * based on this value. - * */ - * public double getSpeed() - * { - * return 314159.2654; - * } - * - * /** - * * Produces a thought. While the returned thoughts are not very - * * deep, they are generated in very short time. - * */ - * public Thought think() - * { - * return null; - * } - * } - * </pre> - * - * <p>The code for <code>com.acme.DeepThinker</code> is left as an - * exercise to the reader. - * - * <p>Acme’s <code>ThinkService</code> plug-in gets deployed as - * a JAR file. Besides the bytecode and resources for - * <code>QuickThinker</code> and <code>DeepThinker</code>, it also - * contains the text file - * <code>META-INF/services/org.foo.ThinkService</code>: - * - * <pre> - * # Available implementations of org.foo.ThinkService - * com.acme.QuickThinker - * com.acme.DeepThinker - * </pre> - * - * <p><b>Thread Safety</b> - * - * <p>It is safe to use <code>ServiceFactory</code> from multiple - * concurrent threads without external synchronization. - * - * <p><b>Note for User Applications</b> - * - * <p>User applications that want to load plug-ins should not directly - * use <code>gnu.classpath.ServiceFactory</code>, because this class - * is only available in Java environments that are based on GNU - * Classpath. Instead, it is recommended that user applications call - * {@link - * javax.imageio.spi.ServiceRegistry#lookupProviders(Class)}. This API - * is actually independent of image I/O, and it is available on every - * environment. - * - * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a> - */ -public final class ServiceFactory -{ - /** - * A logger that gets informed when a service gets loaded, or - * when there is a problem with loading a service. - * - * <p>Because {@link java.util.logging.Logger#getLogger(String)} - * is thread-safe, we do not need to worry about synchronization - * here. - */ - private static final Logger LOGGER = Logger.getLogger("gnu.classpath"); - - - /** - * Declared private in order to prevent constructing instances of - * this utility class. - */ - private ServiceFactory() - { - } - - - /** - * Finds service providers that are implementing the specified - * Service Provider Interface. - * - * <p><b>On-demand loading:</b> Loading and initializing service - * providers is delayed as much as possible. The rationale is that - * typical clients will iterate through the set of installed service - * providers until one is found that matches some criteria (like - * supported formats, or quality of service). In such scenarios, it - * might make sense to install only the frequently needed service - * providers on the local machine. More exotic providers can be put - * onto a server; the server will only be contacted when no suitable - * service could be found locally. - * - * <p><b>Security considerations:</b> Any loaded service providers - * are loaded through the specified ClassLoader, or the system - * ClassLoader if <code>classLoader</code> is - * <code>null</code>. When <code>lookupProviders</code> is called, - * the current {@link AccessControlContext} gets recorded. This - * captured security context will determine the permissions when - * services get loaded via the <code>next()</code> method of the - * returned <code>Iterator</code>. - * - * @param spi the service provider interface which must be - * implemented by any loaded service providers. - * - * @param loader the class loader that will be used to load the - * service providers, or <code>null</code> for the system class - * loader. For using the context class loader, see {@link - * #lookupProviders(Class)}. - * - * @return an iterator over instances of <code>spi</code>. - * - * @throws IllegalArgumentException if <code>spi</code> is - * <code>null</code>. - */ - public static Iterator lookupProviders(Class spi, - ClassLoader loader) - { - String resourceName; - Enumeration urls; - - if (spi == null) - throw new IllegalArgumentException(); - - if (loader == null) - loader = ClassLoader.getSystemClassLoader(); - - resourceName = "META-INF/services/" + spi.getName(); - try - { - urls = loader.getResources(resourceName); - } - catch (IOException ioex) - { - /* If an I/O error occurs here, we cannot provide any service - * providers. In this case, we simply return an iterator that - * does not return anything (no providers installed). - */ - log(Level.WARNING, "cannot access {0}", resourceName, ioex); - return Collections.EMPTY_LIST.iterator(); - } - - return new ServiceIterator(spi, urls, loader, - AccessController.getContext()); - } - - - /** - * Finds service providers that are implementing the specified - * Service Provider Interface, using the context class loader - * for loading providers. - * - * @param spi the service provider interface which must be - * implemented by any loaded service providers. - * - * @return an iterator over instances of <code>spi</code>. - * - * @throws IllegalArgumentException if <code>spi</code> is - * <code>null</code>. - * - * @see #lookupProviders(Class, ClassLoader) - */ - public static Iterator lookupProviders(Class spi) - { - ClassLoader ctxLoader; - - ctxLoader = Thread.currentThread().getContextClassLoader(); - return lookupProviders(spi, ctxLoader); - } - - - /** - * An iterator over service providers that are listed in service - * provider configuration files, which get passed as an Enumeration - * of URLs. This is a helper class for {@link - * ServiceFactory#lookupProviders}. - * - * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a> - */ - private static final class ServiceIterator - implements Iterator - { - /** - * The service provider interface (usually an interface, sometimes - * an abstract class) which the services must implement. - */ - private final Class spi; - - - /** - * An Enumeration<URL> over the URLs that contain a resource - * <code>META-INF/services/<org.foo.SomeService></code>, - * as returned by {@link ClassLoader#getResources(String)}. - */ - private final Enumeration urls; - - - /** - * The class loader used for loading service providers. - */ - private final ClassLoader loader; - - - /** - * The security context used when loading and initializing service - * providers. We want to load and initialize all plug-in service - * providers under the same security context, namely the one that - * was active when {@link #lookupProviders} has been called. - */ - private final AccessControlContext securityContext; - - - /** - * A reader for the current file listing class names of service - * implementors, or <code>null</code> when the last reader has - * been fetched. - */ - private BufferedReader reader; - - - /** - * The URL currently being processed. This is only used for - * emitting error messages. - */ - private URL currentURL; - - - /** - * The service provider that will be returned by the next call to - * {@link #next()}, or <code>null</code> if the iterator has - * already returned all service providers. - */ - private Object nextProvider; - - - /** - * Constructs an Iterator that loads and initializes services on - * demand. - * - * @param spi the service provider interface which the services - * must implement. Usually, this is a Java interface type, but it - * might also be an abstract class or even a concrete superclass. - * - * @param urls an Enumeration<URL> over the URLs that contain a - * resource - * <code>META-INF/services/<org.foo.SomeService></code>, as - * determined by {@link ClassLoader#getResources(String)}. - * - * @param loader the ClassLoader that gets used for loading - * service providers. - * - * @param securityContext the security context to use when loading - * and initializing service providers. - */ - ServiceIterator(Class spi, Enumeration urls, ClassLoader loader, - AccessControlContext securityContext) - { - this.spi = spi; - this.urls = urls; - this.loader = loader; - this.securityContext = securityContext; - this.nextProvider = loadNextServiceProvider(); - } - - - /** - * @throws NoSuchElementException if {@link #hasNext} returns - * <code>false</code>. - */ - public Object next() - { - Object result; - - if (!hasNext()) - throw new NoSuchElementException(); - - result = nextProvider; - nextProvider = loadNextServiceProvider(); - return result; - } - - - public boolean hasNext() - { - return nextProvider != null; - } - - - public void remove() - { - throw new UnsupportedOperationException(); - } - - - private Object loadNextServiceProvider() - { - String line; - - if (reader == null) - advanceReader(); - - for (;;) - { - /* If we have reached the last provider list, we cannot - * retrieve any further lines. - */ - if (reader == null) - return null; - - try - { - line = reader.readLine(); - } - catch (IOException readProblem) - { - log(Level.WARNING, "IOException upon reading {0}", currentURL, - readProblem); - line = null; - } - - /* When we are at the end of one list of services, - * switch over to the next one. - */ - if (line == null) - { - advanceReader(); - continue; - } - - - // Skip whitespace at the beginning and end of each line. - line = line.trim(); - - // Skip empty lines. - if (line.length() == 0) - continue; - - // Skip comment lines. - if (line.charAt(0) == '#') - continue; - - try - { - log(Level.FINE, - "Loading service provider \"{0}\", specified" - + " by \"META-INF/services/{1}\" in {2}.", - new Object[] { line, spi.getName(), currentURL }, - null); - - /* Load the class in the security context that was - * active when calling lookupProviders. - */ - return AccessController.doPrivileged( - new ServiceProviderLoadingAction(spi, line, loader), - securityContext); - } - catch (Exception ex) - { - String msg = "Cannot load service provider class \"{0}\"," - + " specified by \"META-INF/services/{1}\" in {2}"; - if (ex instanceof PrivilegedActionException - && ex.getCause() instanceof ClassCastException) - msg = "Service provider class \"{0}\" is not an instance" - + " of \"{1}\". Specified" - + " by \"META-INF/services/{1}\" in {2}."; - - log(Level.WARNING, msg, - new Object[] { line, spi.getName(), currentURL }, - ex); - continue; - } - } - } - - - private void advanceReader() - { - do - { - if (reader != null) - { - try - { - reader.close(); - log(Level.FINE, "closed {0}", currentURL, null); - } - catch (Exception ex) - { - log(Level.WARNING, "cannot close {0}", currentURL, ex); - } - reader = null; - currentURL = null; - } - - if (!urls.hasMoreElements()) - return; - - currentURL = (URL) urls.nextElement(); - try - { - reader = new BufferedReader(new InputStreamReader( - currentURL.openStream(), "UTF-8")); - log(Level.FINE, "opened {0}", currentURL, null); - } - catch (Exception ex) - { - log(Level.WARNING, "cannot open {0}", currentURL, ex); - } - } - while (reader == null); - } - } - - - // Package-private to avoid a trampoline. - /** - * Passes a log message to the <code>java.util.logging</code> - * framework. This call returns very quickly if no log message will - * be produced, so there is not much overhead in the standard case. - * - * @param the severity of the message, for instance {@link - * Level#WARNING}. - * - * @param msg the log message, for instance <code>“Could not - * load {0}.”</code> - * - * @param param the parameter(s) for the log message, or - * <code>null</code> if <code>msg</code> does not specify any - * parameters. If <code>param</code> is not an array, an array with - * <code>param</code> as its single element gets passed to the - * logging framework. - * - * @param t a Throwable that is associated with the log record, or - * <code>null</code> if the log message is not associated with a - * Throwable. - */ - static void log(Level level, String msg, Object param, Throwable t) - { - LogRecord rec; - - // Return quickly if no log message will be produced. - if (!LOGGER.isLoggable(level)) - return; - - rec = new LogRecord(level, msg); - if (param != null && param.getClass().isArray()) - rec.setParameters((Object[]) param); - else - rec.setParameters(new Object[] { param }); - - rec.setThrown(t); - - // While java.util.logging can sometimes infer the class and - // method of the caller, this automatic inference is not reliable - // on highly optimizing VMs. Also, log messages make more sense to - // developers when they display a public method in a public class; - // otherwise, they might feel tempted to figure out the internals - // of ServiceFactory in order to understand the problem. - rec.setSourceClassName(ServiceFactory.class.getName()); - rec.setSourceMethodName("lookupProviders"); - - LOGGER.log(rec); - } -} |