001 /*
002 * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.imageio.spi;
027
028 import java.security.PrivilegedAction;
029 import java.security.AccessController;
030 import java.util.HashMap;
031 import java.util.Iterator;
032 import java.util.Map;
033 import java.util.NoSuchElementException;
034 import java.util.Set;
035 import java.util.Vector;
036 import com.sun.imageio.spi.FileImageInputStreamSpi;
037 import com.sun.imageio.spi.FileImageOutputStreamSpi;
038 import com.sun.imageio.spi.InputStreamImageInputStreamSpi;
039 import com.sun.imageio.spi.OutputStreamImageOutputStreamSpi;
040 import com.sun.imageio.spi.RAFImageInputStreamSpi;
041 import com.sun.imageio.spi.RAFImageOutputStreamSpi;
042 import com.sun.imageio.plugins.gif.GIFImageReaderSpi;
043 import com.sun.imageio.plugins.gif.GIFImageWriterSpi;
044 import com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi;
045 import com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi;
046 import com.sun.imageio.plugins.png.PNGImageReaderSpi;
047 import com.sun.imageio.plugins.png.PNGImageWriterSpi;
048 import com.sun.imageio.plugins.bmp.BMPImageReaderSpi;
049 import com.sun.imageio.plugins.bmp.BMPImageWriterSpi;
050 import com.sun.imageio.plugins.wbmp.WBMPImageReaderSpi;
051 import com.sun.imageio.plugins.wbmp.WBMPImageWriterSpi;
052 import sun.awt.AppContext;
053 import java.util.ServiceLoader;
054 import java.util.ServiceConfigurationError;
055
056 /**
057 * A registry for service provider instances. Service provider
058 * classes may be detected at run time by means of meta-information in
059 * the JAR files containing them. The intent is that it be relatively
060 * inexpensive to load and inspect all available service provider
061 * classes. These classes may them be used to locate and instantiate
062 * more heavyweight classes that will perform actual work, in this
063 * case instances of <code>ImageReader</code>,
064 * <code>ImageWriter</code>, <code>ImageTranscoder</code>,
065 * <code>ImageInputStream</code>, and <code>ImageOutputStream</code>.
066 *
067 * <p> Service providers found on the system classpath (<i>e.g.</i>,
068 * the <code>jre/lib/ext</code> directory in Sun's implementation of
069 * JDK) are automatically loaded as soon as this class is
070 * instantiated.
071 *
072 * <p> When the <code>registerApplicationClasspathSpis</code> method
073 * is called, service provider instances declared in the
074 * meta-information section of JAR files on the application class path
075 * are loaded. To declare a service provider, a <code>services</code>
076 * subdirectory is placed within the <code>META-INF</code> directory
077 * that is present in every JAR file. This directory contains a file
078 * for each service provider interface that has one or more
079 * implementation classes present in the JAR file. For example, if
080 * the JAR file contained a class named
081 * <code>com.mycompany.imageio.MyFormatReaderSpi</code> which
082 * implements the <code>ImageReaderSpi</code> interface, the JAR file
083 * would contain a file named:
084 *
085 * <pre>
086 * META-INF/services/javax.imageio.spi.ImageReaderSpi
087 * </pre>
088 *
089 * containing the line:
090 *
091 * <pre>
092 * com.mycompany.imageio.MyFormatReaderSpi
093 * </pre>
094 *
095 * <p> The service provider classes are intended to be lightweight
096 * and quick to load. Implementations of these interfaces
097 * should avoid complex dependencies on other classes and on
098 * native code.
099 *
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 * @version 0.5
112 */
113 public final class IIORegistry extends ServiceRegistry {
114
115 /**
116 * A <code>Vector</code> containing the valid IIO registry
117 * categories (superinterfaces) to be used in the constructor.
118 */
119 private static final Vector initialCategories = new Vector(5);
120
121 static {
122 initialCategories.add(ImageReaderSpi.class);
123 initialCategories.add(ImageWriterSpi.class);
124 initialCategories.add(ImageTranscoderSpi.class);
125 initialCategories.add(ImageInputStreamSpi.class);
126 initialCategories.add(ImageOutputStreamSpi.class);
127 }
128
129 /**
130 * Set up the valid service provider categories and automatically
131 * register all available service providers.
132 *
133 * <p> The constructor is private in order to prevent creation of
134 * additional instances.
135 */
136 private IIORegistry() {
137 super (initialCategories.iterator());
138 registerStandardSpis();
139 registerApplicationClasspathSpis();
140 }
141
142 /**
143 * Returns the default <code>IIORegistry</code> instance used by
144 * the Image I/O API. This instance should be used for all
145 * registry functions.
146 *
147 * <p> Each <code>ThreadGroup</code> will receive its own
148 * instance; this allows different <code>Applet</code>s in the
149 * same browser (for example) to each have their own registry.
150 *
151 * @return the default registry for the current
152 * <code>ThreadGroup</code>.
153 */
154 public static IIORegistry getDefaultInstance() {
155 AppContext context = AppContext.getAppContext();
156 IIORegistry registry = (IIORegistry) context
157 .get(IIORegistry.class);
158 if (registry == null) {
159 // Create an instance for this AppContext
160 registry = new IIORegistry();
161 context.put(IIORegistry.class, registry);
162 }
163 return registry;
164 }
165
166 private void registerStandardSpis() {
167 // Hardwire standard SPIs
168 registerServiceProvider(new GIFImageReaderSpi());
169 registerServiceProvider(new GIFImageWriterSpi());
170 registerServiceProvider(new BMPImageReaderSpi());
171 registerServiceProvider(new BMPImageWriterSpi());
172 registerServiceProvider(new WBMPImageReaderSpi());
173 registerServiceProvider(new WBMPImageWriterSpi());
174 registerServiceProvider(new PNGImageReaderSpi());
175 registerServiceProvider(new PNGImageWriterSpi());
176 registerServiceProvider(new JPEGImageReaderSpi());
177 registerServiceProvider(new JPEGImageWriterSpi());
178 registerServiceProvider(new FileImageInputStreamSpi());
179 registerServiceProvider(new FileImageOutputStreamSpi());
180 registerServiceProvider(new InputStreamImageInputStreamSpi());
181 registerServiceProvider(new OutputStreamImageOutputStreamSpi());
182 registerServiceProvider(new RAFImageInputStreamSpi());
183 registerServiceProvider(new RAFImageOutputStreamSpi());
184
185 registerInstalledProviders();
186 }
187
188 /**
189 * Registers all available service providers found on the
190 * application class path, using the default
191 * <code>ClassLoader</code>. This method is typically invoked by
192 * the <code>ImageIO.scanForPlugins</code> method.
193 *
194 * @see javax.imageio.ImageIO#scanForPlugins
195 * @see ClassLoader#getResources
196 */
197 public void registerApplicationClasspathSpis() {
198 // FIX: load only from application classpath
199
200 ClassLoader loader = Thread.currentThread()
201 .getContextClassLoader();
202
203 Iterator categories = getCategories();
204 while (categories.hasNext()) {
205 Class<IIOServiceProvider> c = (Class) categories.next();
206 Iterator<IIOServiceProvider> riter = ServiceLoader.load(c,
207 loader).iterator();
208 while (riter.hasNext()) {
209 try {
210 // Note that the next() call is required to be inside
211 // the try/catch block; see 6342404.
212 IIOServiceProvider r = riter.next();
213 registerServiceProvider(r);
214 } catch (ServiceConfigurationError err) {
215 if (System.getSecurityManager() != null) {
216 // In the applet case, we will catch the error so
217 // registration of other plugins can proceed
218 err.printStackTrace();
219 } else {
220 // In the application case, we will throw the
221 // error to indicate app/system misconfiguration
222 throw err;
223 }
224 }
225 }
226 }
227 }
228
229 private void registerInstalledProviders() {
230 /*
231 We need load installed providers from lib/ext
232 directory in the privileged mode in order to
233 be able read corresponding jar files even if
234 file read capability is restricted (like the
235 applet context case).
236 */
237 PrivilegedAction doRegistration = new PrivilegedAction() {
238 public Object run() {
239 Iterator categories = getCategories();
240 while (categories.hasNext()) {
241 Class<IIOServiceProvider> c = (Class) categories
242 .next();
243 for (IIOServiceProvider p : ServiceLoader
244 .loadInstalled(c)) {
245 registerServiceProvider(p);
246 }
247 }
248 return this;
249 }
250 };
251
252 AccessController.doPrivileged(doRegistration);
253 }
254 }
|