1 /*
   2  * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.imageio.spi;
  27 
  28 import java.security.PrivilegedAction;
  29 import java.security.AccessController;
  30 import java.util.HashMap;
  31 import java.util.Iterator;
  32 import java.util.Map;
  33 import java.util.NoSuchElementException;
  34 import java.util.Set;
  35 import java.util.Vector;
  36 import com.sun.imageio.spi.FileImageInputStreamSpi;
  37 import com.sun.imageio.spi.FileImageOutputStreamSpi;
  38 import com.sun.imageio.spi.InputStreamImageInputStreamSpi;
  39 import com.sun.imageio.spi.OutputStreamImageOutputStreamSpi;
  40 import com.sun.imageio.spi.RAFImageInputStreamSpi;
  41 import com.sun.imageio.spi.RAFImageOutputStreamSpi;
  42 import com.sun.imageio.plugins.gif.GIFImageReaderSpi;
  43 import com.sun.imageio.plugins.gif.GIFImageWriterSpi;
  44 import com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi;
  45 import com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi;
  46 import com.sun.imageio.plugins.png.PNGImageReaderSpi;
  47 import com.sun.imageio.plugins.png.PNGImageWriterSpi;
  48 import com.sun.imageio.plugins.bmp.BMPImageReaderSpi;
  49 import com.sun.imageio.plugins.bmp.BMPImageWriterSpi;
  50 import com.sun.imageio.plugins.wbmp.WBMPImageReaderSpi;
  51 import com.sun.imageio.plugins.wbmp.WBMPImageWriterSpi;
  52 import sun.awt.AppContext;
  53 import java.util.ServiceLoader;
  54 import java.util.ServiceConfigurationError;
  55 
  56 /**
  57  * A registry for service provider instances.  Service provider
  58  * classes may be detected at run time by means of meta-information in
  59  * the JAR files containing them.  The intent is that it be relatively
  60  * inexpensive to load and inspect all available service provider
  61  * classes.  These classes may them be used to locate and instantiate
  62  * more heavyweight classes that will perform actual work, in this
  63  * case instances of <code>ImageReader</code>,
  64  * <code>ImageWriter</code>, <code>ImageTranscoder</code>,
  65  * <code>ImageInputStream</code>, and <code>ImageOutputStream</code>.
  66  *
  67  * Service providers found from the Java platform are automatically
  68  * loaded as soon as this class is instantiated.
  69  *
  70  * <p> When the <code>registerApplicationClasspathSpis</code> method
  71  * is called, service provider instances declared in the
  72  * meta-information section of JAR files on the application class path
  73  * are loaded.  To declare a service provider, a <code>services</code>
  74  * subdirectory is placed within the <code>META-INF</code> directory
  75  * that is present in every JAR file.  This directory contains a file
  76  * for each service provider interface that has one or more
  77  * implementation classes present in the JAR file.  For example, if
  78  * the JAR file contained a class named
  79  * <code>com.mycompany.imageio.MyFormatReaderSpi</code> which
  80  * implements the <code>ImageReaderSpi</code> interface, the JAR file
  81  * would contain a file named:
  82  *
  83  * <pre>
  84  * META-INF/services/javax.imageio.spi.ImageReaderSpi
  85  * </pre>
  86  *
  87  * containing the line:
  88  *
  89  * <pre>
  90  * com.mycompany.imageio.MyFormatReaderSpi
  91  * </pre>
  92  *
  93  * <p> The service provider classes are intended to be lightweight
  94  * and quick to load.  Implementations of these interfaces
  95  * should avoid complex dependencies on other classes and on
  96  * native code.
  97  *
  98  * <p> It is also possible to manually add service providers not found
  99  * automatically, as well as to remove those that are using the
 100  * interfaces of the <code>ServiceRegistry</code> class.  Thus
 101  * the application may customize the contents of the registry as it
 102  * sees fit.
 103  *
 104  * <p> For more details on declaring service providers, and the JAR
 105  * format in general, see the <a
 106  * href="{@docRoot}/../technotes/guides/jar/jar.html">
 107  * JAR File Specification</a>.
 108  *
 109  */
 110 public final class IIORegistry extends ServiceRegistry {
 111 
 112     /**
 113      * A <code>Vector</code> containing the valid IIO registry
 114      * categories (superinterfaces) to be used in the constructor.
 115      */
 116     private static final Vector<Class<?>> initialCategories = new Vector<>(5);
 117 
 118     static {
 119         initialCategories.add(ImageReaderSpi.class);
 120         initialCategories.add(ImageWriterSpi.class);
 121         initialCategories.add(ImageTranscoderSpi.class);
 122         initialCategories.add(ImageInputStreamSpi.class);
 123         initialCategories.add(ImageOutputStreamSpi.class);
 124     }
 125 
 126     /**
 127      * Set up the valid service provider categories and automatically
 128      * register all available service providers.
 129      *
 130      * <p> The constructor is private in order to prevent creation of
 131      * additional instances.
 132      */
 133     private IIORegistry() {
 134         super(initialCategories.iterator());
 135         registerStandardSpis();
 136         registerApplicationClasspathSpis();
 137     }
 138 
 139     /**
 140      * Returns the default <code>IIORegistry</code> instance used by
 141      * the Image I/O API.  This instance should be used for all
 142      * registry functions.
 143      *
 144      * <p> Each <code>ThreadGroup</code> will receive its own
 145      * instance; this allows different <code>Applet</code>s in the
 146      * same browser (for example) to each have their own registry.
 147      *
 148      * @return the default registry for the current
 149      * <code>ThreadGroup</code>.
 150      */
 151     public static IIORegistry getDefaultInstance() {
 152         AppContext context = AppContext.getAppContext();
 153         IIORegistry registry =
 154             (IIORegistry)context.get(IIORegistry.class);
 155         if (registry == null) {
 156             // Create an instance for this AppContext
 157             registry = new IIORegistry();
 158             context.put(IIORegistry.class, registry);
 159         }
 160         return registry;
 161     }
 162 
 163     private void registerStandardSpis() {
 164         // Hardwire standard SPIs
 165         registerServiceProvider(new GIFImageReaderSpi());
 166         registerServiceProvider(new GIFImageWriterSpi());
 167         registerServiceProvider(new BMPImageReaderSpi());
 168         registerServiceProvider(new BMPImageWriterSpi());
 169         registerServiceProvider(new WBMPImageReaderSpi());
 170         registerServiceProvider(new WBMPImageWriterSpi());
 171         registerServiceProvider(new PNGImageReaderSpi());
 172         registerServiceProvider(new PNGImageWriterSpi());
 173         registerServiceProvider(new JPEGImageReaderSpi());
 174         registerServiceProvider(new JPEGImageWriterSpi());
 175         registerServiceProvider(new FileImageInputStreamSpi());
 176         registerServiceProvider(new FileImageOutputStreamSpi());
 177         registerServiceProvider(new InputStreamImageInputStreamSpi());
 178         registerServiceProvider(new OutputStreamImageOutputStreamSpi());
 179         registerServiceProvider(new RAFImageInputStreamSpi());
 180         registerServiceProvider(new RAFImageOutputStreamSpi());
 181 
 182         registerInstalledProviders();
 183     }
 184 
 185     /**
 186      * Registers all available service providers found on the
 187      * application class path, using the default
 188      * <code>ClassLoader</code>.  This method is typically invoked by
 189      * the <code>ImageIO.scanForPlugins</code> method.
 190      *
 191      * @see javax.imageio.ImageIO#scanForPlugins
 192      * @see ClassLoader#getResources
 193      */
 194     public void registerApplicationClasspathSpis() {
 195         // FIX: load only from application classpath
 196 
 197         ClassLoader loader = Thread.currentThread().getContextClassLoader();
 198 
 199         Iterator<Class<?>> categories = getCategories();
 200         while (categories.hasNext()) {
 201             @SuppressWarnings("unchecked")
 202             Class<IIOServiceProvider> c = (Class<IIOServiceProvider>)categories.next();
 203             Iterator<IIOServiceProvider> riter =
 204                     ServiceLoader.load(c, loader).iterator();
 205             while (riter.hasNext()) {
 206                 try {
 207                     // Note that the next() call is required to be inside
 208                     // the try/catch block; see 6342404.
 209                     IIOServiceProvider r = riter.next();
 210                     registerServiceProvider(r);
 211                 } catch (ServiceConfigurationError err) {
 212                     if (System.getSecurityManager() != null) {
 213                         // In the applet case, we will catch the  error so
 214                         // registration of other plugins can  proceed
 215                         err.printStackTrace();
 216                     } else {
 217                         // In the application case, we will  throw the
 218                         // error to indicate app/system  misconfiguration
 219                         throw err;
 220                     }
 221                 }
 222             }
 223         }
 224     }
 225 
 226     private void registerInstalledProviders() {
 227         /*
 228           We need to load installed providers
 229           in the privileged mode in order to
 230           be able read corresponding jar files even if
 231           file read capability is restricted (like the
 232           applet context case).
 233          */
 234         PrivilegedAction<Object> doRegistration =
 235             new PrivilegedAction<Object>() {
 236                 public Object run() {
 237                     Iterator<Class<?>> categories = getCategories();
 238                     while (categories.hasNext()) {
 239                         @SuppressWarnings("unchecked")
 240                         Class<IIOServiceProvider> c = (Class<IIOServiceProvider>)categories.next();
 241                         for (IIOServiceProvider p : ServiceLoader.loadInstalled(c)) {
 242                             registerServiceProvider(p);
 243                         }
 244                     }
 245                     return this;
 246                 }
 247             };
 248 
 249         AccessController.doPrivileged(doRegistration);
 250     }
 251 }
--- EOF ---