| /* DataHandler.java -- Handler for data available in multiple formats. | |
| Copyright (C) 2004 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath 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 for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package javax.activation; | |
| import java.awt.datatransfer.DataFlavor; | |
| import java.awt.datatransfer.Transferable; | |
| import java.awt.datatransfer.UnsupportedFlavorException; | |
| import java.io.InputStream; | |
| import java.io.IOException; | |
| import java.io.OutputStream; | |
| import java.io.PipedInputStream; | |
| import java.io.PipedOutputStream; | |
| import java.net.URL; | |
| /** | |
| * Handler for data available in multiple sources and formats. | |
| * | |
| * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> | |
| * @version 1.1 | |
| */ | |
| public class DataHandler | |
| implements Transferable | |
| { | |
| private static final DataFlavor[] NO_FLAVORS = new DataFlavor[0]; | |
| private static DataContentHandlerFactory factory = null; | |
| private final DataSource dataSource; | |
| private DataSource objDataSource; | |
| private Object object; | |
| private String objectMimeType; | |
| private CommandMap currentCommandMap; | |
| private DataFlavor[] transferFlavors = NO_FLAVORS; | |
| private DataContentHandler dataContentHandler; | |
| private DataContentHandler factoryDCH; | |
| private DataContentHandlerFactory oldFactory; | |
| private String shortType; | |
| /** | |
| * Constructor in which the data is read from a data source. | |
| * @param ds the data source | |
| */ | |
| public DataHandler(DataSource ds) | |
| { | |
| dataSource = ds; | |
| oldFactory = factory; | |
| } | |
| /** | |
| * Constructor using a reified object representation. | |
| * @param obj the object representation of the data | |
| * @param mimeType the MIME type of the object | |
| */ | |
| public DataHandler(Object obj, String mimeType) | |
| { | |
| dataSource = null; | |
| object = obj; | |
| objectMimeType = mimeType; | |
| oldFactory = factory; | |
| } | |
| /** | |
| * Constructor in which the data is read from a URL. | |
| * @param url the URL | |
| */ | |
| public DataHandler(URL url) | |
| { | |
| dataSource = new URLDataSource(url); | |
| oldFactory = factory; | |
| } | |
| /** | |
| * Returns the data source from which data is read. | |
| */ | |
| public DataSource getDataSource() | |
| { | |
| if (dataSource != null) | |
| { | |
| return dataSource; | |
| } | |
| if (objDataSource == null) | |
| { | |
| objDataSource = new DataHandlerDataSource(this); | |
| } | |
| return objDataSource; | |
| } | |
| /** | |
| * Returns the name of the data object if created with a DataSource. | |
| */ | |
| public String getName() | |
| { | |
| if (dataSource != null) | |
| { | |
| return dataSource.getName(); | |
| } | |
| return null; | |
| } | |
| /** | |
| * Returns the MIME type of the data (with parameters). | |
| */ | |
| public String getContentType() | |
| { | |
| if (dataSource != null) | |
| { | |
| return dataSource.getContentType(); | |
| } | |
| return objectMimeType; | |
| } | |
| /** | |
| * Returns an input stream from which the data can be read. | |
| */ | |
| public InputStream getInputStream() | |
| throws IOException | |
| { | |
| if (dataSource != null) | |
| { | |
| return dataSource.getInputStream(); | |
| } | |
| DataContentHandler dch = getDataContentHandler(); | |
| if (dch == null) | |
| { | |
| throw new UnsupportedDataTypeException("no DCH for MIME type " + | |
| getShortType()); | |
| } | |
| if ((dch instanceof ObjectDataContentHandler) && | |
| ((ObjectDataContentHandler)dch).getDCH() == null) | |
| { | |
| throw new UnsupportedDataTypeException("no object DCH " + | |
| "for MIME type " + | |
| getShortType()); | |
| } | |
| PipedOutputStream pos = new PipedOutputStream(); | |
| DataContentHandlerWriter dchw = | |
| new DataContentHandlerWriter(dch, object, objectMimeType, pos); | |
| Thread thread = new Thread(dchw, "DataHandler.getInputStream"); | |
| thread.start(); | |
| return new PipedInputStream(pos); | |
| } | |
| static class DataContentHandlerWriter | |
| implements Runnable | |
| { | |
| DataContentHandler dch; | |
| Object object; | |
| String mimeType; | |
| OutputStream out; | |
| DataContentHandlerWriter(DataContentHandler dch, Object object, | |
| String mimeType, OutputStream out) | |
| { | |
| this.dch = dch; | |
| this.object = object; | |
| this.mimeType = mimeType; | |
| this.out = out; | |
| } | |
| public void run() | |
| { | |
| try | |
| { | |
| dch.writeTo(object, mimeType, out); | |
| } | |
| catch(IOException e) | |
| { | |
| } | |
| finally | |
| { | |
| try | |
| { | |
| out.close(); | |
| } | |
| catch(IOException e) | |
| { | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * Writes the data as a byte stream. | |
| * @param os the stream to write to | |
| */ | |
| public void writeTo(OutputStream os) | |
| throws IOException | |
| { | |
| if (dataSource != null) | |
| { | |
| InputStream in = dataSource.getInputStream(); | |
| byte[] buf = new byte[8192]; | |
| for (int len = in.read(buf); len != -1; len = in.read(buf)) | |
| { | |
| os.write(buf, 0, len); | |
| } | |
| in.close(); | |
| } | |
| else | |
| { | |
| DataContentHandler dch = getDataContentHandler(); | |
| dch.writeTo(object, objectMimeType, os); | |
| } | |
| } | |
| /** | |
| * Returns an output stream that can be used to overwrite the underlying | |
| * data, if the DataSource constructor was used. | |
| */ | |
| public OutputStream getOutputStream() | |
| throws IOException | |
| { | |
| if (dataSource != null) | |
| { | |
| return dataSource.getOutputStream(); | |
| } | |
| return null; | |
| } | |
| /** | |
| * Returns the data flavors in which this data is available. | |
| */ | |
| public synchronized DataFlavor[] getTransferDataFlavors() | |
| { | |
| if (factory != oldFactory || transferFlavors == NO_FLAVORS) | |
| { | |
| DataContentHandler dch = getDataContentHandler(); | |
| transferFlavors = dch.getTransferDataFlavors(); | |
| } | |
| return transferFlavors; | |
| } | |
| /** | |
| * Indicates whether the specified data flavor is supported for this | |
| * data. | |
| */ | |
| public boolean isDataFlavorSupported(DataFlavor flavor) | |
| { | |
| DataFlavor[] flavors = getTransferDataFlavors(); | |
| for (int i = 0; i < flavors.length; i++) | |
| { | |
| if (flavors[i].equals(flavor)) | |
| { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| /** | |
| * Returns an object representing the data to be transferred. | |
| * @param flavor the requested data flavor | |
| */ | |
| public Object getTransferData(DataFlavor flavor) | |
| throws UnsupportedFlavorException, IOException | |
| { | |
| DataContentHandler dch = getDataContentHandler(); | |
| return dch.getTransferData(flavor, dataSource); | |
| } | |
| /** | |
| * Sets the command map to be used by this data handler. | |
| * Setting to null uses the default command map. | |
| * @param commandMap the command map to use | |
| */ | |
| public synchronized void setCommandMap(CommandMap commandMap) | |
| { | |
| if (commandMap != currentCommandMap || commandMap == null) | |
| { | |
| transferFlavors = NO_FLAVORS; | |
| dataContentHandler = null; | |
| currentCommandMap = commandMap; | |
| } | |
| } | |
| /** | |
| * Returns the preferred commands for this type of data. | |
| */ | |
| public CommandInfo[] getPreferredCommands() | |
| { | |
| CommandMap commandMap = getCommandMap(); | |
| return commandMap.getPreferredCommands(getShortType()); | |
| } | |
| /** | |
| * Returns the complete list of commands for this type of data. | |
| */ | |
| public CommandInfo[] getAllCommands() | |
| { | |
| CommandMap commandMap = getCommandMap(); | |
| return commandMap.getAllCommands(getShortType()); | |
| } | |
| /** | |
| * Returns the specified command. | |
| * @param cmdName the command name | |
| */ | |
| public CommandInfo getCommand(String cmdName) | |
| { | |
| CommandMap commandMap = getCommandMap(); | |
| return commandMap.getCommand(getShortType(), cmdName); | |
| } | |
| /** | |
| * Returns the data as a reified object. | |
| */ | |
| public Object getContent() | |
| throws IOException | |
| { | |
| DataContentHandler dch = getDataContentHandler(); | |
| return dch.getContent(getDataSource()); | |
| } | |
| /** | |
| * Returns the instantiated bean using the specified command. | |
| * @param cmdInfo the command to instantiate the bean with | |
| */ | |
| public Object getBean(CommandInfo cmdInfo) | |
| { | |
| try | |
| { | |
| return cmdInfo.getCommandObject(this, getClass().getClassLoader()); | |
| } | |
| catch (IOException e) | |
| { | |
| e.printStackTrace(System.err); | |
| return null; | |
| } | |
| catch (ClassNotFoundException e) | |
| { | |
| e.printStackTrace(System.err); | |
| return null; | |
| } | |
| } | |
| /** | |
| * Sets the data content handler factory. | |
| * If the factory has already been set, throws an Error. | |
| * @param newFactory the factory to set | |
| */ | |
| public static synchronized void | |
| setDataContentHandlerFactory(DataContentHandlerFactory newFactory) | |
| { | |
| if (factory != null) | |
| { | |
| throw new Error("DataContentHandlerFactory already defined"); | |
| } | |
| SecurityManager security = System.getSecurityManager(); | |
| if (security != null) | |
| { | |
| try | |
| { | |
| security.checkSetFactory(); | |
| } | |
| catch (SecurityException e) | |
| { | |
| if (newFactory != null && DataHandler.class.getClassLoader() | |
| != newFactory.getClass().getClassLoader()) | |
| { | |
| throw e; | |
| } | |
| } | |
| } | |
| factory = newFactory; | |
| } | |
| /* | |
| * Returns just the base part of the data's content-type, with no | |
| * parameters. | |
| */ | |
| private synchronized String getShortType() | |
| { | |
| if (shortType == null) | |
| { | |
| String contentType = getContentType(); | |
| try | |
| { | |
| MimeType mimeType = new MimeType(contentType); | |
| shortType = mimeType.getBaseType(); | |
| } | |
| catch (MimeTypeParseException e) | |
| { | |
| shortType = contentType; | |
| } | |
| } | |
| return shortType; | |
| } | |
| /* | |
| * Returns the command map for this handler. | |
| */ | |
| private synchronized CommandMap getCommandMap() | |
| { | |
| if (currentCommandMap != null) | |
| { | |
| return currentCommandMap; | |
| } | |
| return CommandMap.getDefaultCommandMap(); | |
| } | |
| /* | |
| * Returns the DCH for this handler. | |
| */ | |
| private synchronized DataContentHandler getDataContentHandler() | |
| { | |
| if (factory != oldFactory) | |
| { | |
| oldFactory = factory; | |
| factoryDCH = null; | |
| dataContentHandler = null; | |
| transferFlavors = NO_FLAVORS; | |
| } | |
| if (dataContentHandler != null) | |
| { | |
| return dataContentHandler; | |
| } | |
| String mimeType = getShortType(); | |
| if (factoryDCH == null && factory != null) | |
| { | |
| factoryDCH = factory.createDataContentHandler(mimeType); | |
| } | |
| if (factoryDCH != null) | |
| { | |
| dataContentHandler = factoryDCH; | |
| } | |
| if (dataContentHandler == null) | |
| { | |
| CommandMap commandMap = getCommandMap(); | |
| dataContentHandler = commandMap.createDataContentHandler(mimeType); | |
| } | |
| if (dataSource != null) | |
| { | |
| dataContentHandler = | |
| new DataSourceDataContentHandler(dataContentHandler, dataSource); | |
| } | |
| else | |
| { | |
| dataContentHandler = | |
| new ObjectDataContentHandler(dataContentHandler, object, | |
| objectMimeType); | |
| } | |
| return dataContentHandler; | |
| } | |
| } |