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