1 /* 2 * Copyright (c) 1999, 2017, 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 com.sun.imageio.plugins.tiff.TIFFImageReaderSpi; 53 import com.sun.imageio.plugins.tiff.TIFFImageWriterSpi; 54 import sun.awt.AppContext; 55 import java.util.ServiceLoader; 56 import java.util.ServiceConfigurationError; 57 58 /** 59 * A registry for Image I/O service provider instances. Service provider 60 * classes may be discovered at runtime by the mechanisms documented in 61 * {@link java.util.ServiceLoader ServiceLoader}. 62 * 63 * The intent is that it be relatively inexpensive to load and inspect 64 * all available Image I/O service provider classes. 65 * These classes may then be used to locate and instantiate 66 * more heavyweight classes that will perform actual work, in this 67 * case instances of {@code ImageReader}, 68 * {@code ImageWriter}, {@code ImageTranscoder}, 69 * {@code ImageInputStream}, and {@code ImageOutputStream}. 70 * 71 * Service providers included in the Java runtime are automatically 72 * loaded as soon as this class is instantiated. 73 * 74 * <p> When the {@code registerApplicationClasspathSpis} method 75 * is called, additional service provider instances will be discovered 76 * using {@link java.util.ServiceLoader ServiceLoader}. 77 * 78 * <p> It is also possible to manually add service providers not found 79 * automatically, as well as to remove those that are using the 80 * interfaces of the {@code ServiceRegistry} class. Thus 81 * the application may customize the contents of the registry as it 82 * sees fit. 83 * 84 * <p> For information on how to create and deploy service providers, 85 * refer to the documentation on {@link java.util.ServiceLoader ServiceLoader} 86 */ 87 public final class IIORegistry extends ServiceRegistry { 88 89 /** 90 * A {@code Vector} containing the valid IIO registry 91 * categories (superinterfaces) to be used in the constructor. 92 */ 93 private static final Vector<Class<?>> initialCategories = new Vector<>(5); 94 95 static { 96 initialCategories.add(ImageReaderSpi.class); 97 initialCategories.add(ImageWriterSpi.class); 98 initialCategories.add(ImageTranscoderSpi.class); 99 initialCategories.add(ImageInputStreamSpi.class); 100 initialCategories.add(ImageOutputStreamSpi.class); 101 } 102 103 /** 104 * Set up the valid service provider categories and automatically 105 * register all available service providers. 106 * 107 * <p> The constructor is private in order to prevent creation of 108 * additional instances. 109 */ IIORegistry()110 private IIORegistry() { 111 super(initialCategories.iterator()); 112 registerStandardSpis(); 113 registerApplicationClasspathSpis(); 114 } 115 116 /** 117 * Returns the default {@code IIORegistry} instance used by 118 * the Image I/O API. This instance should be used for all 119 * registry functions. 120 * 121 * <p> Each {@code ThreadGroup} will receive its own 122 * instance; this allows different {@code Applet}s in the 123 * same browser (for example) to each have their own registry. 124 * 125 * @return the default registry for the current 126 * {@code ThreadGroup}. 127 */ getDefaultInstance()128 public static IIORegistry getDefaultInstance() { 129 AppContext context = AppContext.getAppContext(); 130 IIORegistry registry = 131 (IIORegistry)context.get(IIORegistry.class); 132 if (registry == null) { 133 // Create an instance for this AppContext 134 registry = new IIORegistry(); 135 context.put(IIORegistry.class, registry); 136 } 137 return registry; 138 } 139 registerStandardSpis()140 private void registerStandardSpis() { 141 // Hardwire standard SPIs 142 registerServiceProvider(new GIFImageReaderSpi()); 143 registerServiceProvider(new GIFImageWriterSpi()); 144 registerServiceProvider(new BMPImageReaderSpi()); 145 registerServiceProvider(new BMPImageWriterSpi()); 146 registerServiceProvider(new WBMPImageReaderSpi()); 147 registerServiceProvider(new WBMPImageWriterSpi()); 148 registerServiceProvider(new TIFFImageReaderSpi()); 149 registerServiceProvider(new TIFFImageWriterSpi()); 150 registerServiceProvider(new PNGImageReaderSpi()); 151 registerServiceProvider(new PNGImageWriterSpi()); 152 registerServiceProvider(new JPEGImageReaderSpi()); 153 registerServiceProvider(new JPEGImageWriterSpi()); 154 registerServiceProvider(new FileImageInputStreamSpi()); 155 registerServiceProvider(new FileImageOutputStreamSpi()); 156 registerServiceProvider(new InputStreamImageInputStreamSpi()); 157 registerServiceProvider(new OutputStreamImageOutputStreamSpi()); 158 registerServiceProvider(new RAFImageInputStreamSpi()); 159 registerServiceProvider(new RAFImageOutputStreamSpi()); 160 161 registerInstalledProviders(); 162 } 163 164 /** 165 * Registers all available service providers found on the 166 * application class path, using the default 167 * {@code ClassLoader}. This method is typically invoked by 168 * the {@code ImageIO.scanForPlugins} method. 169 * 170 * @see javax.imageio.ImageIO#scanForPlugins 171 * @see ClassLoader#getResources 172 */ registerApplicationClasspathSpis()173 public void registerApplicationClasspathSpis() { 174 // FIX: load only from application classpath 175 176 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 177 178 Iterator<Class<?>> categories = getCategories(); 179 while (categories.hasNext()) { 180 @SuppressWarnings("unchecked") 181 Class<IIOServiceProvider> c = (Class<IIOServiceProvider>)categories.next(); 182 Iterator<IIOServiceProvider> riter = 183 ServiceLoader.load(c, loader).iterator(); 184 while (riter.hasNext()) { 185 try { 186 // Note that the next() call is required to be inside 187 // the try/catch block; see 6342404. 188 IIOServiceProvider r = riter.next(); 189 registerServiceProvider(r); 190 } catch (ServiceConfigurationError err) { 191 if (System.getSecurityManager() != null) { 192 // In the applet case, we will catch the error so 193 // registration of other plugins can proceed 194 err.printStackTrace(); 195 } else { 196 // In the application case, we will throw the 197 // error to indicate app/system misconfiguration 198 throw err; 199 } 200 } 201 } 202 } 203 } 204 registerInstalledProviders()205 private void registerInstalledProviders() { 206 /* 207 We need to load installed providers 208 in the privileged mode in order to 209 be able read corresponding jar files even if 210 file read capability is restricted (like the 211 applet context case). 212 */ 213 PrivilegedAction<Object> doRegistration = 214 new PrivilegedAction<Object>() { 215 public Object run() { 216 Iterator<Class<?>> categories = getCategories(); 217 while (categories.hasNext()) { 218 @SuppressWarnings("unchecked") 219 Class<IIOServiceProvider> c = (Class<IIOServiceProvider>)categories.next(); 220 for (IIOServiceProvider p : ServiceLoader.loadInstalled(c)) { 221 registerServiceProvider(p); 222 } 223 } 224 return this; 225 } 226 }; 227 228 AccessController.doPrivileged(doRegistration); 229 } 230 } 231