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: }