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 * <p> Service providers found on the system classpath (typically 68 * the <code>lib/ext</code> directory in the Java 69 * installation directory) are automatically loaded as soon as this class is 70 * instantiated. 71 * 72 * <p> When the <code>registerApplicationClasspathSpis</code> method 73 * is called, service provider instances declared in the 74 * meta-information section of JAR files on the application class path 75 * are loaded. To declare a service provider, a <code>services</code> 76 * subdirectory is placed within the <code>META-INF</code> directory 77 * that is present in every JAR file. This directory contains a file 78 * for each service provider interface that has one or more 79 * implementation classes present in the JAR file. For example, if 80 * the JAR file contained a class named 81 * <code>com.mycompany.imageio.MyFormatReaderSpi</code> which 82 * implements the <code>ImageReaderSpi</code> interface, the JAR file 83 * would contain a file named: 84 * 85 * <pre> 86 * META-INF/services/javax.imageio.spi.ImageReaderSpi 87 * </pre> 88 * 89 * containing the line: 90 * 91 * <pre> 92 * com.mycompany.imageio.MyFormatReaderSpi 93 * </pre> 94 * 95 * <p> The service provider classes are intended to be lightweight 96 * and quick to load. Implementations of these interfaces 97 * should avoid complex dependencies on other classes and on 98 * native code. 99 * 100 * <p> It is also possible to manually add service providers not found 101 * automatically, as well as to remove those that are using the 102 * interfaces of the <code>ServiceRegistry</code> class. Thus 103 * the application may customize the contents of the registry as it 104 * sees fit. 105 * 106 * <p> For more details on declaring service providers, and the JAR 107 * format in general, see the <a 108 * href="{@docRoot}/../technotes/guides/jar/jar.html"> 109 * JAR File Specification</a>. 110 * 111 */ 112 public final class IIORegistry extends ServiceRegistry { 113 114 /** 115 * A <code>Vector</code> containing the valid IIO registry 116 * categories (superinterfaces) to be used in the constructor. 117 */ 118 private static final Vector<Class<?>> initialCategories = new Vector<>(5); 119 120 static { 121 initialCategories.add(ImageReaderSpi.class); 122 initialCategories.add(ImageWriterSpi.class); 123 initialCategories.add(ImageTranscoderSpi.class); 124 initialCategories.add(ImageInputStreamSpi.class); 125 initialCategories.add(ImageOutputStreamSpi.class); 126 } 127 128 /** 129 * Set up the valid service provider categories and automatically 130 * register all available service providers. 131 * 132 * <p> The constructor is private in order to prevent creation of 133 * additional instances. 134 */ 135 private IIORegistry() { 136 super(initialCategories.iterator()); 137 registerStandardSpis(); 138 registerApplicationClasspathSpis(); 139 } 140 141 /** 142 * Returns the default <code>IIORegistry</code> instance used by 143 * the Image I/O API. This instance should be used for all 144 * registry functions. 145 * 146 * <p> Each <code>ThreadGroup</code> will receive its own 147 * instance; this allows different <code>Applet</code>s in the 148 * same browser (for example) to each have their own registry. 149 * 150 * @return the default registry for the current 151 * <code>ThreadGroup</code>. 152 */ 153 public static IIORegistry getDefaultInstance() { 154 AppContext context = AppContext.getAppContext(); 155 IIORegistry registry = 156 (IIORegistry)context.get(IIORegistry.class); 157 if (registry == null) { 158 // Create an instance for this AppContext 159 registry = new IIORegistry(); 160 context.put(IIORegistry.class, registry); 161 } 162 return registry; 163 } 164 165 private void registerStandardSpis() { 166 // Hardwire standard SPIs 167 registerServiceProvider(new GIFImageReaderSpi()); 168 registerServiceProvider(new GIFImageWriterSpi()); 169 registerServiceProvider(new BMPImageReaderSpi()); 170 registerServiceProvider(new BMPImageWriterSpi()); 171 registerServiceProvider(new WBMPImageReaderSpi()); 172 registerServiceProvider(new WBMPImageWriterSpi()); 173 registerServiceProvider(new PNGImageReaderSpi()); 174 registerServiceProvider(new PNGImageWriterSpi()); 175 registerServiceProvider(new JPEGImageReaderSpi()); 176 registerServiceProvider(new JPEGImageWriterSpi()); 177 registerServiceProvider(new FileImageInputStreamSpi()); 178 registerServiceProvider(new FileImageOutputStreamSpi()); 179 registerServiceProvider(new InputStreamImageInputStreamSpi()); 180 registerServiceProvider(new OutputStreamImageOutputStreamSpi()); 181 registerServiceProvider(new RAFImageInputStreamSpi()); 182 registerServiceProvider(new RAFImageOutputStreamSpi()); 183 184 registerInstalledProviders(); 185 } 186 187 /** 188 * Registers all available service providers found on the 189 * application class path, using the default 190 * <code>ClassLoader</code>. This method is typically invoked by 191 * the <code>ImageIO.scanForPlugins</code> method. 192 * 193 * @see javax.imageio.ImageIO#scanForPlugins 194 * @see ClassLoader#getResources 195 */ 196 public void registerApplicationClasspathSpis() { 197 // FIX: load only from application classpath 198 199 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 200 201 Iterator<Class<?>> categories = getCategories(); 202 while (categories.hasNext()) { 203 @SuppressWarnings("unchecked") 204 Class<IIOServiceProvider> c = (Class<IIOServiceProvider>)categories.next(); 205 Iterator<IIOServiceProvider> riter = 206 ServiceLoader.load(c, loader).iterator(); 207 while (riter.hasNext()) { 208 try { 209 // Note that the next() call is required to be inside 210 // the try/catch block; see 6342404. 211 IIOServiceProvider r = riter.next(); 212 registerServiceProvider(r); 213 } catch (ServiceConfigurationError err) { 214 if (System.getSecurityManager() != null) { 215 // In the applet case, we will catch the error so 216 // registration of other plugins can proceed 217 err.printStackTrace(); 218 } else { 219 // In the application case, we will throw the 220 // error to indicate app/system misconfiguration 221 throw err; 222 } 223 } 224 } 225 } 226 } 227 228 private void registerInstalledProviders() { 229 /* 230 We need to load installed providers from the 231 system classpath (typically the <code>lib/ext</code> 232 directory in in the Java installation directory) 233 in the privileged mode in order to 234 be able read corresponding jar files even if 235 file read capability is restricted (like the 236 applet context case). 237 */ 238 PrivilegedAction<Object> doRegistration = 239 new PrivilegedAction<Object>() { 240 public Object run() { 241 Iterator<Class<?>> categories = getCategories(); 242 while (categories.hasNext()) { 243 @SuppressWarnings("unchecked") 244 Class<IIOServiceProvider> c = (Class<IIOServiceProvider>)categories.next(); 245 for (IIOServiceProvider p : ServiceLoader.loadInstalled(c)) { 246 registerServiceProvider(p); 247 } 248 } 249 return this; 250 } 251 }; 252 253 AccessController.doPrivileged(doRegistration); 254 } 255 }