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}, 64 * {@code ImageWriter}, {@code ImageTranscoder}, 65 * {@code ImageInputStream}, and {@code ImageOutputStream}. 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} 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} 74 * subdirectory is placed within the {@code META-INF} 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} which 80 * implements the {@code ImageReaderSpi} 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} 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} 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} 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} will receive its own 145 * instance; this allows different {@code Applet}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}. 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}. This method is typically invoked by 189 * the {@code ImageIO.scanForPlugins} 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 ---