/* * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.imageio.spi; import java.security.PrivilegedAction; import java.security.AccessController; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.Vector; import com.sun.imageio.spi.FileImageInputStreamSpi; import com.sun.imageio.spi.FileImageOutputStreamSpi; import com.sun.imageio.spi.InputStreamImageInputStreamSpi; import com.sun.imageio.spi.OutputStreamImageOutputStreamSpi; import com.sun.imageio.spi.RAFImageInputStreamSpi; import com.sun.imageio.spi.RAFImageOutputStreamSpi; import com.sun.imageio.plugins.gif.GIFImageReaderSpi; import com.sun.imageio.plugins.gif.GIFImageWriterSpi; import com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi; import com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi; import com.sun.imageio.plugins.png.PNGImageReaderSpi; import com.sun.imageio.plugins.png.PNGImageWriterSpi; import com.sun.imageio.plugins.bmp.BMPImageReaderSpi; import com.sun.imageio.plugins.bmp.BMPImageWriterSpi; import com.sun.imageio.plugins.wbmp.WBMPImageReaderSpi; import com.sun.imageio.plugins.wbmp.WBMPImageWriterSpi; import sun.awt.AppContext; import java.util.ServiceLoader; import java.util.ServiceConfigurationError; /** * A registry for service provider instances. Service provider * classes may be detected at run time by means of meta-information in * the JAR files containing them. The intent is that it be relatively * inexpensive to load and inspect all available service provider * classes. These classes may them be used to locate and instantiate * more heavyweight classes that will perform actual work, in this * case instances of ImageReader, * ImageWriter, ImageTranscoder, * ImageInputStream, and ImageOutputStream. * *

Service providers found on the system classpath (e.g., * the jre/lib/ext directory in Sun's implementation of * JDK) are automatically loaded as soon as this class is * instantiated. * *

When the registerApplicationClasspathSpis method * is called, service provider instances declared in the * meta-information section of JAR files on the application class path * are loaded. To declare a service provider, a services * subdirectory is placed within the META-INF directory * that is present in every JAR file. This directory contains a file * for each service provider interface that has one or more * implementation classes present in the JAR file. For example, if * the JAR file contained a class named * com.mycompany.imageio.MyFormatReaderSpi which * implements the ImageReaderSpi interface, the JAR file * would contain a file named: * *

 * META-INF/services/javax.imageio.spi.ImageReaderSpi
 * 
* * containing the line: * *
 * com.mycompany.imageio.MyFormatReaderSpi
 * 
* *

The service provider classes are intended to be lightweight * and quick to load. Implementations of these interfaces * should avoid complex dependencies on other classes and on * native code. * *

It is also possible to manually add service providers not found * automatically, as well as to remove those that are using the * interfaces of the ServiceRegistry class. Thus * the application may customize the contents of the registry as it * sees fit. * *

For more details on declaring service providers, and the JAR * format in general, see the * JAR File Specification. * */ public final class IIORegistry extends ServiceRegistry { /** * A Vector containing the valid IIO registry * categories (superinterfaces) to be used in the constructor. */ private static final Vector initialCategories = new Vector(5); static { initialCategories.add(ImageReaderSpi.class); initialCategories.add(ImageWriterSpi.class); initialCategories.add(ImageTranscoderSpi.class); initialCategories.add(ImageInputStreamSpi.class); initialCategories.add(ImageOutputStreamSpi.class); } /** * Set up the valid service provider categories and automatically * register all available service providers. * *

The constructor is private in order to prevent creation of * additional instances. */ private IIORegistry() { super(initialCategories.iterator()); registerStandardSpis(); registerApplicationClasspathSpis(); } /** * Returns the default IIORegistry instance used by * the Image I/O API. This instance should be used for all * registry functions. * *

Each ThreadGroup will receive its own * instance; this allows different Applets in the * same browser (for example) to each have their own registry. * * @return the default registry for the current * ThreadGroup. */ public static IIORegistry getDefaultInstance() { AppContext context = AppContext.getAppContext(); IIORegistry registry = (IIORegistry)context.get(IIORegistry.class); if (registry == null) { // Create an instance for this AppContext registry = new IIORegistry(); context.put(IIORegistry.class, registry); } return registry; } private void registerStandardSpis() { // Hardwire standard SPIs registerServiceProvider(new GIFImageReaderSpi()); registerServiceProvider(new GIFImageWriterSpi()); registerServiceProvider(new BMPImageReaderSpi()); registerServiceProvider(new BMPImageWriterSpi()); registerServiceProvider(new WBMPImageReaderSpi()); registerServiceProvider(new WBMPImageWriterSpi()); registerServiceProvider(new PNGImageReaderSpi()); registerServiceProvider(new PNGImageWriterSpi()); registerServiceProvider(new JPEGImageReaderSpi()); registerServiceProvider(new JPEGImageWriterSpi()); registerServiceProvider(new FileImageInputStreamSpi()); registerServiceProvider(new FileImageOutputStreamSpi()); registerServiceProvider(new InputStreamImageInputStreamSpi()); registerServiceProvider(new OutputStreamImageOutputStreamSpi()); registerServiceProvider(new RAFImageInputStreamSpi()); registerServiceProvider(new RAFImageOutputStreamSpi()); registerInstalledProviders(); } /** * Registers all available service providers found on the * application class path, using the default * ClassLoader. This method is typically invoked by * the ImageIO.scanForPlugins method. * * @see javax.imageio.ImageIO#scanForPlugins * @see ClassLoader#getResources */ public void registerApplicationClasspathSpis() { // FIX: load only from application classpath ClassLoader loader = Thread.currentThread().getContextClassLoader(); Iterator categories = getCategories(); while (categories.hasNext()) { Class c = (Class)categories.next(); Iterator riter = ServiceLoader.load(c, loader).iterator(); while (riter.hasNext()) { try { // Note that the next() call is required to be inside // the try/catch block; see 6342404. IIOServiceProvider r = riter.next(); registerServiceProvider(r); } catch (ServiceConfigurationError err) { if (System.getSecurityManager() != null) { // In the applet case, we will catch the error so // registration of other plugins can proceed err.printStackTrace(); } else { // In the application case, we will throw the // error to indicate app/system misconfiguration throw err; } } } } } private void registerInstalledProviders() { /* We need load installed providers from lib/ext directory in the privileged mode in order to be able read corresponding jar files even if file read capability is restricted (like the applet context case). */ PrivilegedAction doRegistration = new PrivilegedAction() { public Object run() { Iterator categories = getCategories(); while (categories.hasNext()) { Class c = (Class)categories.next(); for (IIOServiceProvider p : ServiceLoader.loadInstalled(c)) { registerServiceProvider(p); } } return this; } }; AccessController.doPrivileged(doRegistration); } }