feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,161 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* A node in a directed graph. In addition to an arbitrary
* <code>Object</code> containing user data associated with the node,
* each node maintains a <code>Set</code>s of nodes which are pointed
* to by the current node (available from <code>getOutNodes</code>).
* The in-degree of the node (that is, number of nodes that point to
* the current node) may be queried.
*
*/
class DigraphNode implements Cloneable, Serializable {
/** The data associated with this node. */
protected Object data;
/**
* A <code>Set</code> of neighboring nodes pointed to by this
* node.
*/
protected Set outNodes = new HashSet();
/** The in-degree of the node. */
protected int inDegree = 0;
/**
* A <code>Set</code> of neighboring nodes that point to this
* node.
*/
private Set inNodes = new HashSet();
public DigraphNode(Object data) {
this.data = data;
}
/** Returns the <code>Object</code> referenced by this node. */
public Object getData() {
return data;
}
/**
* Returns an <code>Iterator</code> containing the nodes pointed
* to by this node.
*/
public Iterator getOutNodes() {
return outNodes.iterator();
}
/**
* Adds a directed edge to the graph. The outNodes list of this
* node is updated and the in-degree of the other node is incremented.
*
* @param node a <code>DigraphNode</code>.
*
* @return <code>true</code> if the node was not previously the
* target of an edge.
*/
public boolean addEdge(DigraphNode node) {
if (outNodes.contains(node)) {
return false;
}
outNodes.add(node);
node.inNodes.add(this);
node.incrementInDegree();
return true;
}
/**
* Returns <code>true</code> if an edge exists between this node
* and the given node.
*
* @param node a <code>DigraphNode</code>.
*
* @return <code>true</code> if the node is the target of an edge.
*/
public boolean hasEdge(DigraphNode node) {
return outNodes.contains(node);
}
/**
* Removes a directed edge from the graph. The outNodes list of this
* node is updated and the in-degree of the other node is decremented.
*
* @return <code>true</code> if the node was previously the target
* of an edge.
*/
public boolean removeEdge(DigraphNode node) {
if (!outNodes.contains(node)) {
return false;
}
outNodes.remove(node);
node.inNodes.remove(this);
node.decrementInDegree();
return true;
}
/**
* Removes this node from the graph, updating neighboring nodes
* appropriately.
*/
public void dispose() {
Object[] inNodesArray = inNodes.toArray();
for(int i=0; i<inNodesArray.length; i++) {
DigraphNode node = (DigraphNode) inNodesArray[i];
node.removeEdge(this);
}
Object[] outNodesArray = outNodes.toArray();
for(int i=0; i<outNodesArray.length; i++) {
DigraphNode node = (DigraphNode) outNodesArray[i];
removeEdge(node);
}
}
/** Returns the in-degree of this node. */
public int getInDegree() {
return inDegree;
}
/** Increments the in-degree of this node. */
private void incrementInDegree() {
++inDegree;
}
/** Decrements the in-degree of this node. */
private void decrementInDegree() {
--inDegree;
}
}

View File

@@ -0,0 +1,253 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.security.PrivilegedAction;
import java.security.AccessController;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Vector;
import com.sun.imageio.spi.FileImageInputStreamSpi;
import com.sun.imageio.spi.FileImageOutputStreamSpi;
import com.sun.imageio.spi.InputStreamImageInputStreamSpi;
import com.sun.imageio.spi.OutputStreamImageOutputStreamSpi;
import com.sun.imageio.spi.RAFImageInputStreamSpi;
import com.sun.imageio.spi.RAFImageOutputStreamSpi;
import com.sun.imageio.plugins.gif.GIFImageReaderSpi;
import com.sun.imageio.plugins.gif.GIFImageWriterSpi;
import com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi;
import com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi;
import com.sun.imageio.plugins.png.PNGImageReaderSpi;
import com.sun.imageio.plugins.png.PNGImageWriterSpi;
import com.sun.imageio.plugins.bmp.BMPImageReaderSpi;
import com.sun.imageio.plugins.bmp.BMPImageWriterSpi;
import com.sun.imageio.plugins.wbmp.WBMPImageReaderSpi;
import com.sun.imageio.plugins.wbmp.WBMPImageWriterSpi;
import sun.awt.AppContext;
import java.util.ServiceLoader;
import java.util.ServiceConfigurationError;
/**
* A registry for service provider instances. Service provider
* classes may be detected at run time by means of meta-information in
* the JAR files containing them. The intent is that it be relatively
* inexpensive to load and inspect all available service provider
* classes. These classes may them be used to locate and instantiate
* more heavyweight classes that will perform actual work, in this
* case instances of <code>ImageReader</code>,
* <code>ImageWriter</code>, <code>ImageTranscoder</code>,
* <code>ImageInputStream</code>, and <code>ImageOutputStream</code>.
*
* <p> Service providers found on the system classpath (typically
* the <code>lib/ext</code> directory in the Java
* installation directory) are automatically loaded as soon as this class is
* instantiated.
*
* <p> When the <code>registerApplicationClasspathSpis</code> method
* is called, service provider instances declared in the
* meta-information section of JAR files on the application class path
* are loaded. To declare a service provider, a <code>services</code>
* subdirectory is placed within the <code>META-INF</code> directory
* that is present in every JAR file. This directory contains a file
* for each service provider interface that has one or more
* implementation classes present in the JAR file. For example, if
* the JAR file contained a class named
* <code>com.mycompany.imageio.MyFormatReaderSpi</code> which
* implements the <code>ImageReaderSpi</code> interface, the JAR file
* would contain a file named:
*
* <pre>
* META-INF/services/javax.imageio.spi.ImageReaderSpi
* </pre>
*
* containing the line:
*
* <pre>
* com.mycompany.imageio.MyFormatReaderSpi
* </pre>
*
* <p> The service provider classes are intended to be lightweight
* and quick to load. Implementations of these interfaces
* should avoid complex dependencies on other classes and on
* native code.
*
* <p> It is also possible to manually add service providers not found
* automatically, as well as to remove those that are using the
* interfaces of the <code>ServiceRegistry</code> class. Thus
* the application may customize the contents of the registry as it
* sees fit.
*
* <p> For more details on declaring service providers, and the JAR
* format in general, see the <a
* href="{@docRoot}/../technotes/guides/jar/jar.html">
* JAR File Specification</a>.
*
*/
public final class IIORegistry extends ServiceRegistry {
/**
* A <code>Vector</code> containing the valid IIO registry
* categories (superinterfaces) to be used in the constructor.
*/
private static final Vector initialCategories = new Vector(5);
static {
initialCategories.add(ImageReaderSpi.class);
initialCategories.add(ImageWriterSpi.class);
initialCategories.add(ImageTranscoderSpi.class);
initialCategories.add(ImageInputStreamSpi.class);
initialCategories.add(ImageOutputStreamSpi.class);
}
/**
* Set up the valid service provider categories and automatically
* register all available service providers.
*
* <p> The constructor is private in order to prevent creation of
* additional instances.
*/
private IIORegistry() {
super(initialCategories.iterator());
registerStandardSpis();
registerApplicationClasspathSpis();
}
/**
* Returns the default <code>IIORegistry</code> instance used by
* the Image I/O API. This instance should be used for all
* registry functions.
*
* <p> Each <code>ThreadGroup</code> will receive its own
* instance; this allows different <code>Applet</code>s in the
* same browser (for example) to each have their own registry.
*
* @return the default registry for the current
* <code>ThreadGroup</code>.
*/
public static IIORegistry getDefaultInstance() {
AppContext context = AppContext.getAppContext();
IIORegistry registry =
(IIORegistry)context.get(IIORegistry.class);
if (registry == null) {
// Create an instance for this AppContext
registry = new IIORegistry();
context.put(IIORegistry.class, registry);
}
return registry;
}
private void registerStandardSpis() {
// Hardwire standard SPIs
registerServiceProvider(new GIFImageReaderSpi());
registerServiceProvider(new GIFImageWriterSpi());
registerServiceProvider(new BMPImageReaderSpi());
registerServiceProvider(new BMPImageWriterSpi());
registerServiceProvider(new WBMPImageReaderSpi());
registerServiceProvider(new WBMPImageWriterSpi());
registerServiceProvider(new PNGImageReaderSpi());
registerServiceProvider(new PNGImageWriterSpi());
registerServiceProvider(new JPEGImageReaderSpi());
registerServiceProvider(new JPEGImageWriterSpi());
registerServiceProvider(new FileImageInputStreamSpi());
registerServiceProvider(new FileImageOutputStreamSpi());
registerServiceProvider(new InputStreamImageInputStreamSpi());
registerServiceProvider(new OutputStreamImageOutputStreamSpi());
registerServiceProvider(new RAFImageInputStreamSpi());
registerServiceProvider(new RAFImageOutputStreamSpi());
registerInstalledProviders();
}
/**
* Registers all available service providers found on the
* application class path, using the default
* <code>ClassLoader</code>. This method is typically invoked by
* the <code>ImageIO.scanForPlugins</code> method.
*
* @see javax.imageio.ImageIO#scanForPlugins
* @see ClassLoader#getResources
*/
public void registerApplicationClasspathSpis() {
// FIX: load only from application classpath
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Iterator categories = getCategories();
while (categories.hasNext()) {
Class<IIOServiceProvider> c = (Class)categories.next();
Iterator<IIOServiceProvider> riter =
ServiceLoader.load(c, loader).iterator();
while (riter.hasNext()) {
try {
// Note that the next() call is required to be inside
// the try/catch block; see 6342404.
IIOServiceProvider r = riter.next();
registerServiceProvider(r);
} catch (ServiceConfigurationError err) {
if (System.getSecurityManager() != null) {
// In the applet case, we will catch the error so
// registration of other plugins can proceed
err.printStackTrace();
} else {
// In the application case, we will throw the
// error to indicate app/system misconfiguration
throw err;
}
}
}
}
}
private void registerInstalledProviders() {
/*
We need to load installed providers from the
system classpath (typically the <code>lib/ext</code>
directory in in the Java installation directory)
in the privileged mode in order to
be able read corresponding jar files even if
file read capability is restricted (like the
applet context case).
*/
PrivilegedAction doRegistration =
new PrivilegedAction() {
public Object run() {
Iterator categories = getCategories();
while (categories.hasNext()) {
Class<IIOServiceProvider> c = (Class)categories.next();
for (IIOServiceProvider p : ServiceLoader.loadInstalled(c)) {
registerServiceProvider(p);
}
}
return this;
}
};
AccessController.doPrivileged(doRegistration);
}
}

View File

@@ -0,0 +1,172 @@
/*
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.util.Locale;
import javax.imageio.spi.RegisterableService;
import javax.imageio.spi.ServiceRegistry;
/**
* A superinterface for functionality common to all Image I/O service
* provider interfaces (SPIs). For more information on service
* provider classes, see the class comment for the
* <code>IIORegistry</code> class.
*
* @see IIORegistry
* @see javax.imageio.spi.ImageReaderSpi
* @see javax.imageio.spi.ImageWriterSpi
* @see javax.imageio.spi.ImageTranscoderSpi
* @see javax.imageio.spi.ImageInputStreamSpi
*
*/
public abstract class IIOServiceProvider implements RegisterableService {
/**
* A <code>String</code> to be returned from
* <code>getVendorName</code>, initially <code>null</code>.
* Constructors should set this to a non-<code>null</code> value.
*/
protected String vendorName;
/**
* A <code>String</code> to be returned from
* <code>getVersion</code>, initially null. Constructors should
* set this to a non-<code>null</code> value.
*/
protected String version;
/**
* Constructs an <code>IIOServiceProvider</code> with a given
* vendor name and version identifier.
*
* @param vendorName the vendor name.
* @param version a version identifier.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
*/
public IIOServiceProvider(String vendorName,
String version) {
if (vendorName == null) {
throw new IllegalArgumentException("vendorName == null!");
}
if (version == null) {
throw new IllegalArgumentException("version == null!");
}
this.vendorName = vendorName;
this.version = version;
}
/**
* Constructs a blank <code>IIOServiceProvider</code>. It is up
* to the subclass to initialize instance variables and/or
* override method implementations in order to ensure that the
* <code>getVendorName</code> and <code>getVersion</code> methods
* will return non-<code>null</code> values.
*/
public IIOServiceProvider() {
}
/**
* A callback that will be called exactly once after the Spi class
* has been instantiated and registered in a
* <code>ServiceRegistry</code>. This may be used to verify that
* the environment is suitable for this service, for example that
* native libraries can be loaded. If the service cannot function
* in the environment where it finds itself, it should deregister
* itself from the registry.
*
* <p> Only the registry should call this method.
*
* <p> The default implementation does nothing.
*
* @see ServiceRegistry#registerServiceProvider(Object provider)
*/
public void onRegistration(ServiceRegistry registry,
Class<?> category) {}
/**
* A callback that will be whenever the Spi class has been
* deregistered from a <code>ServiceRegistry</code>.
*
* <p> Only the registry should call this method.
*
* <p> The default implementation does nothing.
*
* @see ServiceRegistry#deregisterServiceProvider(Object provider)
*/
public void onDeregistration(ServiceRegistry registry,
Class<?> category) {}
/**
* Returns the name of the vendor responsible for creating this
* service provider and its associated implementation. Because
* the vendor name may be used to select a service provider,
* it is not localized.
*
* <p> The default implementation returns the value of the
* <code>vendorName</code> instance variable.
*
* @return a non-<code>null</code> <code>String</code> containing
* the name of the vendor.
*/
public String getVendorName() {
return vendorName;
}
/**
* Returns a string describing the version
* number of this service provider and its associated
* implementation. Because the version may be used by transcoders
* to identify the service providers they understand, this method
* is not localized.
*
* <p> The default implementation returns the value of the
* <code>version</code> instance variable.
*
* @return a non-<code>null</code> <code>String</code> containing
* the version of this service provider.
*/
public String getVersion() {
return version;
}
/**
* Returns a brief, human-readable description of this service
* provider and its associated implementation. The resulting
* string should be localized for the supplied
* <code>Locale</code>, if possible.
*
* @param locale a <code>Locale</code> for which the return value
* should be localized.
*
* @return a <code>String</code> containing a description of this
* service provider.
*/
public abstract String getDescription(Locale locale);
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.File;
import java.io.IOException;
import javax.imageio.stream.ImageInputStream;
/**
* The service provider interface (SPI) for
* <code>ImageInputStream</code>s. For more information on service
* provider interfaces, see the class comment for the
* <code>IIORegistry</code> class.
*
* <p> This interface allows arbitrary objects to be "wrapped" by
* instances of <code>ImageInputStream</code>. For example,
* a particular <code>ImageInputStreamSpi</code> might allow
* a generic <code>InputStream</code> to be used as an input source;
* another might take input from a <code>URL</code>.
*
* <p> By treating the creation of <code>ImageInputStream</code>s as a
* pluggable service, it becomes possible to handle future input
* sources without changing the API. Also, high-performance
* implementations of <code>ImageInputStream</code> (for example,
* native implementations for a particular platform) can be installed
* and used transparently by applications.
*
* @see IIORegistry
* @see javax.imageio.stream.ImageInputStream
*
*/
public abstract class ImageInputStreamSpi extends IIOServiceProvider {
/**
* A <code>Class</code> object indicating the legal object type
* for use by the <code>createInputStreamInstance</code> method.
*/
protected Class<?> inputClass;
/**
* Constructs a blank <code>ImageInputStreamSpi</code>. It is up
* to the subclass to initialize instance variables and/or
* override method implementations in order to provide working
* versions of all methods.
*/
protected ImageInputStreamSpi() {
}
/**
* Constructs an <code>ImageInputStreamSpi</code> with a given set
* of values.
*
* @param vendorName the vendor name.
* @param version a version identifier.
* @param inputClass a <code>Class</code> object indicating the
* legal object type for use by the
* <code>createInputStreamInstance</code> method.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
*/
public ImageInputStreamSpi(String vendorName,
String version,
Class<?> inputClass) {
super(vendorName, version);
this.inputClass = inputClass;
}
/**
* Returns a <code>Class</code> object representing the class or
* interface type that must be implemented by an input source in
* order to be "wrapped" in an <code>ImageInputStream</code> via
* the <code>createInputStreamInstance</code> method.
*
* <p> Typical return values might include
* <code>InputStream.class</code> or <code>URL.class</code>, but
* any class may be used.
*
* @return a <code>Class</code> variable.
*
* @see #createInputStreamInstance(Object, boolean, File)
*/
public Class<?> getInputClass() {
return inputClass;
}
/**
* Returns <code>true</code> if the <code>ImageInputStream</code>
* implementation associated with this service provider can
* optionally make use of a cache file for improved performance
* and/or memory footrprint. If <code>false</code>, the value of
* the <code>useCache</code> argument to
* <code>createInputStreamInstance</code> will be ignored.
*
* <p> The default implementation returns <code>false</code>.
*
* @return <code>true</code> if a cache file can be used by the
* input streams created by this service provider.
*/
public boolean canUseCacheFile() {
return false;
}
/**
* Returns <code>true</code> if the <code>ImageInputStream</code>
* implementation associated with this service provider requires
* the use of a cache <code>File</code>. If <code>true</code>,
* the value of the <code>useCache</code> argument to
* <code>createInputStreamInstance</code> will be ignored.
*
* <p> The default implementation returns <code>false</code>.
*
* @return <code>true</code> if a cache file is needed by the
* input streams created by this service provider.
*/
public boolean needsCacheFile() {
return false;
}
/**
* Returns an instance of the <code>ImageInputStream</code>
* implementation associated with this service provider. If the
* use of a cache file is optional, the <code>useCache</code>
* parameter will be consulted. Where a cache is required, or
* not applicable, the value of <code>useCache</code> will be ignored.
*
* @param input an object of the class type returned by
* <code>getInputClass</code>.
* @param useCache a <code>boolean</code> indicating whether a
* cache file should be used, in cases where it is optional.
* @param cacheDir a <code>File</code> indicating where the
* cache file should be created, or <code>null</code> to use the
* system directory.
*
* @return an <code>ImageInputStream</code> instance.
*
* @exception IllegalArgumentException if <code>input</code> is
* not an instance of the correct class or is <code>null</code>.
* @exception IllegalArgumentException if a cache file is needed
* but <code>cacheDir</code> is non-<code>null</code> and is not a
* directory.
* @exception IOException if a cache file is needed but cannot be
* created.
*
* @see #getInputClass
* @see #canUseCacheFile
* @see #needsCacheFile
*/
public abstract ImageInputStream
createInputStreamInstance(Object input,
boolean useCache,
File cacheDir) throws IOException;
/**
* Returns an instance of the <code>ImageInputStream</code>
* implementation associated with this service provider. A cache
* file will be created in the system-dependent default
* temporary-file directory, if needed.
*
* @param input an object of the class type returned by
* <code>getInputClass</code>.
*
* @return an <code>ImageInputStream</code> instance.
*
* @exception IllegalArgumentException if <code>input</code> is
* not an instance of the correct class or is <code>null</code>.
* @exception IOException if a cache file is needed but cannot be
* created.
*
* @see #getInputClass()
*/
public ImageInputStream createInputStreamInstance(Object input)
throws IOException {
return createInputStreamInstance(input, true, null);
}
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.File;
import java.io.IOException;
import javax.imageio.stream.ImageOutputStream;
/**
* The service provider interface (SPI) for
* <code>ImageOutputStream</code>s. For more information on service
* provider interfaces, see the class comment for the
* <code>IIORegistry</code> class.
*
* <p> This interface allows arbitrary objects to be "wrapped" by
* instances of <code>ImageOutputStream</code>. For example, a
* particular <code>ImageOutputStreamSpi</code> might allow a generic
* <code>OutputStream</code> to be used as a destination; another
* might output to a <code>File</code> or to a device such as a serial
* port.
*
* <p> By treating the creation of <code>ImageOutputStream</code>s as
* a pluggable service, it becomes possible to handle future output
* destinations without changing the API. Also, high-performance
* implementations of <code>ImageOutputStream</code> (for example,
* native implementations for a particular platform) can be installed
* and used transparently by applications.
*
* @see IIORegistry
* @see javax.imageio.stream.ImageOutputStream
*
*/
public abstract class ImageOutputStreamSpi extends IIOServiceProvider {
/**
* A <code>Class</code> object indicating the legal object type
* for use by the <code>createInputStreamInstance</code> method.
*/
protected Class<?> outputClass;
/**
* Constructs a blank <code>ImageOutputStreamSpi</code>. It is up
* to the subclass to initialize instance variables and/or
* override method implementations in order to provide working
* versions of all methods.
*/
protected ImageOutputStreamSpi() {
}
/**
* Constructs an <code>ImageOutputStreamSpi</code> with a given
* set of values.
*
* @param vendorName the vendor name.
* @param version a version identifier.
* @param outputClass a <code>Class</code> object indicating the
* legal object type for use by the
* <code>createOutputStreamInstance</code> method.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
*/
public ImageOutputStreamSpi(String vendorName,
String version,
Class<?> outputClass) {
super(vendorName, version);
this.outputClass = outputClass;
}
/**
* Returns a <code>Class</code> object representing the class or
* interface type that must be implemented by an output
* destination in order to be "wrapped" in an
* <code>ImageOutputStream</code> via the
* <code>createOutputStreamInstance</code> method.
*
* <p> Typical return values might include
* <code>OutputStream.class</code> or <code>File.class</code>, but
* any class may be used.
*
* @return a <code>Class</code> variable.
*
* @see #createOutputStreamInstance(Object, boolean, File)
*/
public Class<?> getOutputClass() {
return outputClass;
}
/**
* Returns <code>true</code> if the <code>ImageOutputStream</code>
* implementation associated with this service provider can
* optionally make use of a cache <code>File</code> for improved
* performance and/or memory footrprint. If <code>false</code>,
* the value of the <code>cacheFile</code> argument to
* <code>createOutputStreamInstance</code> will be ignored.
*
* <p> The default implementation returns <code>false</code>.
*
* @return <code>true</code> if a cache file can be used by the
* output streams created by this service provider.
*/
public boolean canUseCacheFile() {
return false;
}
/**
* Returns <code>true</code> if the <code>ImageOutputStream</code>
* implementation associated with this service provider requires
* the use of a cache <code>File</code>.
*
* <p> The default implementation returns <code>false</code>.
*
* @return <code>true</code> if a cache file is needed by the
* output streams created by this service provider.
*/
public boolean needsCacheFile() {
return false;
}
/**
* Returns an instance of the <code>ImageOutputStream</code>
* implementation associated with this service provider. If the
* use of a cache file is optional, the <code>useCache</code>
* parameter will be consulted. Where a cache is required, or
* not applicable, the value of <code>useCache</code> will be ignored.
*
* @param output an object of the class type returned by
* <code>getOutputClass</code>.
* @param useCache a <code>boolean</code> indicating whether a
* cache file should be used, in cases where it is optional.
* @param cacheDir a <code>File</code> indicating where the
* cache file should be created, or <code>null</code> to use the
* system directory.
*
* @return an <code>ImageOutputStream</code> instance.
*
* @exception IllegalArgumentException if <code>output</code> is
* not an instance of the correct class or is <code>null</code>.
* @exception IllegalArgumentException if a cache file is needed,
* but <code>cacheDir</code> is non-<code>null</code> and is not a
* directory.
* @exception IOException if a cache file is needed but cannot be
* created.
*
* @see #getOutputClass
*/
public abstract
ImageOutputStream createOutputStreamInstance(Object output,
boolean useCache,
File cacheDir)
throws IOException;
/**
* Returns an instance of the <code>ImageOutputStream</code>
* implementation associated with this service provider. A cache
* file will be created in the system-dependent default
* temporary-file directory, if needed.
*
* @param output an object of the class type returned by
* <code>getOutputClass</code>.
*
* @return an <code>ImageOutputStream</code> instance.
*
* @exception IllegalArgumentException if <code>output</code> is
* not an instance of the correct class or is <code>null</code>.
* @exception IOException if a cache file is needed but cannot be
* created.
*
* @see #getOutputClass()
*/
public ImageOutputStream createOutputStreamInstance(Object output)
throws IOException {
return createOutputStreamInstance(output, true, null);
}
}

View File

@@ -0,0 +1,413 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.IOException;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
/**
* The service provider interface (SPI) for <code>ImageReader</code>s.
* For more information on service provider classes, see the class comment
* for the <code>IIORegistry</code> class.
*
* <p> Each <code>ImageReaderSpi</code> provides several types of information
* about the <code>ImageReader</code> class with which it is associated.
*
* <p> The name of the vendor who defined the SPI class and a
* brief description of the class are available via the
* <code>getVendorName</code>, <code>getDescription</code>,
* and <code>getVersion</code> methods.
* These methods may be internationalized to provide locale-specific
* output. These methods are intended mainly to provide short,
* human-readable information that might be used to organize a pop-up
* menu or other list.
*
* <p> Lists of format names, file suffixes, and MIME types associated
* with the service may be obtained by means of the
* <code>getFormatNames</code>, <code>getFileSuffixes</code>, and
* <code>getMIMETypes</code> methods. These methods may be used to
* identify candidate <code>ImageReader</code>s for decoding a
* particular file or stream based on manual format selection, file
* naming, or MIME associations (for example, when accessing a file
* over HTTP or as an email attachment).
*
* <p> A more reliable way to determine which <code>ImageReader</code>s
* are likely to be able to parse a particular data stream is provided
* by the <code>canDecodeInput</code> method. This methods allows the
* service provider to inspect the actual stream contents.
*
* <p> Finally, an instance of the <code>ImageReader</code> class
* associated with this service provider may be obtained by calling
* the <code>createReaderInstance</code> method. Any heavyweight
* initialization, such as the loading of native libraries or creation
* of large tables, should be deferred at least until the first
* invocation of this method.
*
* @see IIORegistry
* @see javax.imageio.ImageReader
*
*/
public abstract class ImageReaderSpi extends ImageReaderWriterSpi {
/**
* A single-element array, initially containing
* <code>ImageInputStream.class</code>, to be returned from
* <code>getInputTypes</code>.
* @deprecated Instead of using this field, directly create
* the equivalent array <code>{ ImageInputStream.class }</code>.
*/
@Deprecated
public static final Class[] STANDARD_INPUT_TYPE =
{ ImageInputStream.class };
/**
* An array of <code>Class</code> objects to be returned from
* <code>getInputTypes</code>, initially <code>null</code>.
*/
protected Class[] inputTypes = null;
/**
* An array of strings to be returned from
* <code>getImageWriterSpiNames</code>, initially
* <code>null</code>.
*/
protected String[] writerSpiNames = null;
/**
* The <code>Class</code> of the reader, initially
* <code>null</code>.
*/
private Class readerClass = null;
/**
* Constructs a blank <code>ImageReaderSpi</code>. It is up to
* the subclass to initialize instance variables and/or override
* method implementations in order to provide working versions of
* all methods.
*/
protected ImageReaderSpi() {
}
/**
* Constructs an <code>ImageReaderSpi</code> with a given
* set of values.
*
* @param vendorName the vendor name, as a non-<code>null</code>
* <code>String</code>.
* @param version a version identifier, as a non-<code>null</code>
* <code>String</code>.
* @param names a non-<code>null</code> array of
* <code>String</code>s indicating the format names. At least one
* entry must be present.
* @param suffixes an array of <code>String</code>s indicating the
* common file suffixes. If no suffixes are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param MIMETypes an array of <code>String</code>s indicating
* the format's MIME types. If no MIME types are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param readerClassName the fully-qualified name of the
* associated <code>ImageReader</code> class, as a
* non-<code>null</code> <code>String</code>.
* @param inputTypes a non-<code>null</code> array of
* <code>Class</code> objects of length at least 1 indicating the
* legal input types.
* @param writerSpiNames an array <code>String</code>s naming the
* classes of all associated <code>ImageWriter</code>s, or
* <code>null</code>. An array of length 0 is normalized to
* <code>null</code>.
* @param supportsStandardStreamMetadataFormat a
* <code>boolean</code> that indicates whether a stream metadata
* object can use trees described by the standard metadata format.
* @param nativeStreamMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeStreamMetadataFormatName</code>.
* @param nativeStreamMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeStreamMetadataFormat</code>.
* @param extraStreamMetadataFormatNames an array of
* <code>String</code>s, or <code>null</code>, to be returned from
* <code>getExtraStreamMetadataFormatNames</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param extraStreamMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getStreamMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param supportsStandardImageMetadataFormat a
* <code>boolean</code> that indicates whether an image metadata
* object can use trees described by the standard metadata format.
* @param nativeImageMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeImageMetadataFormatName</code>.
* @param nativeImageMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeImageMetadataFormat</code>.
* @param extraImageMetadataFormatNames an array of
* <code>String</code>s to be returned from
* <code>getExtraImageMetadataFormatNames</code>. An array of length 0
* is normalized to <code>null</code>.
* @param extraImageMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getImageMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>names</code>
* is <code>null</code> or has length 0.
* @exception IllegalArgumentException if <code>readerClassName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>inputTypes</code>
* is <code>null</code> or has length 0.
*/
public ImageReaderSpi(String vendorName,
String version,
String[] names,
String[] suffixes,
String[] MIMETypes,
String readerClassName,
Class[] inputTypes,
String[] writerSpiNames,
boolean supportsStandardStreamMetadataFormat,
String nativeStreamMetadataFormatName,
String nativeStreamMetadataFormatClassName,
String[] extraStreamMetadataFormatNames,
String[] extraStreamMetadataFormatClassNames,
boolean supportsStandardImageMetadataFormat,
String nativeImageMetadataFormatName,
String nativeImageMetadataFormatClassName,
String[] extraImageMetadataFormatNames,
String[] extraImageMetadataFormatClassNames) {
super(vendorName, version,
names, suffixes, MIMETypes, readerClassName,
supportsStandardStreamMetadataFormat,
nativeStreamMetadataFormatName,
nativeStreamMetadataFormatClassName,
extraStreamMetadataFormatNames,
extraStreamMetadataFormatClassNames,
supportsStandardImageMetadataFormat,
nativeImageMetadataFormatName,
nativeImageMetadataFormatClassName,
extraImageMetadataFormatNames,
extraImageMetadataFormatClassNames);
if (inputTypes == null) {
throw new IllegalArgumentException
("inputTypes == null!");
}
if (inputTypes.length == 0) {
throw new IllegalArgumentException
("inputTypes.length == 0!");
}
this.inputTypes = (inputTypes == STANDARD_INPUT_TYPE) ?
new Class<?>[] { ImageInputStream.class } :
inputTypes.clone();
// If length == 0, leave it null
if (writerSpiNames != null && writerSpiNames.length > 0) {
this.writerSpiNames = (String[])writerSpiNames.clone();
}
}
/**
* Returns an array of <code>Class</code> objects indicating what
* types of objects may be used as arguments to the reader's
* <code>setInput</code> method.
*
* <p> For most readers, which only accept input from an
* <code>ImageInputStream</code>, a single-element array
* containing <code>ImageInputStream.class</code> should be
* returned.
*
* @return a non-<code>null</code> array of
* <code>Class</code>objects of length at least 1.
*/
public Class[] getInputTypes() {
return (Class[])inputTypes.clone();
}
/**
* Returns <code>true</code> if the supplied source object appears
* to be of the format supported by this reader. Returning
* <code>true</code> from this method does not guarantee that
* reading will succeed, only that there appears to be a
* reasonable chance of success based on a brief inspection of the
* stream contents. If the source is an
* <code>ImageInputStream</code>, implementations will commonly
* check the first several bytes of the stream for a "magic
* number" associated with the format. Once actual reading has
* commenced, the reader may still indicate failure at any time
* prior to the completion of decoding.
*
* <p> It is important that the state of the object not be
* disturbed in order that other <code>ImageReaderSpi</code>s can
* properly determine whether they are able to decode the object.
* In particular, if the source is an
* <code>ImageInputStream</code>, a
* <code>mark</code>/<code>reset</code> pair should be used to
* preserve the stream position.
*
* <p> Formats such as "raw," which can potentially attempt
* to read nearly any stream, should return <code>false</code>
* in order to avoid being invoked in preference to a closer
* match.
*
* <p> If <code>source</code> is not an instance of one of the
* classes returned by <code>getInputTypes</code>, the method
* should simply return <code>false</code>.
*
* @param source the object (typically an
* <code>ImageInputStream</code>) to be decoded.
*
* @return <code>true</code> if it is likely that this stream can
* be decoded.
*
* @exception IllegalArgumentException if <code>source</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs while reading the
* stream.
*/
public abstract boolean canDecodeInput(Object source) throws IOException;
/**
* Returns an instance of the <code>ImageReader</code>
* implementation associated with this service provider.
* The returned object will initially be in an initial state
* as if its <code>reset</code> method had been called.
*
* <p> The default implementation simply returns
* <code>createReaderInstance(null)</code>.
*
* @return an <code>ImageReader</code> instance.
*
* @exception IOException if an error occurs during loading,
* or initialization of the reader class, or during instantiation
* or initialization of the reader object.
*/
public ImageReader createReaderInstance() throws IOException {
return createReaderInstance(null);
}
/**
* Returns an instance of the <code>ImageReader</code>
* implementation associated with this service provider.
* The returned object will initially be in an initial state
* as if its <code>reset</code> method had been called.
*
* <p> An <code>Object</code> may be supplied to the plug-in at
* construction time. The nature of the object is entirely
* plug-in specific.
*
* <p> Typically, a plug-in will implement this method using code
* such as <code>return new MyImageReader(this)</code>.
*
* @param extension a plug-in specific extension object, which may
* be <code>null</code>.
*
* @return an <code>ImageReader</code> instance.
*
* @exception IOException if the attempt to instantiate
* the reader fails.
* @exception IllegalArgumentException if the
* <code>ImageReader</code>'s constructor throws an
* <code>IllegalArgumentException</code> to indicate that the
* extension object is unsuitable.
*/
public abstract ImageReader createReaderInstance(Object extension)
throws IOException;
/**
* Returns <code>true</code> if the <code>ImageReader</code> object
* passed in is an instance of the <code>ImageReader</code>
* associated with this service provider.
*
* <p> The default implementation compares the fully-qualified
* class name of the <code>reader</code> argument with the class
* name passed into the constructor. This method may be overridden
* if more sophisticated checking is required.
*
* @param reader an <code>ImageReader</code> instance.
*
* @return <code>true</code> if <code>reader</code> is recognized.
*
* @exception IllegalArgumentException if <code>reader</code> is
* <code>null</code>.
*/
public boolean isOwnReader(ImageReader reader) {
if (reader == null) {
throw new IllegalArgumentException("reader == null!");
}
String name = reader.getClass().getName();
return name.equals(pluginClassName);
}
/**
* Returns an array of <code>String</code>s containing the fully
* qualified names of all the <code>ImageWriterSpi</code> classes
* that can understand the internal metadata representation used
* by the <code>ImageReader</code> associated with this service
* provider, or <code>null</code> if there are no such
* <code>ImageWriter</code>s specified. If a
* non-<code>null</code> value is returned, it must have non-zero
* length.
*
* <p> The first item in the array must be the name of the service
* provider for the "preferred" writer, as it will be used to
* instantiate the <code>ImageWriter</code> returned by
* <code>ImageIO.getImageWriter(ImageReader)</code>.
*
* <p> This mechanism may be used to obtain
* <code>ImageWriters</code> that will understand the internal
* structure of non-pixel meta-data (see
* <code>IIOTreeInfo</code>) generated by an
* <code>ImageReader</code>. By obtaining this data from the
* <code>ImageReader</code> and passing it on to one of the
* <code>ImageWriters</code> obtained with this method, a client
* program can read an image, modify it in some way, and write it
* back out while preserving all meta-data, without having to
* understand anything about the internal structure of the
* meta-data, or even about the image format.
*
* @return an array of <code>String</code>s of length at least 1
* containing names of <code>ImageWriterSpi</code>, or
* <code>null</code>.
*
* @see javax.imageio.ImageIO#getImageWriter(ImageReader)
*/
public String[] getImageWriterSpiNames() {
return writerSpiNames == null ?
null : (String[])writerSpiNames.clone();
}
}

View File

@@ -0,0 +1,601 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormat;
import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.stream.ImageInputStream;
/**
* A superclass containing instance variables and methods common to
* <code>ImageReaderSpi</code> and <code>ImageWriterSpi</code>.
*
* @see IIORegistry
* @see ImageReaderSpi
* @see ImageWriterSpi
*
*/
public abstract class ImageReaderWriterSpi extends IIOServiceProvider {
/**
* An array of strings to be returned from
* <code>getFormatNames</code>, initially <code>null</code>.
* Constructors should set this to a non-<code>null</code> value.
*/
protected String[] names = null;
/**
* An array of strings to be returned from
* <code>getFileSuffixes</code>, initially <code>null</code>.
*/
protected String[] suffixes = null;
/**
* An array of strings to be returned from
* <code>getMIMETypes</code>, initially <code>null</code>.
*/
protected String[] MIMETypes = null;
/**
* A <code>String</code> containing the name of the associated
* plug-in class, initially <code>null</code>.
*/
protected String pluginClassName = null;
/**
* A boolean indicating whether this plug-in supports the
* standard metadata format for stream metadata, initially
* <code>false</code>.
*/
protected boolean supportsStandardStreamMetadataFormat = false;
/**
* A <code>String</code> containing the name of the native stream
* metadata format supported by this plug-in, initially
* <code>null</code>.
*/
protected String nativeStreamMetadataFormatName = null;
/**
* A <code>String</code> containing the class name of the native
* stream metadata format supported by this plug-in, initially
* <code>null</code>.
*/
protected String nativeStreamMetadataFormatClassName = null;
/**
* An array of <code>String</code>s containing the names of any
* additional stream metadata formats supported by this plug-in,
* initially <code>null</code>.
*/
protected String[] extraStreamMetadataFormatNames = null;
/**
* An array of <code>String</code>s containing the class names of
* any additional stream metadata formats supported by this plug-in,
* initially <code>null</code>.
*/
protected String[] extraStreamMetadataFormatClassNames = null;
/**
* A boolean indicating whether this plug-in supports the
* standard metadata format for image metadata, initially
* <code>false</code>.
*/
protected boolean supportsStandardImageMetadataFormat = false;
/**
* A <code>String</code> containing the name of the
* native stream metadata format supported by this plug-in,
* initially <code>null</code>.
*/
protected String nativeImageMetadataFormatName = null;
/**
* A <code>String</code> containing the class name of the
* native stream metadata format supported by this plug-in,
* initially <code>null</code>.
*/
protected String nativeImageMetadataFormatClassName = null;
/**
* An array of <code>String</code>s containing the names of any
* additional image metadata formats supported by this plug-in,
* initially <code>null</code>.
*/
protected String[] extraImageMetadataFormatNames = null;
/**
* An array of <code>String</code>s containing the class names of
* any additional image metadata formats supported by this
* plug-in, initially <code>null</code>.
*/
protected String[] extraImageMetadataFormatClassNames = null;
/**
* Constructs an <code>ImageReaderWriterSpi</code> with a given
* set of values.
*
* @param vendorName the vendor name, as a non-<code>null</code>
* <code>String</code>.
* @param version a version identifier, as a non-<code>null</code>
* <code>String</code>.
* @param names a non-<code>null</code> array of
* <code>String</code>s indicating the format names. At least one
* entry must be present.
* @param suffixes an array of <code>String</code>s indicating the
* common file suffixes. If no suffixes are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param MIMETypes an array of <code>String</code>s indicating
* the format's MIME types. If no MIME types are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param pluginClassName the fully-qualified name of the
* associated <code>ImageReader</code> or <code>ImageWriter</code>
* class, as a non-<code>null</code> <code>String</code>.
* @param supportsStandardStreamMetadataFormat a
* <code>boolean</code> that indicates whether a stream metadata
* object can use trees described by the standard metadata format.
* @param nativeStreamMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeStreamMetadataFormatName</code>.
* @param nativeStreamMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeStreamMetadataFormat</code>.
* @param extraStreamMetadataFormatNames an array of
* <code>String</code>s, or <code>null</code>, to be returned from
* <code>getExtraStreamMetadataFormatNames</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param extraStreamMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getStreamMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param supportsStandardImageMetadataFormat a
* <code>boolean</code> that indicates whether an image metadata
* object can use trees described by the standard metadata format.
* @param nativeImageMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeImageMetadataFormatName</code>.
* @param nativeImageMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeImageMetadataFormat</code>.
* @param extraImageMetadataFormatNames an array of
* <code>String</code>s to be returned from
* <code>getExtraImageMetadataFormatNames</code>. An array of length 0
* is normalized to <code>null</code>.
* @param extraImageMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getImageMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>names</code>
* is <code>null</code> or has length 0.
* @exception IllegalArgumentException if <code>pluginClassName</code>
* is <code>null</code>.
*/
public ImageReaderWriterSpi(String vendorName,
String version,
String[] names,
String[] suffixes,
String[] MIMETypes,
String pluginClassName,
boolean supportsStandardStreamMetadataFormat,
String nativeStreamMetadataFormatName,
String nativeStreamMetadataFormatClassName,
String[] extraStreamMetadataFormatNames,
String[] extraStreamMetadataFormatClassNames,
boolean supportsStandardImageMetadataFormat,
String nativeImageMetadataFormatName,
String nativeImageMetadataFormatClassName,
String[] extraImageMetadataFormatNames,
String[] extraImageMetadataFormatClassNames) {
super(vendorName, version);
if (names == null) {
throw new IllegalArgumentException("names == null!");
}
if (names.length == 0) {
throw new IllegalArgumentException("names.length == 0!");
}
if (pluginClassName == null) {
throw new IllegalArgumentException("pluginClassName == null!");
}
this.names = (String[])names.clone();
// If length == 0, leave it null
if (suffixes != null && suffixes.length > 0) {
this.suffixes = (String[])suffixes.clone();
}
// If length == 0, leave it null
if (MIMETypes != null && MIMETypes.length > 0) {
this.MIMETypes = (String[])MIMETypes.clone();
}
this.pluginClassName = pluginClassName;
this.supportsStandardStreamMetadataFormat =
supportsStandardStreamMetadataFormat;
this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName;
this.nativeStreamMetadataFormatClassName =
nativeStreamMetadataFormatClassName;
// If length == 0, leave it null
if (extraStreamMetadataFormatNames != null &&
extraStreamMetadataFormatNames.length > 0) {
this.extraStreamMetadataFormatNames =
(String[])extraStreamMetadataFormatNames.clone();
}
// If length == 0, leave it null
if (extraStreamMetadataFormatClassNames != null &&
extraStreamMetadataFormatClassNames.length > 0) {
this.extraStreamMetadataFormatClassNames =
(String[])extraStreamMetadataFormatClassNames.clone();
}
this.supportsStandardImageMetadataFormat =
supportsStandardImageMetadataFormat;
this.nativeImageMetadataFormatName = nativeImageMetadataFormatName;
this.nativeImageMetadataFormatClassName =
nativeImageMetadataFormatClassName;
// If length == 0, leave it null
if (extraImageMetadataFormatNames != null &&
extraImageMetadataFormatNames.length > 0) {
this.extraImageMetadataFormatNames =
(String[])extraImageMetadataFormatNames.clone();
}
// If length == 0, leave it null
if (extraImageMetadataFormatClassNames != null &&
extraImageMetadataFormatClassNames.length > 0) {
this.extraImageMetadataFormatClassNames =
(String[])extraImageMetadataFormatClassNames.clone();
}
}
/**
* Constructs a blank <code>ImageReaderWriterSpi</code>. It is up
* to the subclass to initialize instance variables and/or
* override method implementations in order to provide working
* versions of all methods.
*/
public ImageReaderWriterSpi() {
}
/**
* Returns an array of <code>String</code>s containing
* human-readable names for the formats that are generally usable
* by the <code>ImageReader</code> or <code>ImageWriter</code>
* implementation associated with this service provider. For
* example, a single <code>ImageReader</code> might be able to
* process both PBM and PNM files.
*
* @return a non-<code>null</code> array of <code>String</code>s
* or length at least 1 containing informal format names
* associated with this reader or writer.
*/
public String[] getFormatNames() {
return (String[])names.clone();
}
/**
* Returns an array of <code>String</code>s containing a list of
* file suffixes associated with the formats that are generally
* usable by the <code>ImageReader</code> or
* <code>ImageWriter</code> implementation associated with this
* service provider. For example, a single
* <code>ImageReader</code> might be able to process files with
* '.pbm' and '.pnm' suffixes, or both '.jpg' and '.jpeg'
* suffixes. If there are no known file suffixes,
* <code>null</code> will be returned.
*
* <p> Returning a particular suffix does not guarantee that files
* with that suffix can be processed; it merely indicates that it
* may be worthwhile attempting to decode or encode such files
* using this service provider.
*
* @return an array of <code>String</code>s or length at least 1
* containing common file suffixes associated with this reader or
* writer, or <code>null</code>.
*/
public String[] getFileSuffixes() {
return suffixes == null ? null : (String[])suffixes.clone();
}
/**
* Returns an array of <code>String</code>s containing a list of
* MIME types associated with the formats that are generally
* usable by the <code>ImageReader</code> or
* <code>ImageWriter</code> implementation associated with this
* service provider.
*
* <p> Ideally, only a single MIME type would be required in order
* to describe a particular format. However, for several reasons
* it is necessary to associate a list of types with each service
* provider. First, many common image file formats do not have
* standard MIME types, so a list of commonly used unofficial
* names will be required, such as <code>image/x-pbm</code> and
* <code>image/x-portable-bitmap</code>. Some file formats have
* official MIME types but may sometimes be referred to using
* their previous unofficial designations, such as
* <code>image/x-png</code> instead of the official
* <code>image/png</code>. Finally, a single service provider may
* be capable of parsing multiple distinct types from the MIME
* point of view, for example <code>image/x-xbitmap</code> and
* <code>image/x-xpixmap</code>.
*
* <p> Returning a particular MIME type does not guarantee that
* files claiming to be of that type can be processed; it merely
* indicates that it may be worthwhile attempting to decode or
* encode such files using this service provider.
*
* @return an array of <code>String</code>s or length at least 1
* containing MIME types associated with this reader or writer, or
* <code>null</code>.
*/
public String[] getMIMETypes() {
return MIMETypes == null ? null : (String[])MIMETypes.clone();
}
/**
* Returns the fully-qualified class name of the
* <code>ImageReader</code> or <code>ImageWriter</code> plug-in
* associated with this service provider.
*
* @return the class name, as a non-<code>null</code>
* <code>String</code>.
*/
public String getPluginClassName() {
return pluginClassName;
}
/**
* Returns <code>true</code> if the standard metadata format is
* among the document formats recognized by the
* <code>getAsTree</code> and <code>setFromTree</code> methods on
* the stream metadata objects produced or consumed by this
* plug-in.
*
* @return <code>true</code> if the standard format is supported
* for stream metadata.
*/
public boolean isStandardStreamMetadataFormatSupported() {
return supportsStandardStreamMetadataFormat;
}
/**
* Returns the name of the "native" stream metadata format for
* this plug-in, which typically allows for lossless encoding and
* transmission of the stream metadata stored in the format handled by
* this plug-in. If no such format is supported,
* <code>null</code>will be returned.
*
* <p> The default implementation returns the
* <code>nativeStreamMetadataFormatName</code> instance variable,
* which is typically set by the constructor.
*
* @return the name of the native stream metadata format, or
* <code>null</code>.
*
*/
public String getNativeStreamMetadataFormatName() {
return nativeStreamMetadataFormatName;
}
/**
* Returns an array of <code>String</code>s containing the names
* of additional document formats, other than the native and
* standard formats, recognized by the
* <code>getAsTree</code> and <code>setFromTree</code> methods on
* the stream metadata objects produced or consumed by this
* plug-in.
*
* <p> If the plug-in does not handle metadata, null should be
* returned.
*
* <p> The set of formats may differ according to the particular
* images being read or written; this method should indicate all
* the additional formats supported by the plug-in under any
* circumstances.
*
* <p> The default implementation returns a clone of the
* <code>extraStreamMetadataFormatNames</code> instance variable,
* which is typically set by the constructor.
*
* @return an array of <code>String</code>s, or null.
*
* @see IIOMetadata#getMetadataFormatNames
* @see #getExtraImageMetadataFormatNames
* @see #getNativeStreamMetadataFormatName
*/
public String[] getExtraStreamMetadataFormatNames() {
return extraStreamMetadataFormatNames == null ?
null : (String[])extraStreamMetadataFormatNames.clone();
}
/**
* Returns <code>true</code> if the standard metadata format is
* among the document formats recognized by the
* <code>getAsTree</code> and <code>setFromTree</code> methods on
* the image metadata objects produced or consumed by this
* plug-in.
*
* @return <code>true</code> if the standard format is supported
* for image metadata.
*/
public boolean isStandardImageMetadataFormatSupported() {
return supportsStandardImageMetadataFormat;
}
/**
* Returns the name of the "native" image metadata format for
* this plug-in, which typically allows for lossless encoding and
* transmission of the image metadata stored in the format handled by
* this plug-in. If no such format is supported,
* <code>null</code>will be returned.
*
* <p> The default implementation returns the
* <code>nativeImageMetadataFormatName</code> instance variable,
* which is typically set by the constructor.
*
* @return the name of the native image metadata format, or
* <code>null</code>.
*
* @see #getExtraImageMetadataFormatNames
*/
public String getNativeImageMetadataFormatName() {
return nativeImageMetadataFormatName;
}
/**
* Returns an array of <code>String</code>s containing the names
* of additional document formats, other than the native and
* standard formats, recognized by the
* <code>getAsTree</code> and <code>setFromTree</code> methods on
* the image metadata objects produced or consumed by this
* plug-in.
*
* <p> If the plug-in does not handle image metadata, null should
* be returned.
*
* <p> The set of formats may differ according to the particular
* images being read or written; this method should indicate all
* the additional formats supported by the plug-in under any circumstances.
*
* <p> The default implementation returns a clone of the
* <code>extraImageMetadataFormatNames</code> instance variable,
* which is typically set by the constructor.
*
* @return an array of <code>String</code>s, or null.
*
* @see IIOMetadata#getMetadataFormatNames
* @see #getExtraStreamMetadataFormatNames
* @see #getNativeImageMetadataFormatName
*/
public String[] getExtraImageMetadataFormatNames() {
return extraImageMetadataFormatNames == null ?
null : (String[])extraImageMetadataFormatNames.clone();
}
/**
* Returns an <code>IIOMetadataFormat</code> object describing the
* given stream metadata format, or <code>null</code> if no
* description is available. The supplied name must be the native
* stream metadata format name, the standard metadata format name,
* or one of those returned by
* <code>getExtraStreamMetadataFormatNames</code>.
*
* @param formatName the desired stream metadata format.
*
* @return an <code>IIOMetadataFormat</code> object.
*
* @exception IllegalArgumentException if <code>formatName</code>
* is <code>null</code> or is not a supported name.
*/
public IIOMetadataFormat getStreamMetadataFormat(String formatName) {
return getMetadataFormat(formatName,
supportsStandardStreamMetadataFormat,
nativeStreamMetadataFormatName,
nativeStreamMetadataFormatClassName,
extraStreamMetadataFormatNames,
extraStreamMetadataFormatClassNames);
}
/**
* Returns an <code>IIOMetadataFormat</code> object describing the
* given image metadata format, or <code>null</code> if no
* description is available. The supplied name must be the native
* image metadata format name, the standard metadata format name,
* or one of those returned by
* <code>getExtraImageMetadataFormatNames</code>.
*
* @param formatName the desired image metadata format.
*
* @return an <code>IIOMetadataFormat</code> object.
*
* @exception IllegalArgumentException if <code>formatName</code>
* is <code>null</code> or is not a supported name.
*/
public IIOMetadataFormat getImageMetadataFormat(String formatName) {
return getMetadataFormat(formatName,
supportsStandardImageMetadataFormat,
nativeImageMetadataFormatName,
nativeImageMetadataFormatClassName,
extraImageMetadataFormatNames,
extraImageMetadataFormatClassNames);
}
private IIOMetadataFormat getMetadataFormat(String formatName,
boolean supportsStandard,
String nativeName,
String nativeClassName,
String [] extraNames,
String [] extraClassNames) {
if (formatName == null) {
throw new IllegalArgumentException("formatName == null!");
}
if (supportsStandard && formatName.equals
(IIOMetadataFormatImpl.standardMetadataFormatName)) {
return IIOMetadataFormatImpl.getStandardFormatInstance();
}
String formatClassName = null;
if (formatName.equals(nativeName)) {
formatClassName = nativeClassName;
} else if (extraNames != null) {
for (int i = 0; i < extraNames.length; i++) {
if (formatName.equals(extraNames[i])) {
formatClassName = extraClassNames[i];
break; // out of for
}
}
}
if (formatClassName == null) {
throw new IllegalArgumentException("Unsupported format name");
}
try {
Class cls = Class.forName(formatClassName, true,
ClassLoader.getSystemClassLoader());
Method meth = cls.getMethod("getInstance");
return (IIOMetadataFormat) meth.invoke(null);
} catch (Exception e) {
RuntimeException ex =
new IllegalStateException ("Can't obtain format");
ex.initCause(e);
throw ex;
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import javax.imageio.ImageTranscoder;
/**
* The service provider interface (SPI) for <code>ImageTranscoder</code>s.
* For more information on service provider classes, see the class comment
* for the <code>IIORegistry</code> class.
*
* @see IIORegistry
* @see javax.imageio.ImageTranscoder
*
*/
public abstract class ImageTranscoderSpi extends IIOServiceProvider {
/**
* Constructs a blank <code>ImageTranscoderSpi</code>. It is up
* to the subclass to initialize instance variables and/or
* override method implementations in order to provide working
* versions of all methods.
*/
protected ImageTranscoderSpi() {
}
/**
* Constructs an <code>ImageTranscoderSpi</code> with a given set
* of values.
*
* @param vendorName the vendor name.
* @param version a version identifier.
*/
public ImageTranscoderSpi(String vendorName,
String version) {
super(vendorName, version);
}
/**
* Returns the fully qualified class name of an
* <code>ImageReaderSpi</code> class that generates
* <code>IIOMetadata</code> objects that may be used as input to
* this transcoder.
*
* @return a <code>String</code> containing the fully-qualified
* class name of the <code>ImageReaderSpi</code> implementation class.
*
* @see ImageReaderSpi
*/
public abstract String getReaderServiceProviderName();
/**
* Returns the fully qualified class name of an
* <code>ImageWriterSpi</code> class that generates
* <code>IIOMetadata</code> objects that may be used as input to
* this transcoder.
*
* @return a <code>String</code> containing the fully-qualified
* class name of the <code>ImageWriterSpi</code> implementation class.
*
* @see ImageWriterSpi
*/
public abstract String getWriterServiceProviderName();
/**
* Returns an instance of the <code>ImageTranscoder</code>
* implementation associated with this service provider.
*
* @return an <code>ImageTranscoder</code> instance.
*/
public abstract ImageTranscoder createTranscoderInstance();
}

View File

@@ -0,0 +1,440 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.awt.image.RenderedImage;
import java.io.IOException;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
/**
* The service provider interface (SPI) for <code>ImageWriter</code>s.
* For more information on service provider classes, see the class comment
* for the <code>IIORegistry</code> class.
*
* <p> Each <code>ImageWriterSpi</code> provides several types of information
* about the <code>ImageWriter</code> class with which it is associated.
*
* <p> The name of the vendor who defined the SPI class and a
* brief description of the class are available via the
* <code>getVendorName</code>, <code>getDescription</code>,
* and <code>getVersion</code> methods.
* These methods may be internationalized to provide locale-specific
* output. These methods are intended mainly to provide short,
* human-writable information that might be used to organize a pop-up
* menu or other list.
*
* <p> Lists of format names, file suffixes, and MIME types associated
* with the service may be obtained by means of the
* <code>getFormatNames</code>, <code>getFileSuffixes</code>, and
* <code>getMIMEType</code> methods. These methods may be used to
* identify candidate <code>ImageWriter</code>s for writing a
* particular file or stream based on manual format selection, file
* naming, or MIME associations.
*
* <p> A more reliable way to determine which <code>ImageWriter</code>s
* are likely to be able to parse a particular data stream is provided
* by the <code>canEncodeImage</code> method. This methods allows the
* service provider to inspect the actual image contents.
*
* <p> Finally, an instance of the <code>ImageWriter</code> class
* associated with this service provider may be obtained by calling
* the <code>createWriterInstance</code> method. Any heavyweight
* initialization, such as the loading of native libraries or creation
* of large tables, should be deferred at least until the first
* invocation of this method.
*
* @see IIORegistry
* @see javax.imageio.ImageTypeSpecifier
* @see javax.imageio.ImageWriter
*
*/
public abstract class ImageWriterSpi extends ImageReaderWriterSpi {
/**
* A single-element array, initially containing
* <code>ImageOutputStream.class</code>, to be returned from
* <code>getOutputTypes</code>.
* @deprecated Instead of using this field, directly create
* the equivalent array <code>{ ImageOutputStream.class }</code>.
*/
@Deprecated
public static final Class[] STANDARD_OUTPUT_TYPE =
{ ImageOutputStream.class };
/**
* An array of <code>Class</code> objects to be returned from
* <code>getOutputTypes</code>, initially <code>null</code>.
*/
protected Class[] outputTypes = null;
/**
* An array of strings to be returned from
* <code>getImageReaderSpiNames</code>, initially
* <code>null</code>.
*/
protected String[] readerSpiNames = null;
/**
* The <code>Class</code> of the writer, initially
* <code>null</code>.
*/
private Class writerClass = null;
/**
* Constructs a blank <code>ImageWriterSpi</code>. It is up to
* the subclass to initialize instance variables and/or override
* method implementations in order to provide working versions of
* all methods.
*/
protected ImageWriterSpi() {
}
/**
* Constructs an <code>ImageWriterSpi</code> with a given
* set of values.
*
* @param vendorName the vendor name, as a non-<code>null</code>
* <code>String</code>.
* @param version a version identifier, as a non-<code>null</code>
* <code>String</code>.
* @param names a non-<code>null</code> array of
* <code>String</code>s indicating the format names. At least one
* entry must be present.
* @param suffixes an array of <code>String</code>s indicating the
* common file suffixes. If no suffixes are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param MIMETypes an array of <code>String</code>s indicating
* the format's MIME types. If no suffixes are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param writerClassName the fully-qualified name of the
* associated <code>ImageWriterSpi</code> class, as a
* non-<code>null</code> <code>String</code>.
* @param outputTypes an array of <code>Class</code> objects of
* length at least 1 indicating the legal output types.
* @param readerSpiNames an array <code>String</code>s of length
* at least 1 naming the classes of all associated
* <code>ImageReader</code>s, or <code>null</code>. An array of
* length 0 is normalized to <code>null</code>.
* @param supportsStandardStreamMetadataFormat a
* <code>boolean</code> that indicates whether a stream metadata
* object can use trees described by the standard metadata format.
* @param nativeStreamMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeStreamMetadataFormatName</code>.
* @param nativeStreamMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeStreamMetadataFormat</code>.
* @param extraStreamMetadataFormatNames an array of
* <code>String</code>s, or <code>null</code>, to be returned from
* <code>getExtraStreamMetadataFormatNames</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param extraStreamMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getStreamMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param supportsStandardImageMetadataFormat a
* <code>boolean</code> that indicates whether an image metadata
* object can use trees described by the standard metadata format.
* @param nativeImageMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeImageMetadataFormatName</code>.
* @param nativeImageMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeImageMetadataFormat</code>.
* @param extraImageMetadataFormatNames an array of
* <code>String</code>s to be returned from
* <code>getExtraImageMetadataFormatNames</code>. An array of length 0
* is normalized to <code>null</code>.
* @param extraImageMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getImageMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>names</code>
* is <code>null</code> or has length 0.
* @exception IllegalArgumentException if <code>writerClassName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>outputTypes</code>
* is <code>null</code> or has length 0.
*/
public ImageWriterSpi(String vendorName,
String version,
String[] names,
String[] suffixes,
String[] MIMETypes,
String writerClassName,
Class[] outputTypes,
String[] readerSpiNames,
boolean supportsStandardStreamMetadataFormat,
String nativeStreamMetadataFormatName,
String nativeStreamMetadataFormatClassName,
String[] extraStreamMetadataFormatNames,
String[] extraStreamMetadataFormatClassNames,
boolean supportsStandardImageMetadataFormat,
String nativeImageMetadataFormatName,
String nativeImageMetadataFormatClassName,
String[] extraImageMetadataFormatNames,
String[] extraImageMetadataFormatClassNames) {
super(vendorName, version,
names, suffixes, MIMETypes, writerClassName,
supportsStandardStreamMetadataFormat,
nativeStreamMetadataFormatName,
nativeStreamMetadataFormatClassName,
extraStreamMetadataFormatNames,
extraStreamMetadataFormatClassNames,
supportsStandardImageMetadataFormat,
nativeImageMetadataFormatName,
nativeImageMetadataFormatClassName,
extraImageMetadataFormatNames,
extraImageMetadataFormatClassNames);
if (outputTypes == null) {
throw new IllegalArgumentException
("outputTypes == null!");
}
if (outputTypes.length == 0) {
throw new IllegalArgumentException
("outputTypes.length == 0!");
}
this.outputTypes = (outputTypes == STANDARD_OUTPUT_TYPE) ?
new Class<?>[] { ImageOutputStream.class } :
outputTypes.clone();
// If length == 0, leave it null
if (readerSpiNames != null && readerSpiNames.length > 0) {
this.readerSpiNames = (String[])readerSpiNames.clone();
}
}
/**
* Returns <code>true</code> if the format that this writer
* outputs preserves pixel data bit-accurately. The default
* implementation returns <code>true</code>.
*
* @return <code>true</code> if the format preserves full pixel
* accuracy.
*/
public boolean isFormatLossless() {
return true;
}
/**
* Returns an array of <code>Class</code> objects indicating what
* types of objects may be used as arguments to the writer's
* <code>setOutput</code> method.
*
* <p> For most writers, which only output to an
* <code>ImageOutputStream</code>, a single-element array
* containing <code>ImageOutputStream.class</code> should be
* returned.
*
* @return a non-<code>null</code> array of
* <code>Class</code>objects of length at least 1.
*/
public Class[] getOutputTypes() {
return (Class[])outputTypes.clone();
}
/**
* Returns <code>true</code> if the <code>ImageWriter</code>
* implementation associated with this service provider is able to
* encode an image with the given layout. The layout
* (<i>i.e.</i>, the image's <code>SampleModel</code> and
* <code>ColorModel</code>) is described by an
* <code>ImageTypeSpecifier</code> object.
*
* <p> A return value of <code>true</code> is not an absolute
* guarantee of successful encoding; the encoding process may still
* produce errors due to factors such as I/O errors, inconsistent
* or malformed data structures, etc. The intent is that a
* reasonable inspection of the basic structure of the image be
* performed in order to determine if it is within the scope of
* the encoding format. For example, a service provider for a
* format that can only encode greyscale would return
* <code>false</code> if handed an RGB <code>BufferedImage</code>.
* Similarly, a service provider for a format that can encode
* 8-bit RGB imagery might refuse to encode an image with an
* associated alpha channel.
*
* <p> Different <code>ImageWriter</code>s, and thus service
* providers, may choose to be more or less strict. For example,
* they might accept an image with premultiplied alpha even though
* it will have to be divided out of each pixel, at some loss of
* precision, in order to be stored.
*
* @param type an <code>ImageTypeSpecifier</code> specifying the
* layout of the image to be written.
*
* @return <code>true</code> if this writer is likely to be able
* to encode images with the given layout.
*
* @exception IllegalArgumentException if <code>type</code>
* is <code>null</code>.
*/
public abstract boolean canEncodeImage(ImageTypeSpecifier type);
/**
* Returns <code>true</code> if the <code>ImageWriter</code>
* implementation associated with this service provider is able to
* encode the given <code>RenderedImage</code> instance. Note
* that this includes instances of
* <code>java.awt.image.BufferedImage</code>.
*
* <p> See the discussion for
* <code>canEncodeImage(ImageTypeSpecifier)</code> for information
* on the semantics of this method.
*
* @param im an instance of <code>RenderedImage</code> to be encoded.
*
* @return <code>true</code> if this writer is likely to be able
* to encode this image.
*
* @exception IllegalArgumentException if <code>im</code>
* is <code>null</code>.
*/
public boolean canEncodeImage(RenderedImage im) {
return canEncodeImage(ImageTypeSpecifier.createFromRenderedImage(im));
}
/**
* Returns an instance of the <code>ImageWriter</code>
* implementation associated with this service provider.
* The returned object will initially be in an initial state as if
* its <code>reset</code> method had been called.
*
* <p> The default implementation simply returns
* <code>createWriterInstance(null)</code>.
*
* @return an <code>ImageWriter</code> instance.
*
* @exception IOException if an error occurs during loading,
* or initialization of the writer class, or during instantiation
* or initialization of the writer object.
*/
public ImageWriter createWriterInstance() throws IOException {
return createWriterInstance(null);
}
/**
* Returns an instance of the <code>ImageWriter</code>
* implementation associated with this service provider.
* The returned object will initially be in an initial state
* as if its <code>reset</code> method had been called.
*
* <p> An <code>Object</code> may be supplied to the plug-in at
* construction time. The nature of the object is entirely
* plug-in specific.
*
* <p> Typically, a plug-in will implement this method using code
* such as <code>return new MyImageWriter(this)</code>.
*
* @param extension a plug-in specific extension object, which may
* be <code>null</code>.
*
* @return an <code>ImageWriter</code> instance.
*
* @exception IOException if the attempt to instantiate
* the writer fails.
* @exception IllegalArgumentException if the
* <code>ImageWriter</code>'s constructor throws an
* <code>IllegalArgumentException</code> to indicate that the
* extension object is unsuitable.
*/
public abstract ImageWriter createWriterInstance(Object extension)
throws IOException;
/**
* Returns <code>true</code> if the <code>ImageWriter</code> object
* passed in is an instance of the <code>ImageWriter</code>
* associated with this service provider.
*
* @param writer an <code>ImageWriter</code> instance.
*
* @return <code>true</code> if <code>writer</code> is recognized
*
* @exception IllegalArgumentException if <code>writer</code> is
* <code>null</code>.
*/
public boolean isOwnWriter(ImageWriter writer) {
if (writer == null) {
throw new IllegalArgumentException("writer == null!");
}
String name = writer.getClass().getName();
return name.equals(pluginClassName);
}
/**
* Returns an array of <code>String</code>s containing all the
* fully qualified names of all the <code>ImageReaderSpi</code>
* classes that can understand the internal metadata
* representation used by the <code>ImageWriter</code> associated
* with this service provider, or <code>null</code> if there are
* no such <code>ImageReaders</code> specified. If a
* non-<code>null</code> value is returned, it must have non-zero
* length.
*
* <p> The first item in the array must be the name of the service
* provider for the "preferred" reader, as it will be used to
* instantiate the <code>ImageReader</code> returned by
* <code>ImageIO.getImageReader(ImageWriter)</code>.
*
* <p> This mechanism may be used to obtain
* <code>ImageReaders</code> that will generated non-pixel
* meta-data (see <code>IIOExtraDataInfo</code>) in a structure
* understood by an <code>ImageWriter</code>. By reading the
* image and obtaining this data from one of the
* <code>ImageReaders</code> obtained with this method and passing
* it on to the <code>ImageWriter</code>, a client program can
* read an image, modify it in some way, and write it back out
* preserving all meta-data, without having to understand anything
* about the internal structure of the meta-data, or even about
* the image format.
*
* @return an array of <code>String</code>s of length at least 1
* containing names of <code>ImageReaderSpi</code>s, or
* <code>null</code>.
*
* @see javax.imageio.ImageIO#getImageReader(ImageWriter)
* @see ImageReaderSpi#getImageWriterSpiNames()
*/
public String[] getImageReaderSpiNames() {
return readerSpiNames == null ?
null : (String[])readerSpiNames.clone();
}
}

View File

@@ -0,0 +1,214 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
/**
* A set of <code>Object</code>s with pairwise orderings between them.
* The <code>iterator</code> method provides the elements in
* topologically sorted order. Elements participating in a cycle
* are not returned.
*
* Unlike the <code>SortedSet</code> and <code>SortedMap</code>
* interfaces, which require their elements to implement the
* <code>Comparable</code> interface, this class receives ordering
* information via its <code>setOrdering</code> and
* <code>unsetPreference</code> methods. This difference is due to
* the fact that the relevant ordering between elements is unlikely to
* be inherent in the elements themselves; rather, it is set
* dynamically accoring to application policy. For example, in a
* service provider registry situation, an application might allow the
* user to set a preference order for service provider objects
* supplied by a trusted vendor over those supplied by another.
*
*/
class PartiallyOrderedSet extends AbstractSet {
// The topological sort (roughly) follows the algorithm described in
// Horowitz and Sahni, _Fundamentals of Data Structures_ (1976),
// p. 315.
// Maps Objects to DigraphNodes that contain them
private Map poNodes = new HashMap();
// The set of Objects
private Set nodes = poNodes.keySet();
/**
* Constructs a <code>PartiallyOrderedSet</code>.
*/
public PartiallyOrderedSet() {}
public int size() {
return nodes.size();
}
public boolean contains(Object o) {
return nodes.contains(o);
}
/**
* Returns an iterator over the elements contained in this
* collection, with an ordering that respects the orderings set
* by the <code>setOrdering</code> method.
*/
public Iterator iterator() {
return new PartialOrderIterator(poNodes.values().iterator());
}
/**
* Adds an <code>Object</code> to this
* <code>PartiallyOrderedSet</code>.
*/
public boolean add(Object o) {
if (nodes.contains(o)) {
return false;
}
DigraphNode node = new DigraphNode(o);
poNodes.put(o, node);
return true;
}
/**
* Removes an <code>Object</code> from this
* <code>PartiallyOrderedSet</code>.
*/
public boolean remove(Object o) {
DigraphNode node = (DigraphNode)poNodes.get(o);
if (node == null) {
return false;
}
poNodes.remove(o);
node.dispose();
return true;
}
public void clear() {
poNodes.clear();
}
/**
* Sets an ordering between two nodes. When an iterator is
* requested, the first node will appear earlier in the
* sequence than the second node. If a prior ordering existed
* between the nodes in the opposite order, it is removed.
*
* @return <code>true</code> if no prior ordering existed
* between the nodes, <code>false</code>otherwise.
*/
public boolean setOrdering(Object first, Object second) {
DigraphNode firstPONode =
(DigraphNode)poNodes.get(first);
DigraphNode secondPONode =
(DigraphNode)poNodes.get(second);
secondPONode.removeEdge(firstPONode);
return firstPONode.addEdge(secondPONode);
}
/**
* Removes any ordering between two nodes.
*
* @return true if a prior prefence existed between the nodes.
*/
public boolean unsetOrdering(Object first, Object second) {
DigraphNode firstPONode =
(DigraphNode)poNodes.get(first);
DigraphNode secondPONode =
(DigraphNode)poNodes.get(second);
return firstPONode.removeEdge(secondPONode) ||
secondPONode.removeEdge(firstPONode);
}
/**
* Returns <code>true</code> if an ordering exists between two
* nodes.
*/
public boolean hasOrdering(Object preferred, Object other) {
DigraphNode preferredPONode =
(DigraphNode)poNodes.get(preferred);
DigraphNode otherPONode =
(DigraphNode)poNodes.get(other);
return preferredPONode.hasEdge(otherPONode);
}
}
class PartialOrderIterator implements Iterator {
LinkedList zeroList = new LinkedList();
Map inDegrees = new HashMap(); // DigraphNode -> Integer
public PartialOrderIterator(Iterator iter) {
// Initialize scratch in-degree values, zero list
while (iter.hasNext()) {
DigraphNode node = (DigraphNode)iter.next();
int inDegree = node.getInDegree();
inDegrees.put(node, new Integer(inDegree));
// Add nodes with zero in-degree to the zero list
if (inDegree == 0) {
zeroList.add(node);
}
}
}
public boolean hasNext() {
return !zeroList.isEmpty();
}
public Object next() {
DigraphNode first = (DigraphNode)zeroList.removeFirst();
// For each out node of the output node, decrement its in-degree
Iterator outNodes = first.getOutNodes();
while (outNodes.hasNext()) {
DigraphNode node = (DigraphNode)outNodes.next();
int inDegree = ((Integer)inDegrees.get(node)).intValue() - 1;
inDegrees.put(node, new Integer(inDegree));
// If the in-degree has fallen to 0, place the node on the list
if (inDegree == 0) {
zeroList.add(node);
}
}
return first.getData();
}
public void remove() {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
/**
* An optional interface that may be provided by service provider
* objects that will be registered with a
* <code>ServiceRegistry</code>. If this interface is present,
* notification of registration and deregistration will be performed.
*
* @see ServiceRegistry
*
*/
public interface RegisterableService {
/**
* Called when an object implementing this interface is added to
* the given <code>category</code> of the given
* <code>registry</code>. The object may already be registered
* under another category or categories.
*
* @param registry a <code>ServiceRegistry</code> where this
* object has been registered.
* @param category a <code>Class</code> object indicating the
* registry category under which this object has been registered.
*/
void onRegistration(ServiceRegistry registry, Class<?> category);
/**
* Called when an object implementing this interface is removed
* from the given <code>category</code> of the given
* <code>registry</code>. The object may still be registered
* under another category or categories.
*
* @param registry a <code>ServiceRegistry</code> from which this
* object is being (wholly or partially) deregistered.
* @param category a <code>Class</code> object indicating the
* registry category from which this object is being deregistered.
*/
void onDeregistration(ServiceRegistry registry, Class<?> category);
}

View File

@@ -0,0 +1,859 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.File;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.ServiceLoader;
/**
* A registry for service provider instances.
*
* <p> A <i>service</i> is a well-known set of interfaces and (usually
* abstract) classes. A <i>service provider</i> is a specific
* implementation of a service. The classes in a provider typically
* implement the interface or subclass the class defined by the
* service itself.
*
* <p> Service providers are stored in one or more <i>categories</i>,
* each of which is defined by a class of interface (described by a
* <code>Class</code> object) that all of its members must implement.
* The set of categories may be changed dynamically.
*
* <p> Only a single instance of a given leaf class (that is, the
* actual class returned by <code>getClass()</code>, as opposed to any
* inherited classes or interfaces) may be registered. That is,
* suppose that the
* <code>com.mycompany.mypkg.GreenServiceProvider</code> class
* implements the <code>com.mycompany.mypkg.MyService</code>
* interface. If a <code>GreenServiceProvider</code> instance is
* registered, it will be stored in the category defined by the
* <code>MyService</code> class. If a new instance of
* <code>GreenServiceProvider</code> is registered, it will replace
* the previous instance. In practice, service provider objects are
* usually singletons so this behavior is appropriate.
*
* <p> To declare a service provider, a <code>services</code>
* subdirectory is placed within the <code>META-INF</code> directory
* that is present in every JAR file. This directory contains a file
* for each service provider interface that has one or more
* implementation classes present in the JAR file. For example, if
* the JAR file contained a class named
* <code>com.mycompany.mypkg.MyServiceImpl</code> which implements the
* <code>javax.someapi.SomeService</code> interface, the JAR file
* would contain a file named: <pre>
* META-INF/services/javax.someapi.SomeService </pre>
*
* containing the line:
*
* <pre>
* com.mycompany.mypkg.MyService
* </pre>
*
* <p> The service provider classes should be to be lightweight and
* quick to load. Implementations of these interfaces should avoid
* complex dependencies on other classes and on native code. The usual
* pattern for more complex services is to register a lightweight
* proxy for the heavyweight service.
*
* <p> An application may customize the contents of a registry as it
* sees fit, so long as it has the appropriate runtime permission.
*
* <p> For more details on declaring service providers, and the JAR
* format in general, see the <a
* href="../../../../technotes/guides/jar/jar.html">
* JAR File Specification</a>.
*
* @see RegisterableService
*
*/
public class ServiceRegistry {
// Class -> Registry
private Map categoryMap = new HashMap();
/**
* Constructs a <code>ServiceRegistry</code> instance with a
* set of categories taken from the <code>categories</code>
* argument.
*
* @param categories an <code>Iterator</code> containing
* <code>Class</code> objects to be used to define categories.
*
* @exception IllegalArgumentException if
* <code>categories</code> is <code>null</code>.
*/
public ServiceRegistry(Iterator<Class<?>> categories) {
if (categories == null) {
throw new IllegalArgumentException("categories == null!");
}
while (categories.hasNext()) {
Class category = (Class)categories.next();
SubRegistry reg = new SubRegistry(this, category);
categoryMap.put(category, reg);
}
}
// The following two methods expose functionality from
// sun.misc.Service. If that class is made public, they may be
// removed.
//
// The sun.misc.ServiceConfigurationError class may also be
// exposed, in which case the references to 'an
// <code>Error</code>' below should be changed to 'a
// <code>ServiceConfigurationError</code>'.
/**
* Searches for implementations of a particular service class
* using the given class loader.
*
* <p> This method transforms the name of the given service class
* into a provider-configuration filename as described in the
* class comment and then uses the <code>getResources</code>
* method of the given class loader to find all available files
* with that name. These files are then read and parsed to
* produce a list of provider-class names. The iterator that is
* returned uses the given class loader to look up and then
* instantiate each element of the list.
*
* <p> Because it is possible for extensions to be installed into
* a running Java virtual machine, this method may return
* different results each time it is invoked.
*
* @param providerClass a <code>Class</code>object indicating the
* class or interface of the service providers being detected.
*
* @param loader the class loader to be used to load
* provider-configuration files and instantiate provider classes,
* or <code>null</code> if the system class loader (or, failing that
* the bootstrap class loader) is to be used.
*
* @param <T> the type of the providerClass.
*
* @return An <code>Iterator</code> that yields provider objects
* for the given service, in some arbitrary order. The iterator
* will throw an <code>Error</code> if a provider-configuration
* file violates the specified format or if a provider class
* cannot be found and instantiated.
*
* @exception IllegalArgumentException if
* <code>providerClass</code> is <code>null</code>.
*/
public static <T> Iterator<T> lookupProviders(Class<T> providerClass,
ClassLoader loader)
{
if (providerClass == null) {
throw new IllegalArgumentException("providerClass == null!");
}
return ServiceLoader.load(providerClass, loader).iterator();
}
/**
* Locates and incrementally instantiates the available providers
* of a given service using the context class loader. This
* convenience method is equivalent to:
*
* <pre>
* ClassLoader cl = Thread.currentThread().getContextClassLoader();
* return Service.providers(service, cl);
* </pre>
*
* @param providerClass a <code>Class</code>object indicating the
* class or interface of the service providers being detected.
*
* @param <T> the type of the providerClass.
*
* @return An <code>Iterator</code> that yields provider objects
* for the given service, in some arbitrary order. The iterator
* will throw an <code>Error</code> if a provider-configuration
* file violates the specified format or if a provider class
* cannot be found and instantiated.
*
* @exception IllegalArgumentException if
* <code>providerClass</code> is <code>null</code>.
*/
public static <T> Iterator<T> lookupProviders(Class<T> providerClass) {
if (providerClass == null) {
throw new IllegalArgumentException("providerClass == null!");
}
return ServiceLoader.load(providerClass).iterator();
}
/**
* Returns an <code>Iterator</code> of <code>Class</code> objects
* indicating the current set of categories. The iterator will be
* empty if no categories exist.
*
* @return an <code>Iterator</code> containing
* <code>Class</code>objects.
*/
public Iterator<Class<?>> getCategories() {
Set keySet = categoryMap.keySet();
return keySet.iterator();
}
/**
* Returns an Iterator containing the subregistries to which the
* provider belongs.
*/
private Iterator getSubRegistries(Object provider) {
List l = new ArrayList();
Iterator iter = categoryMap.keySet().iterator();
while (iter.hasNext()) {
Class c = (Class)iter.next();
if (c.isAssignableFrom(provider.getClass())) {
l.add((SubRegistry)categoryMap.get(c));
}
}
return l.iterator();
}
/**
* Adds a service provider object to the registry. The provider
* is associated with the given category.
*
* <p> If <code>provider</code> implements the
* <code>RegisterableService</code> interface, its
* <code>onRegistration</code> method will be called. Its
* <code>onDeregistration</code> method will be called each time
* it is deregistered from a category, for example if a
* category is removed or the registry is garbage collected.
*
* @param provider the service provide object to be registered.
* @param category the category under which to register the
* provider.
* @param <T> the type of the provider.
*
* @return true if no provider of the same class was previously
* registered in the same category category.
*
* @exception IllegalArgumentException if <code>provider</code> is
* <code>null</code>.
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
* @exception ClassCastException if provider does not implement
* the <code>Class</code> defined by <code>category</code>.
*/
public <T> boolean registerServiceProvider(T provider,
Class<T> category) {
if (provider == null) {
throw new IllegalArgumentException("provider == null!");
}
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
if (!category.isAssignableFrom(provider.getClass())) {
throw new ClassCastException();
}
return reg.registerServiceProvider(provider);
}
/**
* Adds a service provider object to the registry. The provider
* is associated within each category present in the registry
* whose <code>Class</code> it implements.
*
* <p> If <code>provider</code> implements the
* <code>RegisterableService</code> interface, its
* <code>onRegistration</code> method will be called once for each
* category it is registered under. Its
* <code>onDeregistration</code> method will be called each time
* it is deregistered from a category or when the registry is
* finalized.
*
* @param provider the service provider object to be registered.
*
* @exception IllegalArgumentException if
* <code>provider</code> is <code>null</code>.
*/
public void registerServiceProvider(Object provider) {
if (provider == null) {
throw new IllegalArgumentException("provider == null!");
}
Iterator regs = getSubRegistries(provider);
while (regs.hasNext()) {
SubRegistry reg = (SubRegistry)regs.next();
reg.registerServiceProvider(provider);
}
}
/**
* Adds a set of service provider objects, taken from an
* <code>Iterator</code> to the registry. Each provider is
* associated within each category present in the registry whose
* <code>Class</code> it implements.
*
* <p> For each entry of <code>providers</code> that implements
* the <code>RegisterableService</code> interface, its
* <code>onRegistration</code> method will be called once for each
* category it is registered under. Its
* <code>onDeregistration</code> method will be called each time
* it is deregistered from a category or when the registry is
* finalized.
*
* @param providers an Iterator containing service provider
* objects to be registered.
*
* @exception IllegalArgumentException if <code>providers</code>
* is <code>null</code> or contains a <code>null</code> entry.
*/
public void registerServiceProviders(Iterator<?> providers) {
if (providers == null) {
throw new IllegalArgumentException("provider == null!");
}
while (providers.hasNext()) {
registerServiceProvider(providers.next());
}
}
/**
* Removes a service provider object from the given category. If
* the provider was not previously registered, nothing happens and
* <code>false</code> is returned. Otherwise, <code>true</code>
* is returned. If an object of the same class as
* <code>provider</code> but not equal (using <code>==</code>) to
* <code>provider</code> is registered, it will not be
* deregistered.
*
* <p> If <code>provider</code> implements the
* <code>RegisterableService</code> interface, its
* <code>onDeregistration</code> method will be called.
*
* @param provider the service provider object to be deregistered.
* @param category the category from which to deregister the
* provider.
* @param <T> the type of the provider.
*
* @return <code>true</code> if the provider was previously
* registered in the same category category,
* <code>false</code> otherwise.
*
* @exception IllegalArgumentException if <code>provider</code> is
* <code>null</code>.
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
* @exception ClassCastException if provider does not implement
* the class defined by <code>category</code>.
*/
public <T> boolean deregisterServiceProvider(T provider,
Class<T> category) {
if (provider == null) {
throw new IllegalArgumentException("provider == null!");
}
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
if (!category.isAssignableFrom(provider.getClass())) {
throw new ClassCastException();
}
return reg.deregisterServiceProvider(provider);
}
/**
* Removes a service provider object from all categories that
* contain it.
*
* @param provider the service provider object to be deregistered.
*
* @exception IllegalArgumentException if <code>provider</code> is
* <code>null</code>.
*/
public void deregisterServiceProvider(Object provider) {
if (provider == null) {
throw new IllegalArgumentException("provider == null!");
}
Iterator regs = getSubRegistries(provider);
while (regs.hasNext()) {
SubRegistry reg = (SubRegistry)regs.next();
reg.deregisterServiceProvider(provider);
}
}
/**
* Returns <code>true</code> if <code>provider</code> is currently
* registered.
*
* @param provider the service provider object to be queried.
*
* @return <code>true</code> if the given provider has been
* registered.
*
* @exception IllegalArgumentException if <code>provider</code> is
* <code>null</code>.
*/
public boolean contains(Object provider) {
if (provider == null) {
throw new IllegalArgumentException("provider == null!");
}
Iterator regs = getSubRegistries(provider);
while (regs.hasNext()) {
SubRegistry reg = (SubRegistry)regs.next();
if (reg.contains(provider)) {
return true;
}
}
return false;
}
/**
* Returns an <code>Iterator</code> containing all registered
* service providers in the given category. If
* <code>useOrdering</code> is <code>false</code>, the iterator
* will return all of the server provider objects in an arbitrary
* order. Otherwise, the ordering will respect any pairwise
* orderings that have been set. If the graph of pairwise
* orderings contains cycles, any providers that belong to a cycle
* will not be returned.
*
* @param category the category to be retrieved from.
* @param useOrdering <code>true</code> if pairwise orderings
* should be taken account in ordering the returned objects.
* @param <T> the type of the category.
*
* @return an <code>Iterator</code> containing service provider
* objects from the given category, possibly in order.
*
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
*/
public <T> Iterator<T> getServiceProviders(Class<T> category,
boolean useOrdering) {
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
return reg.getServiceProviders(useOrdering);
}
/**
* A simple filter interface used by
* <code>ServiceRegistry.getServiceProviders</code> to select
* providers matching an arbitrary criterion. Classes that
* implement this interface should be defined in order to make use
* of the <code>getServiceProviders</code> method of
* <code>ServiceRegistry</code> that takes a <code>Filter</code>.
*
* @see ServiceRegistry#getServiceProviders(Class, ServiceRegistry.Filter, boolean)
*/
public interface Filter {
/**
* Returns <code>true</code> if the given
* <code>provider</code> object matches the criterion defined
* by this <code>Filter</code>.
*
* @param provider a service provider <code>Object</code>.
*
* @return true if the provider matches the criterion.
*/
boolean filter(Object provider);
}
/**
* Returns an <code>Iterator</code> containing service provider
* objects within a given category that satisfy a criterion
* imposed by the supplied <code>ServiceRegistry.Filter</code>
* object's <code>filter</code> method.
*
* <p> The <code>useOrdering</code> argument controls the
* ordering of the results using the same rules as
* <code>getServiceProviders(Class, boolean)</code>.
*
* @param category the category to be retrieved from.
* @param filter an instance of <code>ServiceRegistry.Filter</code>
* whose <code>filter</code> method will be invoked.
* @param useOrdering <code>true</code> if pairwise orderings
* should be taken account in ordering the returned objects.
* @param <T> the type of the category.
*
* @return an <code>Iterator</code> containing service provider
* objects from the given category, possibly in order.
*
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
*/
public <T> Iterator<T> getServiceProviders(Class<T> category,
Filter filter,
boolean useOrdering) {
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
Iterator iter = getServiceProviders(category, useOrdering);
return new FilterIterator(iter, filter);
}
/**
* Returns the currently registered service provider object that
* is of the given class type. At most one object of a given
* class is allowed to be registered at any given time. If no
* registered object has the desired class type, <code>null</code>
* is returned.
*
* @param providerClass the <code>Class</code> of the desired
* service provider object.
* @param <T> the type of the provider.
*
* @return a currently registered service provider object with the
* desired <code>Class</code>type, or <code>null</code> is none is
* present.
*
* @exception IllegalArgumentException if <code>providerClass</code> is
* <code>null</code>.
*/
public <T> T getServiceProviderByClass(Class<T> providerClass) {
if (providerClass == null) {
throw new IllegalArgumentException("providerClass == null!");
}
Iterator iter = categoryMap.keySet().iterator();
while (iter.hasNext()) {
Class c = (Class)iter.next();
if (c.isAssignableFrom(providerClass)) {
SubRegistry reg = (SubRegistry)categoryMap.get(c);
T provider = reg.getServiceProviderByClass(providerClass);
if (provider != null) {
return provider;
}
}
}
return null;
}
/**
* Sets a pairwise ordering between two service provider objects
* within a given category. If one or both objects are not
* currently registered within the given category, or if the
* desired ordering is already set, nothing happens and
* <code>false</code> is returned. If the providers previously
* were ordered in the reverse direction, that ordering is
* removed.
*
* <p> The ordering will be used by the
* <code>getServiceProviders</code> methods when their
* <code>useOrdering</code> argument is <code>true</code>.
*
* @param category a <code>Class</code> object indicating the
* category under which the preference is to be established.
* @param firstProvider the preferred provider.
* @param secondProvider the provider to which
* <code>firstProvider</code> is preferred.
* @param <T> the type of the category.
*
* @return <code>true</code> if a previously unset ordering
* was established.
*
* @exception IllegalArgumentException if either provider is
* <code>null</code> or they are the same object.
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
*/
public <T> boolean setOrdering(Class<T> category,
T firstProvider,
T secondProvider) {
if (firstProvider == null || secondProvider == null) {
throw new IllegalArgumentException("provider is null!");
}
if (firstProvider == secondProvider) {
throw new IllegalArgumentException("providers are the same!");
}
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
if (reg.contains(firstProvider) &&
reg.contains(secondProvider)) {
return reg.setOrdering(firstProvider, secondProvider);
}
return false;
}
/**
* Sets a pairwise ordering between two service provider objects
* within a given category. If one or both objects are not
* currently registered within the given category, or if no
* ordering is currently set between them, nothing happens
* and <code>false</code> is returned.
*
* <p> The ordering will be used by the
* <code>getServiceProviders</code> methods when their
* <code>useOrdering</code> argument is <code>true</code>.
*
* @param category a <code>Class</code> object indicating the
* category under which the preference is to be disestablished.
* @param firstProvider the formerly preferred provider.
* @param secondProvider the provider to which
* <code>firstProvider</code> was formerly preferred.
* @param <T> the type of the category.
*
* @return <code>true</code> if a previously set ordering was
* disestablished.
*
* @exception IllegalArgumentException if either provider is
* <code>null</code> or they are the same object.
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
*/
public <T> boolean unsetOrdering(Class<T> category,
T firstProvider,
T secondProvider) {
if (firstProvider == null || secondProvider == null) {
throw new IllegalArgumentException("provider is null!");
}
if (firstProvider == secondProvider) {
throw new IllegalArgumentException("providers are the same!");
}
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
if (reg.contains(firstProvider) &&
reg.contains(secondProvider)) {
return reg.unsetOrdering(firstProvider, secondProvider);
}
return false;
}
/**
* Deregisters all service provider object currently registered
* under the given category.
*
* @param category the category to be emptied.
*
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
*/
public void deregisterAll(Class<?> category) {
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
reg.clear();
}
/**
* Deregisters all currently registered service providers from all
* categories.
*/
public void deregisterAll() {
Iterator iter = categoryMap.values().iterator();
while (iter.hasNext()) {
SubRegistry reg = (SubRegistry)iter.next();
reg.clear();
}
}
/**
* Finalizes this object prior to garbage collection. The
* <code>deregisterAll</code> method is called to deregister all
* currently registered service providers. This method should not
* be called from application code.
*
* @exception Throwable if an error occurs during superclass
* finalization.
*/
public void finalize() throws Throwable {
deregisterAll();
super.finalize();
}
}
/**
* A portion of a registry dealing with a single superclass or
* interface.
*/
class SubRegistry {
ServiceRegistry registry;
Class category;
// Provider Objects organized by partial ordering
final PartiallyOrderedSet poset = new PartiallyOrderedSet();
// Class -> Provider Object of that class
final Map<Class<?>,Object> map = new HashMap();
final Map<Class<?>,AccessControlContext> accMap = new HashMap<>();
public SubRegistry(ServiceRegistry registry, Class category) {
this.registry = registry;
this.category = category;
}
public boolean registerServiceProvider(Object provider) {
Object oprovider = map.get(provider.getClass());
boolean present = oprovider != null;
if (present) {
deregisterServiceProvider(oprovider);
}
map.put(provider.getClass(), provider);
accMap.put(provider.getClass(), AccessController.getContext());
poset.add(provider);
if (provider instanceof RegisterableService) {
RegisterableService rs = (RegisterableService)provider;
rs.onRegistration(registry, category);
}
return !present;
}
/**
* If the provider was not previously registered, do nothing.
*
* @return true if the provider was previously registered.
*/
public boolean deregisterServiceProvider(Object provider) {
Object oprovider = map.get(provider.getClass());
if (provider == oprovider) {
map.remove(provider.getClass());
accMap.remove(provider.getClass());
poset.remove(provider);
if (provider instanceof RegisterableService) {
RegisterableService rs = (RegisterableService)provider;
rs.onDeregistration(registry, category);
}
return true;
}
return false;
}
public boolean contains(Object provider) {
Object oprovider = map.get(provider.getClass());
return oprovider == provider;
}
public boolean setOrdering(Object firstProvider,
Object secondProvider) {
return poset.setOrdering(firstProvider, secondProvider);
}
public boolean unsetOrdering(Object firstProvider,
Object secondProvider) {
return poset.unsetOrdering(firstProvider, secondProvider);
}
public Iterator getServiceProviders(boolean useOrdering) {
if (useOrdering) {
return poset.iterator();
} else {
return map.values().iterator();
}
}
public <T> T getServiceProviderByClass(Class<T> providerClass) {
return (T)map.get(providerClass);
}
public void clear() {
Iterator iter = map.values().iterator();
while (iter.hasNext()) {
Object provider = iter.next();
iter.remove();
if (provider instanceof RegisterableService) {
RegisterableService rs = (RegisterableService)provider;
AccessControlContext acc = accMap.get(provider.getClass());
if (acc != null || System.getSecurityManager() == null) {
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
rs.onDeregistration(registry, category);
return null;
}, acc);
}
}
}
poset.clear();
accMap.clear();
}
public void finalize() {
clear();
}
}
/**
* A class for wrapping <code>Iterators</code> with a filter function.
* This provides an iterator for a subset without duplication.
*/
class FilterIterator<T> implements Iterator<T> {
private Iterator<T> iter;
private ServiceRegistry.Filter filter;
private T next = null;
public FilterIterator(Iterator<T> iter,
ServiceRegistry.Filter filter) {
this.iter = iter;
this.filter = filter;
advance();
}
private void advance() {
while (iter.hasNext()) {
T elt = iter.next();
if (filter.filter(elt)) {
next = elt;
return;
}
}
next = null;
}
public boolean hasNext() {
return next != null;
}
public T next() {
if (next == null) {
throw new NoSuchElementException();
}
T o = next;
advance();
return o;
}
public void remove() {
throw new UnsupportedOperationException();
}
}