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 */
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 */
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
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 */
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
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