1. /*
  2. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  3. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  4. */
  5. package javax.activation;
  6. import java.io.InputStream;
  7. import java.io.IOException;
  8. import java.io.OutputStream;
  9. import java.io.PipedInputStream;
  10. import java.io.PipedOutputStream;
  11. import java.net.URL;
  12. import java.awt.datatransfer.Transferable;
  13. import java.awt.datatransfer.DataFlavor;
  14. import java.awt.datatransfer.UnsupportedFlavorException;
  15. /**
  16. * The DataHandler class provides a consistent interface to data
  17. * available in many different sources and formats.
  18. * It manages simple stream to string conversions and related operations
  19. * using DataContentHandlers.
  20. * It provides access to commands that can operate on the data.
  21. * The commands are found using a CommandMap. <p>
  22. *
  23. * <b>DataHandler and the Transferable Interface</b><p>
  24. * DataHandler implements the Transferable interface so that data can
  25. * be used in AWT data transfer operations, such as cut and paste and
  26. * drag and drop. The implementation of the Transferable interface
  27. * relies on the availability of an installed DataContentHandler
  28. * object corresponding to the MIME type of the data represented in
  29. * the specific instance of the DataHandler.<p>
  30. *
  31. * <b>DataHandler and CommandMaps</b><p>
  32. * The DataHandler keeps track of the current CommandMap that it uses to
  33. * service requests for commands (<code>getCommand</code>,
  34. * <code>getAllCommands</code>, <code>getPreferredCommands</code>).
  35. * Each instance of a DataHandler may have a CommandMap associated with
  36. * it using the <code>setCommandMap</code> method. If a CommandMap was
  37. * not set, DataHandler calls the <code>getDefaultCommandMap</code>
  38. * method in CommandMap and uses the value it returns. See
  39. * <i>CommandMap</i> for more information. <p>
  40. *
  41. * <b>DataHandler and URLs</b><p>
  42. * The current DataHandler implementation creates a private
  43. * instance of URLDataSource when it is constructed with a URL.
  44. *
  45. * @see javax.activation.CommandMap
  46. * @see javax.activation.DataContentHandler
  47. * @see javax.activation.DataSource
  48. * @see javax.activation.URLDataSource
  49. */
  50. public class DataHandler implements Transferable {
  51. // Use the datasource to indicate whether we were started via the
  52. // DataSource constructor or the object constructor.
  53. private DataSource dataSource = null;
  54. private DataSource objDataSource = null;
  55. // The Object and mimetype from the constructor (if passed in).
  56. // object remains null if it was instantiated with a
  57. // DataSource.
  58. private Object object = null;
  59. private String objectMimeType = null;
  60. // Keep track of the CommandMap
  61. private CommandMap currentCommandMap = null;
  62. // our transfer flavors
  63. private static final DataFlavor emptyFlavors[] = new DataFlavor[0];
  64. private DataFlavor transferFlavors[] = emptyFlavors;
  65. // our DataContentHandler
  66. private DataContentHandler dataContentHandler = null;
  67. private DataContentHandler factoryDCH = null;
  68. // our DataContentHandlerFactory
  69. private static DataContentHandlerFactory factory = null;
  70. private DataContentHandlerFactory oldFactory = null;
  71. // the short representation of the ContentType (sans params)
  72. private String shortType = null;
  73. /**
  74. * Create a <code>DataHandler</code> instance referencing the
  75. * specified DataSource. The data exists in a byte stream form.
  76. * The DataSource will provide an InputStream to access the data.
  77. *
  78. * @param ds the DataSource
  79. */
  80. public DataHandler(DataSource ds) {
  81. // save a reference to the incoming DS
  82. dataSource = ds;
  83. oldFactory = factory; // keep track of the factory
  84. }
  85. /**
  86. * Create a <code>DataHandler</code> instance representing an object
  87. * of this MIME type. This constructor is
  88. * used when the application already has an in-memory representation
  89. * of the data in the form of a Java Object.
  90. *
  91. * @param obj the Java Object
  92. * @param mimeType the MIME type of the object
  93. */
  94. public DataHandler(Object obj, String mimeType) {
  95. object = obj;
  96. objectMimeType = mimeType;
  97. oldFactory = factory; // keep track of the factory
  98. }
  99. /**
  100. * Create a <code>DataHandler</code> instance referencing a URL.
  101. * The DataHandler internally creates a <code>URLDataSource</code>
  102. * instance to represent the URL.
  103. *
  104. * @param url a URL object
  105. */
  106. public DataHandler(URL url) {
  107. dataSource = new URLDataSource(url);
  108. oldFactory = factory; // keep track of the factory
  109. }
  110. /**
  111. * Return the CommandMap for this instance of DataHandler.
  112. */
  113. private synchronized CommandMap getCommandMap() {
  114. if (currentCommandMap != null)
  115. return currentCommandMap;
  116. else
  117. return CommandMap.getDefaultCommandMap();
  118. }
  119. /**
  120. * Return the DataSource associated with this instance
  121. * of DataHandler.
  122. * <p>
  123. * For DataHandlers that have been instantiated with a DataSource,
  124. * this method returns the DataSource that was used to create the
  125. * DataHandler object. In other cases the DataHandler
  126. * constructs a DataSource from the data used to construct
  127. * the DataHandler. DataSources created for DataHandlers <b>not</b>
  128. * instantiated with a DataSource are cached for performance
  129. * reasons.
  130. *
  131. * @return a valid DataSource object for this DataHandler
  132. */
  133. public DataSource getDataSource() {
  134. if (dataSource == null) {
  135. // create one on the fly
  136. if (objDataSource == null)
  137. objDataSource = new DataHandlerDataSource(this);
  138. return objDataSource;
  139. }
  140. return dataSource;
  141. }
  142. /**
  143. * Return the name of the data object. If this DataHandler
  144. * was created with a DataSource, this method calls through
  145. * to the <code>DataSource.getName</code> method, otherwise it
  146. * returns <i>null</i>.
  147. *
  148. * @return the name of the object
  149. */
  150. public String getName() {
  151. if (dataSource != null)
  152. return dataSource.getName();
  153. else
  154. return null;
  155. }
  156. /**
  157. * Return the MIME type of this object as retrieved from
  158. * the source object. Note that this is the <i>full</i>
  159. * type with parameters.
  160. *
  161. * @return the MIME type
  162. */
  163. public String getContentType() {
  164. if (dataSource != null) // data source case
  165. return dataSource.getContentType();
  166. else
  167. return objectMimeType; // obj/type case
  168. }
  169. /**
  170. * Get the InputStream for this object. <p>
  171. *
  172. * For DataHandlers instantiated with a DataSource, the DataHandler
  173. * calls the <code>DataSource.getInputStream</code> method and
  174. * returns the result to the caller.
  175. * <p>
  176. * For DataHandlers instantiated with an Object, the DataHandler
  177. * first attempts to find a DataContentHandler for the Object. If
  178. * the DataHandler can not find a DataContentHandler for this MIME
  179. * type, it throws an UnsupportedDataTypeException. If it is
  180. * successful, it creates a pipe and a thread. The thread uses the
  181. * DataContentHandler's <code>writeTo</code> method to write the
  182. * stream data into one end of the pipe. The other end of the pipe
  183. * is returned to the caller. Because a thread is created to copy
  184. * the data, IOExceptions that may occur during the copy can not be
  185. * propagated back to the caller. The result is an empty stream.<p>
  186. *
  187. * @return the InputStream representing this data
  188. * @exception IOException if an I/O error occurs
  189. *
  190. * @see javax.activation.DataContentHandler#writeTo
  191. * @see javax.activation.UnsupportedDataTypeException
  192. */
  193. public InputStream getInputStream() throws IOException {
  194. InputStream ins = null;
  195. if (dataSource != null) {
  196. ins = dataSource.getInputStream();
  197. } else {
  198. DataContentHandler dch = getDataContentHandler();
  199. // we won't even try if we can't get a dch
  200. if (dch == null)
  201. throw new UnsupportedDataTypeException(
  202. "no DCH for MIME type " + getBaseType());
  203. if (dch instanceof ObjectDataContentHandler) {
  204. if (((ObjectDataContentHandler)dch).getDCH() == null)
  205. throw new UnsupportedDataTypeException(
  206. "no object DCH for MIME type " + getBaseType());
  207. }
  208. // there is none but the default^^^^^^^^^^^^^^^^
  209. final DataContentHandler fdch = dch;
  210. // from bill s.
  211. // ce n'est pas une pipe!
  212. //
  213. // NOTE: This block of code needs to throw exceptions, but
  214. // can't because it is in another thread!!! ARG!
  215. //
  216. final PipedOutputStream pos = new PipedOutputStream();
  217. PipedInputStream pin = new PipedInputStream(pos);
  218. new Thread(
  219. new Runnable() {
  220. public void run() {
  221. try {
  222. fdch.writeTo(object, objectMimeType, pos);
  223. } catch (IOException e) {
  224. } finally {
  225. try {
  226. pos.close();
  227. } catch (IOException ie) { }
  228. }
  229. }
  230. },
  231. "DataHandler.getInputStream").start();
  232. ins = pin;
  233. }
  234. return ins;
  235. }
  236. /**
  237. * Write the data to an <code>OutputStream</code>.<p>
  238. *
  239. * If the DataHandler was created with a DataSource, writeTo
  240. * retrieves the InputStream and copies the bytes from the
  241. * InputStream to the OutputStream passed in.
  242. * <p>
  243. * If the DataHandler was created with an object, writeTo
  244. * retrieves the DataContentHandler for the object's type.
  245. * If the DataContentHandler was found, it calls the
  246. * <code>writeTo</code> method on the <code>DataContentHandler</code>.
  247. *
  248. * @param os the OutputStream to write to
  249. * @exception IOException if an I/O error occurs
  250. */
  251. public void writeTo(OutputStream os) throws IOException {
  252. // for the DataSource case
  253. if (dataSource != null) {
  254. InputStream is = null;
  255. byte data[] = new byte[8*1024];
  256. int bytes_read;
  257. is = dataSource.getInputStream();
  258. while ((bytes_read = is.read(data)) > 0) {
  259. os.write(data, 0, bytes_read);
  260. }
  261. is.close();
  262. } else { // for the Object case
  263. DataContentHandler dch = getDataContentHandler();
  264. dch.writeTo(object, objectMimeType, os);
  265. }
  266. }
  267. /**
  268. * Get an OutputStream for this DataHandler to allow overwriting
  269. * the underlying data.
  270. * If the DataHandler was created with a DataSource, the
  271. * DataSource's <code>getOutputStream</code> method is called.
  272. * Otherwise, <code>null</code> is returned.
  273. *
  274. * @return the OutputStream
  275. *
  276. * @see javax.activation.DataSource#getOutputStream
  277. * @see javax.activation.URLDataSource
  278. */
  279. public OutputStream getOutputStream() throws IOException {
  280. if (dataSource != null)
  281. return dataSource.getOutputStream();
  282. else
  283. return null;
  284. }
  285. /**
  286. * Return the DataFlavors in which this data is available. <p>
  287. *
  288. * Returns an array of DataFlavor objects indicating the flavors
  289. * the data can be provided in. The array is usually ordered
  290. * according to preference for providing the data, from most
  291. * richly descriptive to least richly descriptive.<p>
  292. *
  293. * The DataHandler attempts to find a DataContentHandler that
  294. * corresponds to the MIME type of the data. If one is located,
  295. * the DataHandler calls the DataContentHandler's
  296. * <code>getTransferDataFlavors</code> method. <p>
  297. *
  298. * If a DataContentHandler can <i>not</i> be located, and if the
  299. * DataHandler was created with a DataSource (or URL), one
  300. * DataFlavor is returned that represents this object's MIME type
  301. * and the <code>java.io.InputStream</code> class. If the
  302. * DataHandler was created with an object and a MIME type,
  303. * getTransferDataFlavors returns one DataFlavor that represents
  304. * this object's MIME type and the object's class.
  305. *
  306. * @return an array of data flavors in which this data can be transferred
  307. * @see javax.activation.DataContentHandler#getTransferDataFlavors
  308. */
  309. public synchronized DataFlavor[] getTransferDataFlavors() {
  310. if (factory != oldFactory) // if the factory has changed, clear cache
  311. transferFlavors = emptyFlavors;
  312. // if it's not set, set it...
  313. if (transferFlavors == emptyFlavors)
  314. transferFlavors = getDataContentHandler().getTransferDataFlavors();
  315. return transferFlavors;
  316. }
  317. /**
  318. * Returns whether the specified data flavor is supported
  319. * for this object.<p>
  320. *
  321. * This method iterates through the DataFlavors returned from
  322. * <code>getTransferDataFlavors</code>, comparing each with
  323. * the specified flavor.
  324. *
  325. * @param flavor the requested flavor for the data
  326. * @return true if the data flavor is supported
  327. * @see javax.activation.DataHandler#getTransferDataFlavors
  328. */
  329. public boolean isDataFlavorSupported(DataFlavor flavor) {
  330. DataFlavor[] lFlavors = getTransferDataFlavors();
  331. for (int i = 0; i < lFlavors.length; i++) {
  332. if (lFlavors[i].equals(flavor))
  333. return true;
  334. }
  335. return false;
  336. }
  337. /**
  338. * Returns an object that represents the data to be
  339. * transferred. The class of the object returned is defined by the
  340. * representation class of the data flavor.<p>
  341. *
  342. * <b>For DataHandler's created with DataSources or URLs:</b><p>
  343. *
  344. * The DataHandler attempts to locate a DataContentHandler
  345. * for this MIME type. If one is found, the passed in DataFlavor
  346. * and the type of the data are passed to its <code>getTransferData</code>
  347. * method. If the DataHandler fails to locate a DataContentHandler
  348. * and the flavor specifies this object's MIME type and the
  349. * <code>java.io.InputStream</code> class, this object's InputStream
  350. * is returned.
  351. * Otherwise it throws an UnsupportedFlavorException. <p>
  352. *
  353. * <b>For DataHandler's created with Objects:</b><p>
  354. *
  355. * The DataHandler attempts to locate a DataContentHandler
  356. * for this MIME type. If one is found, the passed in DataFlavor
  357. * and the type of the data are passed to its getTransferData
  358. * method. If the DataHandler fails to locate a DataContentHandler
  359. * and the flavor specifies this object's MIME type and its class,
  360. * this DataHandler's referenced object is returned.
  361. * Otherwise it throws an UnsupportedFlavorException.
  362. *
  363. * @param flavor the requested flavor for the data
  364. * @return the object
  365. * @exception UnsupportedFlavorException if the data could not be
  366. * converted to the requested flavor
  367. * @exception IOException if an I/O error occurs
  368. * @see javax.activation.ActivationDataFlavor
  369. */
  370. public Object getTransferData(DataFlavor flavor)
  371. throws UnsupportedFlavorException, IOException {
  372. return getDataContentHandler().getTransferData(flavor, dataSource);
  373. }
  374. /**
  375. * Set the CommandMap for use by this DataHandler.
  376. * Setting it to <code>null</code> causes the CommandMap to revert
  377. * to the CommandMap returned by the
  378. * <code>CommandMap.getDefaultCommandMap</code> method.
  379. * Changing the CommandMap, or setting it to <code>null</code>,
  380. * clears out any data cached from the previous CommandMap.
  381. *
  382. * @param commandMap the CommandMap to use in this DataHandler
  383. *
  384. * @see javax.activation.CommandMap#setDefaultCommandMap
  385. */
  386. public synchronized void setCommandMap(CommandMap commandMap) {
  387. if (commandMap != currentCommandMap || commandMap == null) {
  388. // clear cached values...
  389. transferFlavors = emptyFlavors;
  390. dataContentHandler = null;
  391. currentCommandMap = commandMap;
  392. }
  393. }
  394. /**
  395. * Return the <i>preferred</i> commands for this type of data.
  396. * This method calls the <code>getPreferredCommands</code> method
  397. * in the CommandMap associated with this instance of DataHandler.
  398. * This method returns an array that represents a subset of
  399. * available commands. In cases where multiple commands for the
  400. * MIME type represented by this DataHandler are present, the
  401. * installed CommandMap chooses the appropriate commands.
  402. *
  403. * @return the CommandInfo objects representing the preferred commands
  404. *
  405. * @see javax.activation.CommandMap#getPreferredCommands
  406. */
  407. public CommandInfo[] getPreferredCommands() {
  408. return getCommandMap().getPreferredCommands(getBaseType());
  409. }
  410. /**
  411. * Return all the commands for this type of data.
  412. * This method returns an array containing all commands
  413. * for the type of data represented by this DataHandler. The
  414. * MIME type for the underlying data represented by this DataHandler
  415. * is used to call through to the <code>getAllCommands</code> method
  416. * of the CommandMap associated with this DataHandler.
  417. *
  418. * @return the CommandInfo objects representing all the commands
  419. *
  420. * @see javax.activation.CommandMap#getAllCommands
  421. */
  422. public CommandInfo[] getAllCommands() {
  423. return getCommandMap().getAllCommands(getBaseType());
  424. }
  425. /**
  426. * Get the command <i>cmdName</i>. Use the search semantics as
  427. * defined by the CommandMap installed in this DataHandler. The
  428. * MIME type for the underlying data represented by this DataHandler
  429. * is used to call through to the <code>getCommand</code> method
  430. * of the CommandMap associated with this DataHandler.
  431. *
  432. * @param cmdName the command name
  433. * @return the CommandInfo corresponding to the command
  434. *
  435. * @see javax.activation.CommandMap#getCommand
  436. */
  437. public CommandInfo getCommand(String cmdName) {
  438. return getCommandMap().getCommand(getBaseType(), cmdName);
  439. }
  440. /**
  441. * Return the data in its preferred Object form. <p>
  442. *
  443. * If the DataHandler was instantiated with an object, return
  444. * the object. <p>
  445. *
  446. * If the DataHandler was instantiated with a DataSource,
  447. * this method uses a DataContentHandler to return the content
  448. * object for the data represented by this DataHandler. If no
  449. * <code>DataContentHandler</code> can be found for the
  450. * the type of this data, the DataHandler returns an
  451. * InputStream for the data.
  452. *
  453. * @return the content.
  454. * @exception IOException if an IOException occurs during
  455. * this operation.
  456. */
  457. public Object getContent() throws IOException {
  458. return getDataContentHandler().getContent(getDataSource());
  459. }
  460. /**
  461. * A convenience method that takes a CommandInfo object
  462. * and instantiates the corresponding command, usually
  463. * a JavaBean component.
  464. * <p>
  465. * This method calls the CommandInfo's <code>getCommandObject</code>
  466. * method with the <code>ClassLoader</code> used to load
  467. * the <code>javax.activation.DataHandler</code> class itself.
  468. *
  469. * @param cmdinfo the CommandInfo corresponding to a command
  470. * @return the instantiated command object
  471. */
  472. public Object getBean(CommandInfo cmdinfo) {
  473. Object bean = null;
  474. try {
  475. // make the bean
  476. bean = cmdinfo.getCommandObject(this, getClass().getClassLoader());
  477. } catch (IOException e) {
  478. } catch (ClassNotFoundException e) { }
  479. return bean;
  480. }
  481. /**
  482. * Get the DataContentHandler for this DataHandler: <p>
  483. *
  484. * If a DataContentHandlerFactory is set, use it.
  485. * Otherwise look for an object to serve DCH in the
  486. * following order: <p>
  487. *
  488. * 1) if a factory is set, use it <p>
  489. * 2) if a CommandMap is set, use it <p>
  490. * 3) use the default CommandMap <p>
  491. *
  492. * In any case, wrap the real DataContentHandler with one of our own
  493. * to handle any missing cases, fill in defaults, and to ensure that
  494. * we always have a non-null DataContentHandler.
  495. *
  496. * @return the requested DataContentHandler
  497. */
  498. private synchronized DataContentHandler getDataContentHandler() {
  499. // make sure the factory didn't change
  500. if (factory != oldFactory) {
  501. oldFactory = factory;
  502. factoryDCH = null;
  503. dataContentHandler = null;
  504. transferFlavors = emptyFlavors;
  505. }
  506. if (dataContentHandler != null)
  507. return dataContentHandler;
  508. String simpleMT = getBaseType();
  509. if (factoryDCH == null && factory != null)
  510. factoryDCH = factory.createDataContentHandler(simpleMT);
  511. if (factoryDCH != null)
  512. dataContentHandler = factoryDCH;
  513. if (dataContentHandler == null) {
  514. dataContentHandler =
  515. getCommandMap().createDataContentHandler(simpleMT);
  516. }
  517. // getDataContentHandler always uses these 'wrapper' handlers
  518. // to make sure it returns SOMETHING meaningful...
  519. if (dataSource != null)
  520. dataContentHandler = new DataSourceDataContentHandler(
  521. dataContentHandler,
  522. dataSource);
  523. else
  524. dataContentHandler = new ObjectDataContentHandler(
  525. dataContentHandler,
  526. object,
  527. objectMimeType);
  528. return dataContentHandler;
  529. }
  530. /**
  531. * Use the MimeType class to extract the MIME type/subtype,
  532. * ignoring the parameters. The type is cached.
  533. */
  534. private synchronized String getBaseType() {
  535. if (shortType == null) {
  536. String ct = getContentType();
  537. try {
  538. MimeType mt = new MimeType(ct);
  539. shortType = mt.getBaseType();
  540. } catch (MimeTypeParseException e) {
  541. shortType = ct;
  542. }
  543. }
  544. return shortType;
  545. }
  546. /**
  547. * Sets the DataContentHandlerFactory. The DataContentHandlerFactory
  548. * is called first to find DataContentHandlers.
  549. * The DataContentHandlerFactory can only be set once.
  550. * <p>
  551. * If the DataContentHandlerFactory has already been set,
  552. * this method throws an Error.
  553. *
  554. * @param factory the DataContentHandlerFactory
  555. * @exception Error if the factory has already been defined.
  556. *
  557. * @see javax.activation.DataContentHandlerFactory
  558. */
  559. public static synchronized void setDataContentHandlerFactory(
  560. DataContentHandlerFactory newFactory) {
  561. if (factory != null)
  562. throw new Error("DataContentHandlerFactory already defined");
  563. SecurityManager security = System.getSecurityManager();
  564. if (security != null) {
  565. try {
  566. // if it's ok with the SecurityManager, it's ok with me...
  567. security.checkSetFactory();
  568. } catch (SecurityException ex) {
  569. // otherwise, we also allow it if this code and the
  570. // factory come from the same class loader (e.g.,
  571. // the JAF classes were loaded with the applet classes).
  572. if (DataHandler.class.getClassLoader() !=
  573. newFactory.getClass().getClassLoader())
  574. throw ex;
  575. }
  576. }
  577. factory = newFactory;
  578. }
  579. }
  580. /**
  581. * The DataHanderDataSource class implements the
  582. * DataSource interface when the DataHandler is constructed
  583. * with an Object and a mimeType string.
  584. */
  585. class DataHandlerDataSource implements DataSource {
  586. DataHandler dataHandler = null;
  587. /**
  588. * The constructor.
  589. */
  590. public DataHandlerDataSource(DataHandler dh) {
  591. this.dataHandler = dh;
  592. }
  593. /**
  594. * Returns an <code>InputStream</code> representing this object.
  595. * @return the <code>InputStream</code>
  596. */
  597. public InputStream getInputStream() throws IOException {
  598. return dataHandler.getInputStream();
  599. }
  600. /**
  601. * Returns the <code>OutputStream</code> for this object.
  602. * @return the <code>OutputStream</code>
  603. */
  604. public OutputStream getOutputStream() throws IOException {
  605. return dataHandler.getOutputStream();
  606. }
  607. /**
  608. * Returns the MIME type of the data represented by this object.
  609. * @return the MIME type
  610. */
  611. public String getContentType() {
  612. return dataHandler.getContentType();
  613. }
  614. /**
  615. * Returns the name of this object.
  616. * @return the name of this object
  617. */
  618. public String getName() {
  619. return dataHandler.getName(); // what else would it be?
  620. }
  621. }
  622. /*
  623. * DataSourceDataContentHandler
  624. *
  625. * This is a <i>private</i> DataContentHandler that wraps the real
  626. * DataContentHandler in the case where the DataHandler was instantiated
  627. * with a DataSource.
  628. */
  629. class DataSourceDataContentHandler implements DataContentHandler {
  630. private DataSource ds = null;
  631. private DataFlavor transferFlavors[] = null;
  632. private DataContentHandler dch = null;
  633. /**
  634. * The constructor.
  635. */
  636. public DataSourceDataContentHandler(DataContentHandler dch, DataSource ds) {
  637. this.ds = ds;
  638. this.dch = dch;
  639. }
  640. /**
  641. * Return the DataFlavors for this <code>DataContentHandler</code>.
  642. * @return the DataFlavors
  643. */
  644. public DataFlavor[] getTransferDataFlavors() {
  645. if (transferFlavors == null) {
  646. if (dch != null) { // is there a dch?
  647. transferFlavors = dch.getTransferDataFlavors();
  648. } else {
  649. transferFlavors = new DataFlavor[1];
  650. transferFlavors[0] =
  651. new ActivationDataFlavor(ds.getContentType(),
  652. ds.getContentType());
  653. }
  654. }
  655. return transferFlavors;
  656. }
  657. /**
  658. * Return the Transfer Data of type DataFlavor from InputStream.
  659. * @param df the DataFlavor
  660. * @param ds the DataSource
  661. * @return the constructed Object
  662. */
  663. public Object getTransferData(DataFlavor df, DataSource ds) throws
  664. UnsupportedFlavorException, IOException {
  665. if (dch != null)
  666. return dch.getTransferData(df, ds);
  667. else if (df.equals(transferFlavors[0])) // only have one now
  668. return ds.getInputStream();
  669. else
  670. throw new UnsupportedFlavorException(df);
  671. }
  672. public Object getContent(DataSource ds) throws IOException {
  673. if (dch != null)
  674. return dch.getContent(ds);
  675. else
  676. return ds.getInputStream();
  677. }
  678. /**
  679. * Write the object to the output stream.
  680. */
  681. public void writeTo(Object obj, String mimeType, OutputStream os)
  682. throws IOException {
  683. if (dch != null)
  684. dch.writeTo(obj, mimeType, os);
  685. else
  686. throw new UnsupportedDataTypeException(
  687. "no DCH for content type " + ds.getContentType());
  688. }
  689. }
  690. /*
  691. * ObjectDataContentHandler
  692. *
  693. * This is a <i>private</i> DataContentHandler that wraps the real
  694. * DataContentHandler in the case where the DataHandler was instantiated
  695. * with an object.
  696. */
  697. class ObjectDataContentHandler implements DataContentHandler {
  698. private DataFlavor transferFlavors[] = null;
  699. private Object obj;
  700. private String mimeType;
  701. private DataContentHandler dch = null;
  702. /**
  703. * The constructor.
  704. */
  705. public ObjectDataContentHandler(DataContentHandler dch,
  706. Object obj, String mimeType) {
  707. this.obj = obj;
  708. this.mimeType = mimeType;
  709. this.dch = dch;
  710. }
  711. /**
  712. * Return the DataContentHandler for this object.
  713. * Used only by the DataHandler class.
  714. */
  715. public DataContentHandler getDCH() {
  716. return dch;
  717. }
  718. /**
  719. * Return the DataFlavors for this <code>DataContentHandler</code>.
  720. * @return the DataFlavors
  721. */
  722. public DataFlavor[] getTransferDataFlavors() {
  723. if (transferFlavors == null) {
  724. if (dch != null) {
  725. transferFlavors = dch.getTransferDataFlavors();
  726. } else {
  727. transferFlavors = new DataFlavor[1];
  728. transferFlavors[0] = new ActivationDataFlavor(obj.getClass(),
  729. mimeType, mimeType);
  730. }
  731. }
  732. return transferFlavors;
  733. }
  734. /**
  735. * Return the Transfer Data of type DataFlavor from InputStream.
  736. * @param df the DataFlavor
  737. * @param ds the DataSource
  738. * @return the constructed Object
  739. */
  740. public Object getTransferData(DataFlavor df, DataSource ds)
  741. throws UnsupportedFlavorException, IOException {
  742. if (dch != null)
  743. return dch.getTransferData(df, ds);
  744. else if (df.equals(transferFlavors[0])) // only have one now
  745. return obj;
  746. else
  747. throw new UnsupportedFlavorException(df);
  748. }
  749. public Object getContent(DataSource ds) {
  750. return obj;
  751. }
  752. /**
  753. * Write the object to the output stream.
  754. */
  755. public void writeTo(Object obj, String mimeType, OutputStream os)
  756. throws IOException {
  757. if (dch != null)
  758. dch.writeTo(obj, mimeType, os);
  759. else
  760. throw new UnsupportedDataTypeException(
  761. "no object DCH for MIME type " + this.mimeType);
  762. }
  763. }