aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package javax.activation; aoqi@0: aoqi@0: import java.io.InputStream; aoqi@0: import java.io.IOException; aoqi@0: import java.io.OutputStream; aoqi@0: import java.io.PipedInputStream; aoqi@0: import java.io.PipedOutputStream; aoqi@0: import java.io.OutputStreamWriter; aoqi@0: import java.net.URL; aoqi@0: import java.awt.datatransfer.Transferable; aoqi@0: import java.awt.datatransfer.DataFlavor; aoqi@0: import java.awt.datatransfer.UnsupportedFlavorException; aoqi@0: aoqi@0: /** aoqi@0: * The DataHandler class provides a consistent interface to data aoqi@0: * available in many different sources and formats. aoqi@0: * It manages simple stream to string conversions and related operations aoqi@0: * using DataContentHandlers. aoqi@0: * It provides access to commands that can operate on the data. aoqi@0: * The commands are found using a CommandMap.
aoqi@0: * aoqi@0: * DataHandler and the Transferable Interface
aoqi@0: * DataHandler implements the Transferable interface so that data can aoqi@0: * be used in AWT data transfer operations, such as cut and paste and aoqi@0: * drag and drop. The implementation of the Transferable interface aoqi@0: * relies on the availability of an installed DataContentHandler aoqi@0: * object corresponding to the MIME type of the data represented in aoqi@0: * the specific instance of the DataHandler.
aoqi@0: * aoqi@0: * DataHandler and CommandMaps
aoqi@0: * The DataHandler keeps track of the current CommandMap that it uses to
aoqi@0: * service requests for commands (getCommand
,
aoqi@0: * getAllCommands
, getPreferredCommands
).
aoqi@0: * Each instance of a DataHandler may have a CommandMap associated with
aoqi@0: * it using the setCommandMap
method. If a CommandMap was
aoqi@0: * not set, DataHandler calls the getDefaultCommandMap
aoqi@0: * method in CommandMap and uses the value it returns. See
aoqi@0: * CommandMap for more information.
aoqi@0: * aoqi@0: * DataHandler and URLs
aoqi@0: * The current DataHandler implementation creates a private
aoqi@0: * instance of URLDataSource when it is constructed with a URL.
aoqi@0: *
aoqi@0: * @see javax.activation.CommandMap
aoqi@0: * @see javax.activation.DataContentHandler
aoqi@0: * @see javax.activation.DataSource
aoqi@0: * @see javax.activation.URLDataSource
aoqi@0: *
aoqi@0: * @since 1.6
aoqi@0: */
aoqi@0:
aoqi@0: public class DataHandler implements Transferable {
aoqi@0:
aoqi@0: // Use the datasource to indicate whether we were started via the
aoqi@0: // DataSource constructor or the object constructor.
aoqi@0: private DataSource dataSource = null;
aoqi@0: private DataSource objDataSource = null;
aoqi@0:
aoqi@0: // The Object and mimetype from the constructor (if passed in).
aoqi@0: // object remains null if it was instantiated with a
aoqi@0: // DataSource.
aoqi@0: private Object object = null;
aoqi@0: private String objectMimeType = null;
aoqi@0:
aoqi@0: // Keep track of the CommandMap
aoqi@0: private CommandMap currentCommandMap = null;
aoqi@0:
aoqi@0: // our transfer flavors
aoqi@0: private static final DataFlavor emptyFlavors[] = new DataFlavor[0];
aoqi@0: private DataFlavor transferFlavors[] = emptyFlavors;
aoqi@0:
aoqi@0: // our DataContentHandler
aoqi@0: private DataContentHandler dataContentHandler = null;
aoqi@0: private DataContentHandler factoryDCH = null;
aoqi@0:
aoqi@0: // our DataContentHandlerFactory
aoqi@0: private static DataContentHandlerFactory factory = null;
aoqi@0: private DataContentHandlerFactory oldFactory = null;
aoqi@0: // the short representation of the ContentType (sans params)
aoqi@0: private String shortType = null;
aoqi@0:
aoqi@0: /**
aoqi@0: * Create a DataHandler
instance referencing the
aoqi@0: * specified DataSource. The data exists in a byte stream form.
aoqi@0: * The DataSource will provide an InputStream to access the data.
aoqi@0: *
aoqi@0: * @param ds the DataSource
aoqi@0: */
aoqi@0: public DataHandler(DataSource ds) {
aoqi@0: // save a reference to the incoming DS
aoqi@0: dataSource = ds;
aoqi@0: oldFactory = factory; // keep track of the factory
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Create a DataHandler
instance representing an object
aoqi@0: * of this MIME type. This constructor is
aoqi@0: * used when the application already has an in-memory representation
aoqi@0: * of the data in the form of a Java Object.
aoqi@0: *
aoqi@0: * @param obj the Java Object
aoqi@0: * @param mimeType the MIME type of the object
aoqi@0: */
aoqi@0: public DataHandler(Object obj, String mimeType) {
aoqi@0: object = obj;
aoqi@0: objectMimeType = mimeType;
aoqi@0: oldFactory = factory; // keep track of the factory
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Create a DataHandler
instance referencing a URL.
aoqi@0: * The DataHandler internally creates a URLDataSource
aoqi@0: * instance to represent the URL.
aoqi@0: *
aoqi@0: * @param url a URL object
aoqi@0: */
aoqi@0: public DataHandler(URL url) {
aoqi@0: dataSource = new URLDataSource(url);
aoqi@0: oldFactory = factory; // keep track of the factory
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the CommandMap for this instance of DataHandler.
aoqi@0: */
aoqi@0: private synchronized CommandMap getCommandMap() {
aoqi@0: if (currentCommandMap != null)
aoqi@0: return currentCommandMap;
aoqi@0: else
aoqi@0: return CommandMap.getDefaultCommandMap();
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the DataSource associated with this instance
aoqi@0: * of DataHandler.
aoqi@0: *
aoqi@0: * For DataHandlers that have been instantiated with a DataSource,
aoqi@0: * this method returns the DataSource that was used to create the
aoqi@0: * DataHandler object. In other cases the DataHandler
aoqi@0: * constructs a DataSource from the data used to construct
aoqi@0: * the DataHandler. DataSources created for DataHandlers not
aoqi@0: * instantiated with a DataSource are cached for performance
aoqi@0: * reasons.
aoqi@0: *
aoqi@0: * @return a valid DataSource object for this DataHandler
aoqi@0: */
aoqi@0: public DataSource getDataSource() {
aoqi@0: if (dataSource == null) {
aoqi@0: // create one on the fly
aoqi@0: if (objDataSource == null)
aoqi@0: objDataSource = new DataHandlerDataSource(this);
aoqi@0: return objDataSource;
aoqi@0: }
aoqi@0: return dataSource;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the name of the data object. If this DataHandler
aoqi@0: * was created with a DataSource, this method calls through
aoqi@0: * to the DataSource.getName
method, otherwise it
aoqi@0: * returns null.
aoqi@0: *
aoqi@0: * @return the name of the object
aoqi@0: */
aoqi@0: public String getName() {
aoqi@0: if (dataSource != null)
aoqi@0: return dataSource.getName();
aoqi@0: else
aoqi@0: return null;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the MIME type of this object as retrieved from
aoqi@0: * the source object. Note that this is the full
aoqi@0: * type with parameters.
aoqi@0: *
aoqi@0: * @return the MIME type
aoqi@0: */
aoqi@0: public String getContentType() {
aoqi@0: if (dataSource != null) // data source case
aoqi@0: return dataSource.getContentType();
aoqi@0: else
aoqi@0: return objectMimeType; // obj/type case
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Get the InputStream for this object.
aoqi@0: *
aoqi@0: * For DataHandlers instantiated with a DataSource, the DataHandler
aoqi@0: * calls the DataSource.getInputStream
method and
aoqi@0: * returns the result to the caller.
aoqi@0: *
aoqi@0: * For DataHandlers instantiated with an Object, the DataHandler
aoqi@0: * first attempts to find a DataContentHandler for the Object. If
aoqi@0: * the DataHandler can not find a DataContentHandler for this MIME
aoqi@0: * type, it throws an UnsupportedDataTypeException. If it is
aoqi@0: * successful, it creates a pipe and a thread. The thread uses the
aoqi@0: * DataContentHandler's writeTo
method to write the
aoqi@0: * stream data into one end of the pipe. The other end of the pipe
aoqi@0: * is returned to the caller. Because a thread is created to copy
aoqi@0: * the data, IOExceptions that may occur during the copy can not be
aoqi@0: * propagated back to the caller. The result is an empty stream.
aoqi@0: *
aoqi@0: * @return the InputStream representing this data
aoqi@0: * @exception IOException if an I/O error occurs
aoqi@0: *
aoqi@0: * @see javax.activation.DataContentHandler#writeTo
aoqi@0: * @see javax.activation.UnsupportedDataTypeException
aoqi@0: */
aoqi@0: public InputStream getInputStream() throws IOException {
aoqi@0: InputStream ins = null;
aoqi@0:
aoqi@0: if (dataSource != null) {
aoqi@0: ins = dataSource.getInputStream();
aoqi@0: } else {
aoqi@0: DataContentHandler dch = getDataContentHandler();
aoqi@0: // we won't even try if we can't get a dch
aoqi@0: if (dch == null)
aoqi@0: throw new UnsupportedDataTypeException(
aoqi@0: "no DCH for MIME type " + getBaseType());
aoqi@0:
aoqi@0: if (dch instanceof ObjectDataContentHandler) {
aoqi@0: if (((ObjectDataContentHandler)dch).getDCH() == null)
aoqi@0: throw new UnsupportedDataTypeException(
aoqi@0: "no object DCH for MIME type " + getBaseType());
aoqi@0: }
aoqi@0: // there is none but the default^^^^^^^^^^^^^^^^
aoqi@0: final DataContentHandler fdch = dch;
aoqi@0:
aoqi@0: // from bill s.
aoqi@0: // ce n'est pas une pipe!
aoqi@0: //
aoqi@0: // NOTE: This block of code needs to throw exceptions, but
aoqi@0: // can't because it is in another thread!!! ARG!
aoqi@0: //
aoqi@0: final PipedOutputStream pos = new PipedOutputStream();
aoqi@0: PipedInputStream pin = new PipedInputStream(pos);
aoqi@0: new Thread(
aoqi@0: new Runnable() {
aoqi@0: public void run() {
aoqi@0: try {
aoqi@0: fdch.writeTo(object, objectMimeType, pos);
aoqi@0: } catch (IOException e) {
aoqi@0:
aoqi@0: } finally {
aoqi@0: try {
aoqi@0: pos.close();
aoqi@0: } catch (IOException ie) { }
aoqi@0: }
aoqi@0: }
aoqi@0: },
aoqi@0: "DataHandler.getInputStream").start();
aoqi@0: ins = pin;
aoqi@0: }
aoqi@0:
aoqi@0: return ins;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Write the data to an OutputStream
.
aoqi@0: * aoqi@0: * If the DataHandler was created with a DataSource, writeTo aoqi@0: * retrieves the InputStream and copies the bytes from the aoqi@0: * InputStream to the OutputStream passed in. aoqi@0: *
aoqi@0: * If the DataHandler was created with an object, writeTo
aoqi@0: * retrieves the DataContentHandler for the object's type.
aoqi@0: * If the DataContentHandler was found, it calls the
aoqi@0: * writeTo
method on the DataContentHandler
.
aoqi@0: *
aoqi@0: * @param os the OutputStream to write to
aoqi@0: * @exception IOException if an I/O error occurs
aoqi@0: */
aoqi@0: public void writeTo(OutputStream os) throws IOException {
aoqi@0: // for the DataSource case
aoqi@0: if (dataSource != null) {
aoqi@0: InputStream is = null;
aoqi@0: byte data[] = new byte[8*1024];
aoqi@0: int bytes_read;
aoqi@0:
aoqi@0: is = dataSource.getInputStream();
aoqi@0:
aoqi@0: try {
aoqi@0: while ((bytes_read = is.read(data)) > 0) {
aoqi@0: os.write(data, 0, bytes_read);
aoqi@0: }
aoqi@0: } finally {
aoqi@0: is.close();
aoqi@0: is = null;
aoqi@0: }
aoqi@0: } else { // for the Object case
aoqi@0: DataContentHandler dch = getDataContentHandler();
aoqi@0: dch.writeTo(object, objectMimeType, os);
aoqi@0: }
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Get an OutputStream for this DataHandler to allow overwriting
aoqi@0: * the underlying data.
aoqi@0: * If the DataHandler was created with a DataSource, the
aoqi@0: * DataSource's getOutputStream
method is called.
aoqi@0: * Otherwise, null
is returned.
aoqi@0: *
aoqi@0: * @return the OutputStream
aoqi@0: *
aoqi@0: * @see javax.activation.DataSource#getOutputStream
aoqi@0: * @see javax.activation.URLDataSource
aoqi@0: */
aoqi@0: public OutputStream getOutputStream() throws IOException {
aoqi@0: if (dataSource != null)
aoqi@0: return dataSource.getOutputStream();
aoqi@0: else
aoqi@0: return null;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the DataFlavors in which this data is available.
aoqi@0: * aoqi@0: * Returns an array of DataFlavor objects indicating the flavors aoqi@0: * the data can be provided in. The array is usually ordered aoqi@0: * according to preference for providing the data, from most aoqi@0: * richly descriptive to least richly descriptive.
aoqi@0: *
aoqi@0: * The DataHandler attempts to find a DataContentHandler that
aoqi@0: * corresponds to the MIME type of the data. If one is located,
aoqi@0: * the DataHandler calls the DataContentHandler's
aoqi@0: * getTransferDataFlavors
method.
aoqi@0: *
aoqi@0: * If a DataContentHandler can not be located, and if the
aoqi@0: * DataHandler was created with a DataSource (or URL), one
aoqi@0: * DataFlavor is returned that represents this object's MIME type
aoqi@0: * and the java.io.InputStream
class. If the
aoqi@0: * DataHandler was created with an object and a MIME type,
aoqi@0: * getTransferDataFlavors returns one DataFlavor that represents
aoqi@0: * this object's MIME type and the object's class.
aoqi@0: *
aoqi@0: * @return an array of data flavors in which this data can be transferred
aoqi@0: * @see javax.activation.DataContentHandler#getTransferDataFlavors
aoqi@0: */
aoqi@0: public synchronized DataFlavor[] getTransferDataFlavors() {
aoqi@0: if (factory != oldFactory) // if the factory has changed, clear cache
aoqi@0: transferFlavors = emptyFlavors;
aoqi@0:
aoqi@0: // if it's not set, set it...
aoqi@0: if (transferFlavors == emptyFlavors)
aoqi@0: transferFlavors = getDataContentHandler().getTransferDataFlavors();
aoqi@0:
aoqi@0: if (transferFlavors == emptyFlavors)
aoqi@0: return transferFlavors;
aoqi@0: else
aoqi@0: return transferFlavors.clone();
aoqi@0:
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Returns whether the specified data flavor is supported
aoqi@0: * for this object.
aoqi@0: *
aoqi@0: * This method iterates through the DataFlavors returned from
aoqi@0: * getTransferDataFlavors
, comparing each with
aoqi@0: * the specified flavor.
aoqi@0: *
aoqi@0: * @param flavor the requested flavor for the data
aoqi@0: * @return true if the data flavor is supported
aoqi@0: * @see javax.activation.DataHandler#getTransferDataFlavors
aoqi@0: */
aoqi@0: public boolean isDataFlavorSupported(DataFlavor flavor) {
aoqi@0: DataFlavor[] lFlavors = getTransferDataFlavors();
aoqi@0:
aoqi@0: for (int i = 0; i < lFlavors.length; i++) {
aoqi@0: if (lFlavors[i].equals(flavor))
aoqi@0: return true;
aoqi@0: }
aoqi@0: return false;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Returns an object that represents the data to be
aoqi@0: * transferred. The class of the object returned is defined by the
aoqi@0: * representation class of the data flavor.
aoqi@0: * aoqi@0: * For DataHandler's created with DataSources or URLs:
aoqi@0: *
aoqi@0: * The DataHandler attempts to locate a DataContentHandler
aoqi@0: * for this MIME type. If one is found, the passed in DataFlavor
aoqi@0: * and the type of the data are passed to its getTransferData
aoqi@0: * method. If the DataHandler fails to locate a DataContentHandler
aoqi@0: * and the flavor specifies this object's MIME type and the
aoqi@0: * java.io.InputStream
class, this object's InputStream
aoqi@0: * is returned.
aoqi@0: * Otherwise it throws an UnsupportedFlavorException.
aoqi@0: * aoqi@0: * For DataHandler's created with Objects:
aoqi@0: *
aoqi@0: * The DataHandler attempts to locate a DataContentHandler
aoqi@0: * for this MIME type. If one is found, the passed in DataFlavor
aoqi@0: * and the type of the data are passed to its getTransferData
aoqi@0: * method. If the DataHandler fails to locate a DataContentHandler
aoqi@0: * and the flavor specifies this object's MIME type and its class,
aoqi@0: * this DataHandler's referenced object is returned.
aoqi@0: * Otherwise it throws an UnsupportedFlavorException.
aoqi@0: *
aoqi@0: * @param flavor the requested flavor for the data
aoqi@0: * @return the object
aoqi@0: * @exception UnsupportedFlavorException if the data could not be
aoqi@0: * converted to the requested flavor
aoqi@0: * @exception IOException if an I/O error occurs
aoqi@0: * @see javax.activation.ActivationDataFlavor
aoqi@0: */
aoqi@0: public Object getTransferData(DataFlavor flavor)
aoqi@0: throws UnsupportedFlavorException, IOException {
aoqi@0: return getDataContentHandler().getTransferData(flavor, dataSource);
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Set the CommandMap for use by this DataHandler.
aoqi@0: * Setting it to null
causes the CommandMap to revert
aoqi@0: * to the CommandMap returned by the
aoqi@0: * CommandMap.getDefaultCommandMap
method.
aoqi@0: * Changing the CommandMap, or setting it to null
,
aoqi@0: * clears out any data cached from the previous CommandMap.
aoqi@0: *
aoqi@0: * @param commandMap the CommandMap to use in this DataHandler
aoqi@0: *
aoqi@0: * @see javax.activation.CommandMap#setDefaultCommandMap
aoqi@0: */
aoqi@0: public synchronized void setCommandMap(CommandMap commandMap) {
aoqi@0: if (commandMap != currentCommandMap || commandMap == null) {
aoqi@0: // clear cached values...
aoqi@0: transferFlavors = emptyFlavors;
aoqi@0: dataContentHandler = null;
aoqi@0:
aoqi@0: currentCommandMap = commandMap;
aoqi@0: }
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the preferred commands for this type of data.
aoqi@0: * This method calls the getPreferredCommands
method
aoqi@0: * in the CommandMap associated with this instance of DataHandler.
aoqi@0: * This method returns an array that represents a subset of
aoqi@0: * available commands. In cases where multiple commands for the
aoqi@0: * MIME type represented by this DataHandler are present, the
aoqi@0: * installed CommandMap chooses the appropriate commands.
aoqi@0: *
aoqi@0: * @return the CommandInfo objects representing the preferred commands
aoqi@0: *
aoqi@0: * @see javax.activation.CommandMap#getPreferredCommands
aoqi@0: */
aoqi@0: public CommandInfo[] getPreferredCommands() {
aoqi@0: if (dataSource != null)
aoqi@0: return getCommandMap().getPreferredCommands(getBaseType(),
aoqi@0: dataSource);
aoqi@0: else
aoqi@0: return getCommandMap().getPreferredCommands(getBaseType());
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return all the commands for this type of data.
aoqi@0: * This method returns an array containing all commands
aoqi@0: * for the type of data represented by this DataHandler. The
aoqi@0: * MIME type for the underlying data represented by this DataHandler
aoqi@0: * is used to call through to the getAllCommands
method
aoqi@0: * of the CommandMap associated with this DataHandler.
aoqi@0: *
aoqi@0: * @return the CommandInfo objects representing all the commands
aoqi@0: *
aoqi@0: * @see javax.activation.CommandMap#getAllCommands
aoqi@0: */
aoqi@0: public CommandInfo[] getAllCommands() {
aoqi@0: if (dataSource != null)
aoqi@0: return getCommandMap().getAllCommands(getBaseType(), dataSource);
aoqi@0: else
aoqi@0: return getCommandMap().getAllCommands(getBaseType());
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Get the command cmdName. Use the search semantics as
aoqi@0: * defined by the CommandMap installed in this DataHandler. The
aoqi@0: * MIME type for the underlying data represented by this DataHandler
aoqi@0: * is used to call through to the getCommand
method
aoqi@0: * of the CommandMap associated with this DataHandler.
aoqi@0: *
aoqi@0: * @param cmdName the command name
aoqi@0: * @return the CommandInfo corresponding to the command
aoqi@0: *
aoqi@0: * @see javax.activation.CommandMap#getCommand
aoqi@0: */
aoqi@0: public CommandInfo getCommand(String cmdName) {
aoqi@0: if (dataSource != null)
aoqi@0: return getCommandMap().getCommand(getBaseType(), cmdName,
aoqi@0: dataSource);
aoqi@0: else
aoqi@0: return getCommandMap().getCommand(getBaseType(), cmdName);
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the data in its preferred Object form.
aoqi@0: * aoqi@0: * If the DataHandler was instantiated with an object, return aoqi@0: * the object.
aoqi@0: *
aoqi@0: * If the DataHandler was instantiated with a DataSource,
aoqi@0: * this method uses a DataContentHandler to return the content
aoqi@0: * object for the data represented by this DataHandler. If no
aoqi@0: * DataContentHandler
can be found for the
aoqi@0: * the type of this data, the DataHandler returns an
aoqi@0: * InputStream for the data.
aoqi@0: *
aoqi@0: * @return the content.
aoqi@0: * @exception IOException if an IOException occurs during
aoqi@0: * this operation.
aoqi@0: */
aoqi@0: public Object getContent() throws IOException {
aoqi@0: if (object != null)
aoqi@0: return object;
aoqi@0: else
aoqi@0: return getDataContentHandler().getContent(getDataSource());
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * A convenience method that takes a CommandInfo object
aoqi@0: * and instantiates the corresponding command, usually
aoqi@0: * a JavaBean component.
aoqi@0: *
aoqi@0: * This method calls the CommandInfo's getCommandObject
aoqi@0: * method with the ClassLoader
used to load
aoqi@0: * the javax.activation.DataHandler
class itself.
aoqi@0: *
aoqi@0: * @param cmdinfo the CommandInfo corresponding to a command
aoqi@0: * @return the instantiated command object
aoqi@0: */
aoqi@0: public Object getBean(CommandInfo cmdinfo) {
aoqi@0: Object bean = null;
aoqi@0:
aoqi@0: try {
aoqi@0: // make the bean
aoqi@0: ClassLoader cld = null;
aoqi@0: // First try the "application's" class loader.
aoqi@0: cld = SecuritySupport.getContextClassLoader();
aoqi@0: if (cld == null)
aoqi@0: cld = this.getClass().getClassLoader();
aoqi@0: bean = cmdinfo.getCommandObject(this, cld);
aoqi@0: } catch (IOException e) {
aoqi@0: } catch (ClassNotFoundException e) { }
aoqi@0:
aoqi@0: return bean;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Get the DataContentHandler for this DataHandler:
aoqi@0: * aoqi@0: * If a DataContentHandlerFactory is set, use it. aoqi@0: * Otherwise look for an object to serve DCH in the aoqi@0: * following order:
aoqi@0: * aoqi@0: * 1) if a factory is set, use it
aoqi@0: * 2) if a CommandMap is set, use it
aoqi@0: * 3) use the default CommandMap
aoqi@0: * aoqi@0: * In any case, wrap the real DataContentHandler with one of our own aoqi@0: * to handle any missing cases, fill in defaults, and to ensure that aoqi@0: * we always have a non-null DataContentHandler. aoqi@0: * aoqi@0: * @return the requested DataContentHandler aoqi@0: */ aoqi@0: private synchronized DataContentHandler getDataContentHandler() { aoqi@0: aoqi@0: // make sure the factory didn't change aoqi@0: if (factory != oldFactory) { aoqi@0: oldFactory = factory; aoqi@0: factoryDCH = null; aoqi@0: dataContentHandler = null; aoqi@0: transferFlavors = emptyFlavors; aoqi@0: } aoqi@0: aoqi@0: if (dataContentHandler != null) aoqi@0: return dataContentHandler; aoqi@0: aoqi@0: String simpleMT = getBaseType(); aoqi@0: aoqi@0: if (factoryDCH == null && factory != null) aoqi@0: factoryDCH = factory.createDataContentHandler(simpleMT); aoqi@0: aoqi@0: if (factoryDCH != null) aoqi@0: dataContentHandler = factoryDCH; aoqi@0: aoqi@0: if (dataContentHandler == null) { aoqi@0: if (dataSource != null) aoqi@0: dataContentHandler = getCommandMap(). aoqi@0: createDataContentHandler(simpleMT, dataSource); aoqi@0: else aoqi@0: dataContentHandler = getCommandMap(). aoqi@0: createDataContentHandler(simpleMT); aoqi@0: } aoqi@0: aoqi@0: // getDataContentHandler always uses these 'wrapper' handlers aoqi@0: // to make sure it returns SOMETHING meaningful... aoqi@0: if (dataSource != null) aoqi@0: dataContentHandler = new DataSourceDataContentHandler( aoqi@0: dataContentHandler, aoqi@0: dataSource); aoqi@0: else aoqi@0: dataContentHandler = new ObjectDataContentHandler( aoqi@0: dataContentHandler, aoqi@0: object, aoqi@0: objectMimeType); aoqi@0: return dataContentHandler; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Use the MimeType class to extract the MIME type/subtype, aoqi@0: * ignoring the parameters. The type is cached. aoqi@0: */ aoqi@0: private synchronized String getBaseType() { aoqi@0: if (shortType == null) { aoqi@0: String ct = getContentType(); aoqi@0: try { aoqi@0: MimeType mt = new MimeType(ct); aoqi@0: shortType = mt.getBaseType(); aoqi@0: } catch (MimeTypeParseException e) { aoqi@0: shortType = ct; aoqi@0: } aoqi@0: } aoqi@0: return shortType; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Sets the DataContentHandlerFactory. The DataContentHandlerFactory aoqi@0: * is called first to find DataContentHandlers. aoqi@0: * The DataContentHandlerFactory can only be set once. aoqi@0: *
aoqi@0: * If the DataContentHandlerFactory has already been set,
aoqi@0: * this method throws an Error.
aoqi@0: *
aoqi@0: * @param newFactory the DataContentHandlerFactory
aoqi@0: * @exception Error if the factory has already been defined.
aoqi@0: *
aoqi@0: * @see javax.activation.DataContentHandlerFactory
aoqi@0: */
aoqi@0: public static synchronized void setDataContentHandlerFactory(
aoqi@0: DataContentHandlerFactory newFactory) {
aoqi@0: if (factory != null)
aoqi@0: throw new Error("DataContentHandlerFactory already defined");
aoqi@0:
aoqi@0: SecurityManager security = System.getSecurityManager();
aoqi@0: if (security != null) {
aoqi@0: try {
aoqi@0: // if it's ok with the SecurityManager, it's ok with me...
aoqi@0: security.checkSetFactory();
aoqi@0: } catch (SecurityException ex) {
aoqi@0: // otherwise, we also allow it if this code and the
aoqi@0: // factory come from the same class loader (e.g.,
aoqi@0: // the JAF classes were loaded with the applet classes).
aoqi@0: if (DataHandler.class.getClassLoader() !=
aoqi@0: newFactory.getClass().getClassLoader())
aoqi@0: throw ex;
aoqi@0: }
aoqi@0: }
aoqi@0: factory = newFactory;
aoqi@0: }
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * The DataHanderDataSource class implements the
aoqi@0: * DataSource interface when the DataHandler is constructed
aoqi@0: * with an Object and a mimeType string.
aoqi@0: */
aoqi@0: class DataHandlerDataSource implements DataSource {
aoqi@0: DataHandler dataHandler = null;
aoqi@0:
aoqi@0: /**
aoqi@0: * The constructor.
aoqi@0: */
aoqi@0: public DataHandlerDataSource(DataHandler dh) {
aoqi@0: this.dataHandler = dh;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Returns an InputStream
representing this object.
aoqi@0: * @return the InputStream
aoqi@0: */
aoqi@0: public InputStream getInputStream() throws IOException {
aoqi@0: return dataHandler.getInputStream();
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Returns the OutputStream
for this object.
aoqi@0: * @return the OutputStream
aoqi@0: */
aoqi@0: public OutputStream getOutputStream() throws IOException {
aoqi@0: return dataHandler.getOutputStream();
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Returns the MIME type of the data represented by this object.
aoqi@0: * @return the MIME type
aoqi@0: */
aoqi@0: public String getContentType() {
aoqi@0: return dataHandler.getContentType();
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Returns the name of this object.
aoqi@0: * @return the name of this object
aoqi@0: */
aoqi@0: public String getName() {
aoqi@0: return dataHandler.getName(); // what else would it be?
aoqi@0: }
aoqi@0: }
aoqi@0:
aoqi@0: /*
aoqi@0: * DataSourceDataContentHandler
aoqi@0: *
aoqi@0: * This is a private DataContentHandler that wraps the real
aoqi@0: * DataContentHandler in the case where the DataHandler was instantiated
aoqi@0: * with a DataSource.
aoqi@0: */
aoqi@0: class DataSourceDataContentHandler implements DataContentHandler {
aoqi@0: private DataSource ds = null;
aoqi@0: private DataFlavor transferFlavors[] = null;
aoqi@0: private DataContentHandler dch = null;
aoqi@0:
aoqi@0: /**
aoqi@0: * The constructor.
aoqi@0: */
aoqi@0: public DataSourceDataContentHandler(DataContentHandler dch, DataSource ds) {
aoqi@0: this.ds = ds;
aoqi@0: this.dch = dch;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the DataFlavors for this DataContentHandler
.
aoqi@0: * @return the DataFlavors
aoqi@0: */
aoqi@0: public DataFlavor[] getTransferDataFlavors() {
aoqi@0:
aoqi@0: if (transferFlavors == null) {
aoqi@0: if (dch != null) { // is there a dch?
aoqi@0: transferFlavors = dch.getTransferDataFlavors();
aoqi@0: } else {
aoqi@0: transferFlavors = new DataFlavor[1];
aoqi@0: transferFlavors[0] =
aoqi@0: new ActivationDataFlavor(ds.getContentType(),
aoqi@0: ds.getContentType());
aoqi@0: }
aoqi@0: }
aoqi@0: return transferFlavors;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the Transfer Data of type DataFlavor from InputStream.
aoqi@0: * @param df the DataFlavor
aoqi@0: * @param ds the DataSource
aoqi@0: * @return the constructed Object
aoqi@0: */
aoqi@0: public Object getTransferData(DataFlavor df, DataSource ds) throws
aoqi@0: UnsupportedFlavorException, IOException {
aoqi@0:
aoqi@0: if (dch != null)
aoqi@0: return dch.getTransferData(df, ds);
aoqi@0: else if (df.equals(getTransferDataFlavors()[0])) // only have one now
aoqi@0: return ds.getInputStream();
aoqi@0: else
aoqi@0: throw new UnsupportedFlavorException(df);
aoqi@0: }
aoqi@0:
aoqi@0: public Object getContent(DataSource ds) throws IOException {
aoqi@0:
aoqi@0: if (dch != null)
aoqi@0: return dch.getContent(ds);
aoqi@0: else
aoqi@0: return ds.getInputStream();
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Write the object to the output stream.
aoqi@0: */
aoqi@0: public void writeTo(Object obj, String mimeType, OutputStream os)
aoqi@0: throws IOException {
aoqi@0: if (dch != null)
aoqi@0: dch.writeTo(obj, mimeType, os);
aoqi@0: else
aoqi@0: throw new UnsupportedDataTypeException(
aoqi@0: "no DCH for content type " + ds.getContentType());
aoqi@0: }
aoqi@0: }
aoqi@0:
aoqi@0: /*
aoqi@0: * ObjectDataContentHandler
aoqi@0: *
aoqi@0: * This is a private DataContentHandler that wraps the real
aoqi@0: * DataContentHandler in the case where the DataHandler was instantiated
aoqi@0: * with an object.
aoqi@0: */
aoqi@0: class ObjectDataContentHandler implements DataContentHandler {
aoqi@0: private DataFlavor transferFlavors[] = null;
aoqi@0: private Object obj;
aoqi@0: private String mimeType;
aoqi@0: private DataContentHandler dch = null;
aoqi@0:
aoqi@0: /**
aoqi@0: * The constructor.
aoqi@0: */
aoqi@0: public ObjectDataContentHandler(DataContentHandler dch,
aoqi@0: Object obj, String mimeType) {
aoqi@0: this.obj = obj;
aoqi@0: this.mimeType = mimeType;
aoqi@0: this.dch = dch;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the DataContentHandler for this object.
aoqi@0: * Used only by the DataHandler class.
aoqi@0: */
aoqi@0: public DataContentHandler getDCH() {
aoqi@0: return dch;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the DataFlavors for this DataContentHandler
.
aoqi@0: * @return the DataFlavors
aoqi@0: */
aoqi@0: public synchronized DataFlavor[] getTransferDataFlavors() {
aoqi@0: if (transferFlavors == null) {
aoqi@0: if (dch != null) {
aoqi@0: transferFlavors = dch.getTransferDataFlavors();
aoqi@0: } else {
aoqi@0: transferFlavors = new DataFlavor[1];
aoqi@0: transferFlavors[0] = new ActivationDataFlavor(obj.getClass(),
aoqi@0: mimeType, mimeType);
aoqi@0: }
aoqi@0: }
aoqi@0: return transferFlavors;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return the Transfer Data of type DataFlavor from InputStream.
aoqi@0: * @param df the DataFlavor
aoqi@0: * @param ds the DataSource
aoqi@0: * @return the constructed Object
aoqi@0: */
aoqi@0: public Object getTransferData(DataFlavor df, DataSource ds)
aoqi@0: throws UnsupportedFlavorException, IOException {
aoqi@0:
aoqi@0: if (dch != null)
aoqi@0: return dch.getTransferData(df, ds);
aoqi@0: else if (df.equals(getTransferDataFlavors()[0])) // only have one now
aoqi@0: return obj;
aoqi@0: else
aoqi@0: throw new UnsupportedFlavorException(df);
aoqi@0:
aoqi@0: }
aoqi@0:
aoqi@0: public Object getContent(DataSource ds) {
aoqi@0: return obj;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Write the object to the output stream.
aoqi@0: */
aoqi@0: public void writeTo(Object obj, String mimeType, OutputStream os)
aoqi@0: throws IOException {
aoqi@0: if (dch != null)
aoqi@0: dch.writeTo(obj, mimeType, os);
aoqi@0: else if (obj instanceof byte[])
aoqi@0: os.write((byte[])obj);
aoqi@0: else if (obj instanceof String) {
aoqi@0: OutputStreamWriter osw = new OutputStreamWriter(os);
aoqi@0: osw.write((String)obj);
aoqi@0: osw.flush();
aoqi@0: } else throw new UnsupportedDataTypeException(
aoqi@0: "no object DCH for MIME type " + this.mimeType);
aoqi@0: }
aoqi@0: }