Path: blob/aarch64-shenandoah-jdk8u272-b10/jaxws/src/share/jaf_classes/javax/activation/DataHandler.java
38877 views
/*1* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.activation;2627import java.io.InputStream;28import java.io.IOException;29import java.io.OutputStream;30import java.io.PipedInputStream;31import java.io.PipedOutputStream;32import java.io.OutputStreamWriter;33import java.net.URL;34import java.awt.datatransfer.Transferable;35import java.awt.datatransfer.DataFlavor;36import java.awt.datatransfer.UnsupportedFlavorException;3738/**39* The DataHandler class provides a consistent interface to data40* available in many different sources and formats.41* It manages simple stream to string conversions and related operations42* using DataContentHandlers.43* It provides access to commands that can operate on the data.44* The commands are found using a CommandMap. <p>45*46* <b>DataHandler and the Transferable Interface</b><p>47* DataHandler implements the Transferable interface so that data can48* be used in AWT data transfer operations, such as cut and paste and49* drag and drop. The implementation of the Transferable interface50* relies on the availability of an installed DataContentHandler51* object corresponding to the MIME type of the data represented in52* the specific instance of the DataHandler.<p>53*54* <b>DataHandler and CommandMaps</b><p>55* The DataHandler keeps track of the current CommandMap that it uses to56* service requests for commands (<code>getCommand</code>,57* <code>getAllCommands</code>, <code>getPreferredCommands</code>).58* Each instance of a DataHandler may have a CommandMap associated with59* it using the <code>setCommandMap</code> method. If a CommandMap was60* not set, DataHandler calls the <code>getDefaultCommandMap</code>61* method in CommandMap and uses the value it returns. See62* <i>CommandMap</i> for more information. <p>63*64* <b>DataHandler and URLs</b><p>65* The current DataHandler implementation creates a private66* instance of URLDataSource when it is constructed with a URL.67*68* @see javax.activation.CommandMap69* @see javax.activation.DataContentHandler70* @see javax.activation.DataSource71* @see javax.activation.URLDataSource72*73* @since 1.674*/7576public class DataHandler implements Transferable {7778// Use the datasource to indicate whether we were started via the79// DataSource constructor or the object constructor.80private DataSource dataSource = null;81private DataSource objDataSource = null;8283// The Object and mimetype from the constructor (if passed in).84// object remains null if it was instantiated with a85// DataSource.86private Object object = null;87private String objectMimeType = null;8889// Keep track of the CommandMap90private CommandMap currentCommandMap = null;9192// our transfer flavors93private static final DataFlavor emptyFlavors[] = new DataFlavor[0];94private DataFlavor transferFlavors[] = emptyFlavors;9596// our DataContentHandler97private DataContentHandler dataContentHandler = null;98private DataContentHandler factoryDCH = null;99100// our DataContentHandlerFactory101private static DataContentHandlerFactory factory = null;102private DataContentHandlerFactory oldFactory = null;103// the short representation of the ContentType (sans params)104private String shortType = null;105106/**107* Create a <code>DataHandler</code> instance referencing the108* specified DataSource. The data exists in a byte stream form.109* The DataSource will provide an InputStream to access the data.110*111* @param ds the DataSource112*/113public DataHandler(DataSource ds) {114// save a reference to the incoming DS115dataSource = ds;116oldFactory = factory; // keep track of the factory117}118119/**120* Create a <code>DataHandler</code> instance representing an object121* of this MIME type. This constructor is122* used when the application already has an in-memory representation123* of the data in the form of a Java Object.124*125* @param obj the Java Object126* @param mimeType the MIME type of the object127*/128public DataHandler(Object obj, String mimeType) {129object = obj;130objectMimeType = mimeType;131oldFactory = factory; // keep track of the factory132}133134/**135* Create a <code>DataHandler</code> instance referencing a URL.136* The DataHandler internally creates a <code>URLDataSource</code>137* instance to represent the URL.138*139* @param url a URL object140*/141public DataHandler(URL url) {142dataSource = new URLDataSource(url);143oldFactory = factory; // keep track of the factory144}145146/**147* Return the CommandMap for this instance of DataHandler.148*/149private synchronized CommandMap getCommandMap() {150if (currentCommandMap != null)151return currentCommandMap;152else153return CommandMap.getDefaultCommandMap();154}155156/**157* Return the DataSource associated with this instance158* of DataHandler.159* <p>160* For DataHandlers that have been instantiated with a DataSource,161* this method returns the DataSource that was used to create the162* DataHandler object. In other cases the DataHandler163* constructs a DataSource from the data used to construct164* the DataHandler. DataSources created for DataHandlers <b>not</b>165* instantiated with a DataSource are cached for performance166* reasons.167*168* @return a valid DataSource object for this DataHandler169*/170public DataSource getDataSource() {171if (dataSource == null) {172// create one on the fly173if (objDataSource == null)174objDataSource = new DataHandlerDataSource(this);175return objDataSource;176}177return dataSource;178}179180/**181* Return the name of the data object. If this DataHandler182* was created with a DataSource, this method calls through183* to the <code>DataSource.getName</code> method, otherwise it184* returns <i>null</i>.185*186* @return the name of the object187*/188public String getName() {189if (dataSource != null)190return dataSource.getName();191else192return null;193}194195/**196* Return the MIME type of this object as retrieved from197* the source object. Note that this is the <i>full</i>198* type with parameters.199*200* @return the MIME type201*/202public String getContentType() {203if (dataSource != null) // data source case204return dataSource.getContentType();205else206return objectMimeType; // obj/type case207}208209/**210* Get the InputStream for this object. <p>211*212* For DataHandlers instantiated with a DataSource, the DataHandler213* calls the <code>DataSource.getInputStream</code> method and214* returns the result to the caller.215* <p>216* For DataHandlers instantiated with an Object, the DataHandler217* first attempts to find a DataContentHandler for the Object. If218* the DataHandler can not find a DataContentHandler for this MIME219* type, it throws an UnsupportedDataTypeException. If it is220* successful, it creates a pipe and a thread. The thread uses the221* DataContentHandler's <code>writeTo</code> method to write the222* stream data into one end of the pipe. The other end of the pipe223* is returned to the caller. Because a thread is created to copy224* the data, IOExceptions that may occur during the copy can not be225* propagated back to the caller. The result is an empty stream.<p>226*227* @return the InputStream representing this data228* @exception IOException if an I/O error occurs229*230* @see javax.activation.DataContentHandler#writeTo231* @see javax.activation.UnsupportedDataTypeException232*/233public InputStream getInputStream() throws IOException {234InputStream ins = null;235236if (dataSource != null) {237ins = dataSource.getInputStream();238} else {239DataContentHandler dch = getDataContentHandler();240// we won't even try if we can't get a dch241if (dch == null)242throw new UnsupportedDataTypeException(243"no DCH for MIME type " + getBaseType());244245if (dch instanceof ObjectDataContentHandler) {246if (((ObjectDataContentHandler)dch).getDCH() == null)247throw new UnsupportedDataTypeException(248"no object DCH for MIME type " + getBaseType());249}250// there is none but the default^^^^^^^^^^^^^^^^251final DataContentHandler fdch = dch;252253// from bill s.254// ce n'est pas une pipe!255//256// NOTE: This block of code needs to throw exceptions, but257// can't because it is in another thread!!! ARG!258//259final PipedOutputStream pos = new PipedOutputStream();260PipedInputStream pin = new PipedInputStream(pos);261new Thread(262new Runnable() {263public void run() {264try {265fdch.writeTo(object, objectMimeType, pos);266} catch (IOException e) {267268} finally {269try {270pos.close();271} catch (IOException ie) { }272}273}274},275"DataHandler.getInputStream").start();276ins = pin;277}278279return ins;280}281282/**283* Write the data to an <code>OutputStream</code>.<p>284*285* If the DataHandler was created with a DataSource, writeTo286* retrieves the InputStream and copies the bytes from the287* InputStream to the OutputStream passed in.288* <p>289* If the DataHandler was created with an object, writeTo290* retrieves the DataContentHandler for the object's type.291* If the DataContentHandler was found, it calls the292* <code>writeTo</code> method on the <code>DataContentHandler</code>.293*294* @param os the OutputStream to write to295* @exception IOException if an I/O error occurs296*/297public void writeTo(OutputStream os) throws IOException {298// for the DataSource case299if (dataSource != null) {300InputStream is = null;301byte data[] = new byte[8*1024];302int bytes_read;303304is = dataSource.getInputStream();305306try {307while ((bytes_read = is.read(data)) > 0) {308os.write(data, 0, bytes_read);309}310} finally {311is.close();312is = null;313}314} else { // for the Object case315DataContentHandler dch = getDataContentHandler();316dch.writeTo(object, objectMimeType, os);317}318}319320/**321* Get an OutputStream for this DataHandler to allow overwriting322* the underlying data.323* If the DataHandler was created with a DataSource, the324* DataSource's <code>getOutputStream</code> method is called.325* Otherwise, <code>null</code> is returned.326*327* @return the OutputStream328*329* @see javax.activation.DataSource#getOutputStream330* @see javax.activation.URLDataSource331*/332public OutputStream getOutputStream() throws IOException {333if (dataSource != null)334return dataSource.getOutputStream();335else336return null;337}338339/**340* Return the DataFlavors in which this data is available. <p>341*342* Returns an array of DataFlavor objects indicating the flavors343* the data can be provided in. The array is usually ordered344* according to preference for providing the data, from most345* richly descriptive to least richly descriptive.<p>346*347* The DataHandler attempts to find a DataContentHandler that348* corresponds to the MIME type of the data. If one is located,349* the DataHandler calls the DataContentHandler's350* <code>getTransferDataFlavors</code> method. <p>351*352* If a DataContentHandler can <i>not</i> be located, and if the353* DataHandler was created with a DataSource (or URL), one354* DataFlavor is returned that represents this object's MIME type355* and the <code>java.io.InputStream</code> class. If the356* DataHandler was created with an object and a MIME type,357* getTransferDataFlavors returns one DataFlavor that represents358* this object's MIME type and the object's class.359*360* @return an array of data flavors in which this data can be transferred361* @see javax.activation.DataContentHandler#getTransferDataFlavors362*/363public synchronized DataFlavor[] getTransferDataFlavors() {364if (factory != oldFactory) // if the factory has changed, clear cache365transferFlavors = emptyFlavors;366367// if it's not set, set it...368if (transferFlavors == emptyFlavors)369transferFlavors = getDataContentHandler().getTransferDataFlavors();370371if (transferFlavors == emptyFlavors)372return transferFlavors;373else374return transferFlavors.clone();375376}377378/**379* Returns whether the specified data flavor is supported380* for this object.<p>381*382* This method iterates through the DataFlavors returned from383* <code>getTransferDataFlavors</code>, comparing each with384* the specified flavor.385*386* @param flavor the requested flavor for the data387* @return true if the data flavor is supported388* @see javax.activation.DataHandler#getTransferDataFlavors389*/390public boolean isDataFlavorSupported(DataFlavor flavor) {391DataFlavor[] lFlavors = getTransferDataFlavors();392393for (int i = 0; i < lFlavors.length; i++) {394if (lFlavors[i].equals(flavor))395return true;396}397return false;398}399400/**401* Returns an object that represents the data to be402* transferred. The class of the object returned is defined by the403* representation class of the data flavor.<p>404*405* <b>For DataHandler's created with DataSources or URLs:</b><p>406*407* The DataHandler attempts to locate a DataContentHandler408* for this MIME type. If one is found, the passed in DataFlavor409* and the type of the data are passed to its <code>getTransferData</code>410* method. If the DataHandler fails to locate a DataContentHandler411* and the flavor specifies this object's MIME type and the412* <code>java.io.InputStream</code> class, this object's InputStream413* is returned.414* Otherwise it throws an UnsupportedFlavorException. <p>415*416* <b>For DataHandler's created with Objects:</b><p>417*418* The DataHandler attempts to locate a DataContentHandler419* for this MIME type. If one is found, the passed in DataFlavor420* and the type of the data are passed to its getTransferData421* method. If the DataHandler fails to locate a DataContentHandler422* and the flavor specifies this object's MIME type and its class,423* this DataHandler's referenced object is returned.424* Otherwise it throws an UnsupportedFlavorException.425*426* @param flavor the requested flavor for the data427* @return the object428* @exception UnsupportedFlavorException if the data could not be429* converted to the requested flavor430* @exception IOException if an I/O error occurs431* @see javax.activation.ActivationDataFlavor432*/433public Object getTransferData(DataFlavor flavor)434throws UnsupportedFlavorException, IOException {435return getDataContentHandler().getTransferData(flavor, dataSource);436}437438/**439* Set the CommandMap for use by this DataHandler.440* Setting it to <code>null</code> causes the CommandMap to revert441* to the CommandMap returned by the442* <code>CommandMap.getDefaultCommandMap</code> method.443* Changing the CommandMap, or setting it to <code>null</code>,444* clears out any data cached from the previous CommandMap.445*446* @param commandMap the CommandMap to use in this DataHandler447*448* @see javax.activation.CommandMap#setDefaultCommandMap449*/450public synchronized void setCommandMap(CommandMap commandMap) {451if (commandMap != currentCommandMap || commandMap == null) {452// clear cached values...453transferFlavors = emptyFlavors;454dataContentHandler = null;455456currentCommandMap = commandMap;457}458}459460/**461* Return the <i>preferred</i> commands for this type of data.462* This method calls the <code>getPreferredCommands</code> method463* in the CommandMap associated with this instance of DataHandler.464* This method returns an array that represents a subset of465* available commands. In cases where multiple commands for the466* MIME type represented by this DataHandler are present, the467* installed CommandMap chooses the appropriate commands.468*469* @return the CommandInfo objects representing the preferred commands470*471* @see javax.activation.CommandMap#getPreferredCommands472*/473public CommandInfo[] getPreferredCommands() {474if (dataSource != null)475return getCommandMap().getPreferredCommands(getBaseType(),476dataSource);477else478return getCommandMap().getPreferredCommands(getBaseType());479}480481/**482* Return all the commands for this type of data.483* This method returns an array containing all commands484* for the type of data represented by this DataHandler. The485* MIME type for the underlying data represented by this DataHandler486* is used to call through to the <code>getAllCommands</code> method487* of the CommandMap associated with this DataHandler.488*489* @return the CommandInfo objects representing all the commands490*491* @see javax.activation.CommandMap#getAllCommands492*/493public CommandInfo[] getAllCommands() {494if (dataSource != null)495return getCommandMap().getAllCommands(getBaseType(), dataSource);496else497return getCommandMap().getAllCommands(getBaseType());498}499500/**501* Get the command <i>cmdName</i>. Use the search semantics as502* defined by the CommandMap installed in this DataHandler. The503* MIME type for the underlying data represented by this DataHandler504* is used to call through to the <code>getCommand</code> method505* of the CommandMap associated with this DataHandler.506*507* @param cmdName the command name508* @return the CommandInfo corresponding to the command509*510* @see javax.activation.CommandMap#getCommand511*/512public CommandInfo getCommand(String cmdName) {513if (dataSource != null)514return getCommandMap().getCommand(getBaseType(), cmdName,515dataSource);516else517return getCommandMap().getCommand(getBaseType(), cmdName);518}519520/**521* Return the data in its preferred Object form. <p>522*523* If the DataHandler was instantiated with an object, return524* the object. <p>525*526* If the DataHandler was instantiated with a DataSource,527* this method uses a DataContentHandler to return the content528* object for the data represented by this DataHandler. If no529* <code>DataContentHandler</code> can be found for the530* the type of this data, the DataHandler returns an531* InputStream for the data.532*533* @return the content.534* @exception IOException if an IOException occurs during535* this operation.536*/537public Object getContent() throws IOException {538if (object != null)539return object;540else541return getDataContentHandler().getContent(getDataSource());542}543544/**545* A convenience method that takes a CommandInfo object546* and instantiates the corresponding command, usually547* a JavaBean component.548* <p>549* This method calls the CommandInfo's <code>getCommandObject</code>550* method with the <code>ClassLoader</code> used to load551* the <code>javax.activation.DataHandler</code> class itself.552*553* @param cmdinfo the CommandInfo corresponding to a command554* @return the instantiated command object555*/556public Object getBean(CommandInfo cmdinfo) {557Object bean = null;558559try {560// make the bean561ClassLoader cld = null;562// First try the "application's" class loader.563cld = SecuritySupport.getContextClassLoader();564if (cld == null)565cld = this.getClass().getClassLoader();566bean = cmdinfo.getCommandObject(this, cld);567} catch (IOException e) {568} catch (ClassNotFoundException e) { }569570return bean;571}572573/**574* Get the DataContentHandler for this DataHandler: <p>575*576* If a DataContentHandlerFactory is set, use it.577* Otherwise look for an object to serve DCH in the578* following order: <p>579*580* 1) if a factory is set, use it <p>581* 2) if a CommandMap is set, use it <p>582* 3) use the default CommandMap <p>583*584* In any case, wrap the real DataContentHandler with one of our own585* to handle any missing cases, fill in defaults, and to ensure that586* we always have a non-null DataContentHandler.587*588* @return the requested DataContentHandler589*/590private synchronized DataContentHandler getDataContentHandler() {591592// make sure the factory didn't change593if (factory != oldFactory) {594oldFactory = factory;595factoryDCH = null;596dataContentHandler = null;597transferFlavors = emptyFlavors;598}599600if (dataContentHandler != null)601return dataContentHandler;602603String simpleMT = getBaseType();604605if (factoryDCH == null && factory != null)606factoryDCH = factory.createDataContentHandler(simpleMT);607608if (factoryDCH != null)609dataContentHandler = factoryDCH;610611if (dataContentHandler == null) {612if (dataSource != null)613dataContentHandler = getCommandMap().614createDataContentHandler(simpleMT, dataSource);615else616dataContentHandler = getCommandMap().617createDataContentHandler(simpleMT);618}619620// getDataContentHandler always uses these 'wrapper' handlers621// to make sure it returns SOMETHING meaningful...622if (dataSource != null)623dataContentHandler = new DataSourceDataContentHandler(624dataContentHandler,625dataSource);626else627dataContentHandler = new ObjectDataContentHandler(628dataContentHandler,629object,630objectMimeType);631return dataContentHandler;632}633634/**635* Use the MimeType class to extract the MIME type/subtype,636* ignoring the parameters. The type is cached.637*/638private synchronized String getBaseType() {639if (shortType == null) {640String ct = getContentType();641try {642MimeType mt = new MimeType(ct);643shortType = mt.getBaseType();644} catch (MimeTypeParseException e) {645shortType = ct;646}647}648return shortType;649}650651/**652* Sets the DataContentHandlerFactory. The DataContentHandlerFactory653* is called first to find DataContentHandlers.654* The DataContentHandlerFactory can only be set once.655* <p>656* If the DataContentHandlerFactory has already been set,657* this method throws an Error.658*659* @param newFactory the DataContentHandlerFactory660* @exception Error if the factory has already been defined.661*662* @see javax.activation.DataContentHandlerFactory663*/664public static synchronized void setDataContentHandlerFactory(665DataContentHandlerFactory newFactory) {666if (factory != null)667throw new Error("DataContentHandlerFactory already defined");668669SecurityManager security = System.getSecurityManager();670if (security != null) {671try {672// if it's ok with the SecurityManager, it's ok with me...673security.checkSetFactory();674} catch (SecurityException ex) {675// otherwise, we also allow it if this code and the676// factory come from the same class loader (e.g.,677// the JAF classes were loaded with the applet classes).678if (DataHandler.class.getClassLoader() !=679newFactory.getClass().getClassLoader())680throw ex;681}682}683factory = newFactory;684}685}686687/**688* The DataHanderDataSource class implements the689* DataSource interface when the DataHandler is constructed690* with an Object and a mimeType string.691*/692class DataHandlerDataSource implements DataSource {693DataHandler dataHandler = null;694695/**696* The constructor.697*/698public DataHandlerDataSource(DataHandler dh) {699this.dataHandler = dh;700}701702/**703* Returns an <code>InputStream</code> representing this object.704* @return the <code>InputStream</code>705*/706public InputStream getInputStream() throws IOException {707return dataHandler.getInputStream();708}709710/**711* Returns the <code>OutputStream</code> for this object.712* @return the <code>OutputStream</code>713*/714public OutputStream getOutputStream() throws IOException {715return dataHandler.getOutputStream();716}717718/**719* Returns the MIME type of the data represented by this object.720* @return the MIME type721*/722public String getContentType() {723return dataHandler.getContentType();724}725726/**727* Returns the name of this object.728* @return the name of this object729*/730public String getName() {731return dataHandler.getName(); // what else would it be?732}733}734735/*736* DataSourceDataContentHandler737*738* This is a <i>private</i> DataContentHandler that wraps the real739* DataContentHandler in the case where the DataHandler was instantiated740* with a DataSource.741*/742class DataSourceDataContentHandler implements DataContentHandler {743private DataSource ds = null;744private DataFlavor transferFlavors[] = null;745private DataContentHandler dch = null;746747/**748* The constructor.749*/750public DataSourceDataContentHandler(DataContentHandler dch, DataSource ds) {751this.ds = ds;752this.dch = dch;753}754755/**756* Return the DataFlavors for this <code>DataContentHandler</code>.757* @return the DataFlavors758*/759public DataFlavor[] getTransferDataFlavors() {760761if (transferFlavors == null) {762if (dch != null) { // is there a dch?763transferFlavors = dch.getTransferDataFlavors();764} else {765transferFlavors = new DataFlavor[1];766transferFlavors[0] =767new ActivationDataFlavor(ds.getContentType(),768ds.getContentType());769}770}771return transferFlavors;772}773774/**775* Return the Transfer Data of type DataFlavor from InputStream.776* @param df the DataFlavor777* @param ds the DataSource778* @return the constructed Object779*/780public Object getTransferData(DataFlavor df, DataSource ds) throws781UnsupportedFlavorException, IOException {782783if (dch != null)784return dch.getTransferData(df, ds);785else if (df.equals(getTransferDataFlavors()[0])) // only have one now786return ds.getInputStream();787else788throw new UnsupportedFlavorException(df);789}790791public Object getContent(DataSource ds) throws IOException {792793if (dch != null)794return dch.getContent(ds);795else796return ds.getInputStream();797}798799/**800* Write the object to the output stream.801*/802public void writeTo(Object obj, String mimeType, OutputStream os)803throws IOException {804if (dch != null)805dch.writeTo(obj, mimeType, os);806else807throw new UnsupportedDataTypeException(808"no DCH for content type " + ds.getContentType());809}810}811812/*813* ObjectDataContentHandler814*815* This is a <i>private</i> DataContentHandler that wraps the real816* DataContentHandler in the case where the DataHandler was instantiated817* with an object.818*/819class ObjectDataContentHandler implements DataContentHandler {820private DataFlavor transferFlavors[] = null;821private Object obj;822private String mimeType;823private DataContentHandler dch = null;824825/**826* The constructor.827*/828public ObjectDataContentHandler(DataContentHandler dch,829Object obj, String mimeType) {830this.obj = obj;831this.mimeType = mimeType;832this.dch = dch;833}834835/**836* Return the DataContentHandler for this object.837* Used only by the DataHandler class.838*/839public DataContentHandler getDCH() {840return dch;841}842843/**844* Return the DataFlavors for this <code>DataContentHandler</code>.845* @return the DataFlavors846*/847public synchronized DataFlavor[] getTransferDataFlavors() {848if (transferFlavors == null) {849if (dch != null) {850transferFlavors = dch.getTransferDataFlavors();851} else {852transferFlavors = new DataFlavor[1];853transferFlavors[0] = new ActivationDataFlavor(obj.getClass(),854mimeType, mimeType);855}856}857return transferFlavors;858}859860/**861* Return the Transfer Data of type DataFlavor from InputStream.862* @param df the DataFlavor863* @param ds the DataSource864* @return the constructed Object865*/866public Object getTransferData(DataFlavor df, DataSource ds)867throws UnsupportedFlavorException, IOException {868869if (dch != null)870return dch.getTransferData(df, ds);871else if (df.equals(getTransferDataFlavors()[0])) // only have one now872return obj;873else874throw new UnsupportedFlavorException(df);875876}877878public Object getContent(DataSource ds) {879return obj;880}881882/**883* Write the object to the output stream.884*/885public void writeTo(Object obj, String mimeType, OutputStream os)886throws IOException {887if (dch != null)888dch.writeTo(obj, mimeType, os);889else if (obj instanceof byte[])890os.write((byte[])obj);891else if (obj instanceof String) {892OutputStreamWriter osw = new OutputStreamWriter(os);893osw.write((String)obj);894osw.flush();895} else throw new UnsupportedDataTypeException(896"no object DCH for MIME type " + this.mimeType);897}898}899900901