< prev index next >

src/java.activation/share/classes/javax/activation/DataHandler.java

Print this page




  37 import java.awt.datatransfer.UnsupportedFlavorException;
  38 
  39 /**
  40  * The DataHandler class provides a consistent interface to data
  41  * available in many different sources and formats.
  42  * It manages simple stream to string conversions and related operations
  43  * using DataContentHandlers.
  44  * It provides access to commands that can operate on the data.
  45  * The commands are found using a CommandMap. <p>
  46  *
  47  * <b>DataHandler and the Transferable Interface</b><p>
  48  * DataHandler implements the Transferable interface so that data can
  49  * be used in AWT data transfer operations, such as cut and paste and
  50  * drag and drop. The implementation of the Transferable interface
  51  * relies on the availability of an installed DataContentHandler
  52  * object corresponding to the MIME type of the data represented in
  53  * the specific instance of the DataHandler.<p>
  54  *
  55  * <b>DataHandler and CommandMaps</b><p>
  56  * The DataHandler keeps track of the current CommandMap that it uses to
  57  * service requests for commands (<code>getCommand</code>,
  58  * <code>getAllCommands</code>, <code>getPreferredCommands</code>).
  59  * Each instance of a DataHandler may have a CommandMap associated with
  60  * it using the <code>setCommandMap</code> method.  If a CommandMap was
  61  * not set, DataHandler calls the <code>getDefaultCommandMap</code>
  62  * method in CommandMap and uses the value it returns. See
  63  * <i>CommandMap</i> for more information. <p>
  64  *
  65  * <b>DataHandler and URLs</b><p>
  66  * The current DataHandler implementation creates a private
  67  * instance of URLDataSource when it is constructed with a URL.
  68  *
  69  * @see javax.activation.CommandMap
  70  * @see javax.activation.DataContentHandler
  71  * @see javax.activation.DataSource
  72  * @see javax.activation.URLDataSource
  73  *
  74  * @since 1.6
  75  */
  76 
  77 public class DataHandler implements Transferable {
  78 
  79     // Use the datasource to indicate whether we were started via the
  80     // DataSource constructor or the object constructor.
  81     private DataSource dataSource = null;


  88     private String objectMimeType = null;
  89 
  90     // Keep track of the CommandMap
  91     private CommandMap currentCommandMap = null;
  92 
  93     // our transfer flavors
  94     private static final DataFlavor emptyFlavors[] = new DataFlavor[0];
  95     private DataFlavor transferFlavors[] = emptyFlavors;
  96 
  97     // our DataContentHandler
  98     private DataContentHandler dataContentHandler = null;
  99     private DataContentHandler factoryDCH = null;
 100 
 101     // our DataContentHandlerFactory
 102     private static DataContentHandlerFactory factory = null;
 103     private DataContentHandlerFactory oldFactory = null;
 104     // the short representation of the ContentType (sans params)
 105     private String shortType = null;
 106 
 107     /**
 108      * Create a <code>DataHandler</code> instance referencing the
 109      * specified DataSource.  The data exists in a byte stream form.
 110      * The DataSource will provide an InputStream to access the data.
 111      *
 112      * @param ds        the DataSource
 113      */
 114     public DataHandler(DataSource ds) {
 115         // save a reference to the incoming DS
 116         dataSource = ds;
 117         oldFactory = factory; // keep track of the factory
 118     }
 119 
 120     /**
 121      * Create a <code>DataHandler</code> instance representing an object
 122      * of this MIME type.  This constructor is
 123      * used when the application already has an in-memory representation
 124      * of the data in the form of a Java Object.
 125      *
 126      * @param obj       the Java Object
 127      * @param mimeType  the MIME type of the object
 128      */
 129     public DataHandler(Object obj, String mimeType) {
 130         object = obj;
 131         objectMimeType = mimeType;
 132         oldFactory = factory; // keep track of the factory
 133     }
 134 
 135     /**
 136      * Create a <code>DataHandler</code> instance referencing a URL.
 137      * The DataHandler internally creates a <code>URLDataSource</code>
 138      * instance to represent the URL.
 139      *
 140      * @param url       a URL object
 141      */
 142     public DataHandler(URL url) {
 143         dataSource = new URLDataSource(url);
 144         oldFactory = factory; // keep track of the factory
 145     }
 146 
 147     /**
 148      * Return the CommandMap for this instance of DataHandler.
 149      */
 150     private synchronized CommandMap getCommandMap() {
 151         if (currentCommandMap != null)
 152             return currentCommandMap;
 153         else
 154             return CommandMap.getDefaultCommandMap();
 155     }
 156 
 157     /**


 164      * constructs a DataSource from the data used to construct
 165      * the DataHandler. DataSources created for DataHandlers <b>not</b>
 166      * instantiated with a DataSource are cached for performance
 167      * reasons.
 168      *
 169      * @return  a valid DataSource object for this DataHandler
 170      */
 171     public DataSource getDataSource() {
 172         if (dataSource == null) {
 173             // create one on the fly
 174             if (objDataSource == null)
 175                 objDataSource = new DataHandlerDataSource(this);
 176             return objDataSource;
 177         }
 178         return dataSource;
 179     }
 180 
 181     /**
 182      * Return the name of the data object. If this DataHandler
 183      * was created with a DataSource, this method calls through
 184      * to the <code>DataSource.getName</code> method, otherwise it
 185      * returns <i>null</i>.
 186      *
 187      * @return  the name of the object
 188      */
 189     public String getName() {
 190         if (dataSource != null)
 191             return dataSource.getName();
 192         else
 193             return null;
 194     }
 195 
 196     /**
 197      * Return the MIME type of this object as retrieved from
 198      * the source object. Note that this is the <i>full</i>
 199      * type with parameters.
 200      *
 201      * @return  the MIME type
 202      */
 203     public String getContentType() {
 204         if (dataSource != null) // data source case
 205             return dataSource.getContentType();
 206         else
 207             return objectMimeType; // obj/type case
 208     }
 209 
 210     /**
 211      * Get the InputStream for this object. <p>
 212      *
 213      * For DataHandlers instantiated with a DataSource, the DataHandler
 214      * calls the <code>DataSource.getInputStream</code> method and
 215      * returns the result to the caller.
 216      * <p>
 217      * For DataHandlers instantiated with an Object, the DataHandler
 218      * first attempts to find a DataContentHandler for the Object. If
 219      * the DataHandler can not find a DataContentHandler for this MIME
 220      * type, it throws an UnsupportedDataTypeException.  If it is
 221      * successful, it creates a pipe and a thread.  The thread uses the
 222      * DataContentHandler's <code>writeTo</code> method to write the
 223      * stream data into one end of the pipe.  The other end of the pipe
 224      * is returned to the caller.  Because a thread is created to copy
 225      * the data, IOExceptions that may occur during the copy can not be
 226      * propagated back to the caller. The result is an empty stream.<p>
 227      *
 228      * @return  the InputStream representing this data
 229      * @exception IOException   if an I/O error occurs
 230      *
 231      * @see javax.activation.DataContentHandler#writeTo
 232      * @see javax.activation.UnsupportedDataTypeException
 233      */
 234     public InputStream getInputStream() throws IOException {
 235         InputStream ins = null;
 236 
 237         if (dataSource != null) {
 238             ins = dataSource.getInputStream();
 239         } else {
 240             DataContentHandler dch = getDataContentHandler();
 241             // we won't even try if we can't get a dch
 242             if (dch == null)
 243                 throw new UnsupportedDataTypeException(
 244                                 "no DCH for MIME type " + getBaseType());
 245 
 246             if (dch instanceof ObjectDataContentHandler) {


 264                 public void run() {
 265                     try {
 266                         fdch.writeTo(object, objectMimeType, pos);
 267                     } catch (IOException e) {
 268 
 269                     } finally {
 270                         try {
 271                             pos.close();
 272                         } catch (IOException ie) { }
 273                     }
 274                 }
 275             },
 276                       "DataHandler.getInputStream").start();
 277             ins = pin;
 278         }
 279 
 280         return ins;
 281     }
 282 
 283     /**
 284      * Write the data to an <code>OutputStream</code>.<p>
 285      *
 286      * If the DataHandler was created with a DataSource, writeTo
 287      * retrieves the InputStream and copies the bytes from the
 288      * InputStream to the OutputStream passed in.
 289      * <p>
 290      * If the DataHandler was created with an object, writeTo
 291      * retrieves the DataContentHandler for the object's type.
 292      * If the DataContentHandler was found, it calls the
 293      * <code>writeTo</code> method on the <code>DataContentHandler</code>.
 294      *
 295      * @param os        the OutputStream to write to
 296      * @exception IOException   if an I/O error occurs
 297      */
 298     public void writeTo(OutputStream os) throws IOException {
 299         // for the DataSource case
 300         if (dataSource != null) {
 301             InputStream is = null;
 302             byte data[] = new byte[8*1024];
 303             int bytes_read;
 304 
 305             is = dataSource.getInputStream();
 306 
 307             try {
 308                 while ((bytes_read = is.read(data)) > 0) {
 309                     os.write(data, 0, bytes_read);
 310                 }
 311             } finally {
 312                 is.close();
 313                 is = null;
 314             }
 315         } else { // for the Object case
 316             DataContentHandler dch = getDataContentHandler();
 317             dch.writeTo(object, objectMimeType, os);
 318         }
 319     }
 320 
 321     /**
 322      * Get an OutputStream for this DataHandler to allow overwriting
 323      * the underlying data.
 324      * If the DataHandler was created with a DataSource, the
 325      * DataSource's <code>getOutputStream</code> method is called.
 326      * Otherwise, <code>null</code> is returned.
 327      *
 328      * @return the OutputStream
 329      *
 330      * @see javax.activation.DataSource#getOutputStream
 331      * @see javax.activation.URLDataSource
 332      */
 333     public OutputStream getOutputStream() throws IOException {
 334         if (dataSource != null)
 335             return dataSource.getOutputStream();
 336         else
 337             return null;
 338     }
 339 
 340     /**
 341      * Return the DataFlavors in which this data is available. <p>
 342      *
 343      * Returns an array of DataFlavor objects indicating the flavors
 344      * the data can be provided in. The array is usually ordered
 345      * according to preference for providing the data, from most
 346      * richly descriptive to least richly descriptive.<p>
 347      *
 348      * The DataHandler attempts to find a DataContentHandler that
 349      * corresponds to the MIME type of the data. If one is located,
 350      * the DataHandler calls the DataContentHandler's
 351      * <code>getTransferDataFlavors</code> method. <p>
 352      *
 353      * If a DataContentHandler can <i>not</i> be located, and if the
 354      * DataHandler was created with a DataSource (or URL), one
 355      * DataFlavor is returned that represents this object's MIME type
 356      * and the <code>java.io.InputStream</code> class.  If the
 357      * DataHandler was created with an object and a MIME type,
 358      * getTransferDataFlavors returns one DataFlavor that represents
 359      * this object's MIME type and the object's class.
 360      *
 361      * @return  an array of data flavors in which this data can be transferred
 362      * @see javax.activation.DataContentHandler#getTransferDataFlavors
 363      */
 364     public synchronized DataFlavor[] getTransferDataFlavors() {
 365         if (factory != oldFactory) // if the factory has changed, clear cache
 366             transferFlavors = emptyFlavors;
 367 
 368         // if it's not set, set it...
 369         if (transferFlavors == emptyFlavors)
 370             transferFlavors = getDataContentHandler().getTransferDataFlavors();
 371 
 372         if (transferFlavors == emptyFlavors)
 373             return transferFlavors;
 374         else
 375             return transferFlavors.clone();
 376 
 377     }
 378 
 379     /**
 380      * Returns whether the specified data flavor is supported
 381      * for this object.<p>
 382      *
 383      * This method iterates through the DataFlavors returned from
 384      * <code>getTransferDataFlavors</code>, comparing each with
 385      * the specified flavor.
 386      *
 387      * @param flavor    the requested flavor for the data
 388      * @return          true if the data flavor is supported
 389      * @see javax.activation.DataHandler#getTransferDataFlavors
 390      */
 391     public boolean isDataFlavorSupported(DataFlavor flavor) {
 392         DataFlavor[] lFlavors = getTransferDataFlavors();
 393 
 394         for (int i = 0; i < lFlavors.length; i++) {
 395             if (lFlavors[i].equals(flavor))
 396                 return true;
 397         }
 398         return false;
 399     }
 400 
 401     /**
 402      * Returns an object that represents the data to be
 403      * transferred. The class of the object returned is defined by the
 404      * representation class of the data flavor.<p>
 405      *
 406      * <b>For DataHandler's created with DataSources or URLs:</b><p>
 407      *
 408      * The DataHandler attempts to locate a DataContentHandler
 409      * for this MIME type. If one is found, the passed in DataFlavor
 410      * and the type of the data are passed to its <code>getTransferData</code>
 411      * method. If the DataHandler fails to locate a DataContentHandler
 412      * and the flavor specifies this object's MIME type and the
 413      * <code>java.io.InputStream</code> class, this object's InputStream
 414      * is returned.
 415      * Otherwise it throws an UnsupportedFlavorException. <p>
 416      *
 417      * <b>For DataHandler's created with Objects:</b><p>
 418      *
 419      * The DataHandler attempts to locate a DataContentHandler
 420      * for this MIME type. If one is found, the passed in DataFlavor
 421      * and the type of the data are passed to its getTransferData
 422      * method. If the DataHandler fails to locate a DataContentHandler
 423      * and the flavor specifies this object's MIME type and its class,
 424      * this DataHandler's referenced object is returned.
 425      * Otherwise it throws an UnsupportedFlavorException.
 426      *
 427      * @param flavor    the requested flavor for the data
 428      * @return          the object
 429      * @exception UnsupportedFlavorException    if the data could not be
 430      *                  converted to the requested flavor
 431      * @exception IOException   if an I/O error occurs
 432      * @see javax.activation.ActivationDataFlavor
 433      */
 434     public Object getTransferData(DataFlavor flavor)
 435                                 throws UnsupportedFlavorException, IOException {
 436         return getDataContentHandler().getTransferData(flavor, dataSource);
 437     }
 438 
 439     /**
 440      * Set the CommandMap for use by this DataHandler.
 441      * Setting it to <code>null</code> causes the CommandMap to revert
 442      * to the CommandMap returned by the
 443      * <code>CommandMap.getDefaultCommandMap</code> method.
 444      * Changing the CommandMap, or setting it to <code>null</code>,
 445      * clears out any data cached from the previous CommandMap.
 446      *
 447      * @param commandMap        the CommandMap to use in this DataHandler
 448      *
 449      * @see javax.activation.CommandMap#setDefaultCommandMap
 450      */
 451     public synchronized void setCommandMap(CommandMap commandMap) {
 452         if (commandMap != currentCommandMap || commandMap == null) {
 453             // clear cached values...
 454             transferFlavors = emptyFlavors;
 455             dataContentHandler = null;
 456 
 457             currentCommandMap = commandMap;
 458         }
 459     }
 460 
 461     /**
 462      * Return the <i>preferred</i> commands for this type of data.
 463      * This method calls the <code>getPreferredCommands</code> method
 464      * in the CommandMap associated with this instance of DataHandler.
 465      * This method returns an array that represents a subset of
 466      * available commands. In cases where multiple commands for the
 467      * MIME type represented by this DataHandler are present, the
 468      * installed CommandMap chooses the appropriate commands.
 469      *
 470      * @return  the CommandInfo objects representing the preferred commands
 471      *
 472      * @see javax.activation.CommandMap#getPreferredCommands
 473      */
 474     public CommandInfo[] getPreferredCommands() {
 475         if (dataSource != null)
 476             return getCommandMap().getPreferredCommands(getBaseType(),
 477                                                         dataSource);
 478         else
 479             return getCommandMap().getPreferredCommands(getBaseType());
 480     }
 481 
 482     /**
 483      * Return all the commands for this type of data.
 484      * This method returns an array containing all commands
 485      * for the type of data represented by this DataHandler. The
 486      * MIME type for the underlying data represented by this DataHandler
 487      * is used to call through to the <code>getAllCommands</code> method
 488      * of the CommandMap associated with this DataHandler.
 489      *
 490      * @return  the CommandInfo objects representing all the commands
 491      *
 492      * @see javax.activation.CommandMap#getAllCommands
 493      */
 494     public CommandInfo[] getAllCommands() {
 495         if (dataSource != null)
 496             return getCommandMap().getAllCommands(getBaseType(), dataSource);
 497         else
 498             return getCommandMap().getAllCommands(getBaseType());
 499     }
 500 
 501     /**
 502      * Get the command <i>cmdName</i>. Use the search semantics as
 503      * defined by the CommandMap installed in this DataHandler. The
 504      * MIME type for the underlying data represented by this DataHandler
 505      * is used to call through to the <code>getCommand</code> method
 506      * of the CommandMap associated with this DataHandler.
 507      *
 508      * @param cmdName   the command name
 509      * @return  the CommandInfo corresponding to the command
 510      *
 511      * @see javax.activation.CommandMap#getCommand
 512      */
 513     public CommandInfo getCommand(String cmdName) {
 514         if (dataSource != null)
 515             return getCommandMap().getCommand(getBaseType(), cmdName,
 516                                                                 dataSource);
 517         else
 518             return getCommandMap().getCommand(getBaseType(), cmdName);
 519     }
 520 
 521     /**
 522      * Return the data in its preferred Object form. <p>
 523      *
 524      * If the DataHandler was instantiated with an object, return
 525      * the object. <p>
 526      *
 527      * If the DataHandler was instantiated with a DataSource,
 528      * this method uses a DataContentHandler to return the content
 529      * object for the data represented by this DataHandler. If no
 530      * <code>DataContentHandler</code> can be found for the
 531      * the type of this data, the DataHandler returns an
 532      * InputStream for the data.
 533      *
 534      * @return the content.
 535      * @exception IOException if an IOException occurs during
 536      *                              this operation.
 537      */
 538     public Object getContent() throws IOException {
 539         if (object != null)
 540             return object;
 541         else
 542             return getDataContentHandler().getContent(getDataSource());
 543     }
 544 
 545     /**
 546      * A convenience method that takes a CommandInfo object
 547      * and instantiates the corresponding command, usually
 548      * a JavaBean component.
 549      * <p>
 550      * This method calls the CommandInfo's <code>getCommandObject</code>
 551      * method with the <code>ClassLoader</code> used to load
 552      * the <code>javax.activation.DataHandler</code> class itself.
 553      *
 554      * @param cmdinfo   the CommandInfo corresponding to a command
 555      * @return  the instantiated command object
 556      */
 557     public Object getBean(CommandInfo cmdinfo) {
 558         Object bean = null;
 559 
 560         try {
 561             // make the bean
 562             ClassLoader cld = null;
 563             // First try the "application's" class loader.
 564             cld = SecuritySupport.getContextClassLoader();
 565             if (cld == null)
 566                 cld = this.getClass().getClassLoader();
 567             bean = cmdinfo.getCommandObject(this, cld);
 568         } catch (IOException e) {
 569         } catch (ClassNotFoundException e) { }
 570 
 571         return bean;
 572     }


 684         factory = newFactory;
 685     }
 686 }
 687 
 688 /**
 689  * The DataHanderDataSource class implements the
 690  * DataSource interface when the DataHandler is constructed
 691  * with an Object and a mimeType string.
 692  */
 693 class DataHandlerDataSource implements DataSource {
 694     DataHandler dataHandler = null;
 695 
 696     /**
 697      * The constructor.
 698      */
 699     public DataHandlerDataSource(DataHandler dh) {
 700         this.dataHandler = dh;
 701     }
 702 
 703     /**
 704      * Returns an <code>InputStream</code> representing this object.
 705      * @return  the <code>InputStream</code>
 706      */
 707     public InputStream getInputStream() throws IOException {
 708         return dataHandler.getInputStream();
 709     }
 710 
 711     /**
 712      * Returns the <code>OutputStream</code> for this object.
 713      * @return  the <code>OutputStream</code>
 714      */
 715     public OutputStream getOutputStream() throws IOException {
 716         return dataHandler.getOutputStream();
 717     }
 718 
 719     /**
 720      * Returns the MIME type of the data represented by this object.
 721      * @return  the MIME type
 722      */
 723     public String getContentType() {
 724         return dataHandler.getContentType();
 725     }
 726 
 727     /**
 728      * Returns the name of this object.
 729      * @return  the name of this object
 730      */
 731     public String getName() {
 732         return dataHandler.getName(); // what else would it be?
 733     }


 737  * DataSourceDataContentHandler
 738  *
 739  * This is a <i>private</i> DataContentHandler that wraps the real
 740  * DataContentHandler in the case where the DataHandler was instantiated
 741  * with a DataSource.
 742  */
 743 class DataSourceDataContentHandler implements DataContentHandler {
 744     private DataSource ds = null;
 745     private DataFlavor transferFlavors[] = null;
 746     private DataContentHandler dch = null;
 747 
 748     /**
 749      * The constructor.
 750      */
 751     public DataSourceDataContentHandler(DataContentHandler dch, DataSource ds) {
 752         this.ds = ds;
 753         this.dch = dch;
 754     }
 755 
 756     /**
 757      * Return the DataFlavors for this <code>DataContentHandler</code>.
 758      * @return  the DataFlavors
 759      */
 760     public DataFlavor[] getTransferDataFlavors() {
 761 
 762         if (transferFlavors == null) {
 763             if (dch != null) { // is there a dch?
 764                 transferFlavors = dch.getTransferDataFlavors();
 765             } else {
 766                 transferFlavors = new DataFlavor[1];
 767                 transferFlavors[0] =
 768                     new ActivationDataFlavor(ds.getContentType(),
 769                                              ds.getContentType());
 770             }
 771         }
 772         return transferFlavors;
 773     }
 774 
 775     /**
 776      * Return the Transfer Data of type DataFlavor from InputStream.
 777      * @param df        the DataFlavor


 825 
 826     /**
 827      * The constructor.
 828      */
 829     public ObjectDataContentHandler(DataContentHandler dch,
 830                                     Object obj, String mimeType) {
 831         this.obj = obj;
 832         this.mimeType = mimeType;
 833         this.dch = dch;
 834     }
 835 
 836     /**
 837      * Return the DataContentHandler for this object.
 838      * Used only by the DataHandler class.
 839      */
 840     public DataContentHandler getDCH() {
 841         return dch;
 842     }
 843 
 844     /**
 845      * Return the DataFlavors for this <code>DataContentHandler</code>.
 846      * @return  the DataFlavors
 847      */
 848     public synchronized DataFlavor[] getTransferDataFlavors() {
 849         if (transferFlavors == null) {
 850             if (dch != null) {
 851                 transferFlavors = dch.getTransferDataFlavors();
 852             } else {
 853                 transferFlavors = new DataFlavor[1];
 854                 transferFlavors[0] = new ActivationDataFlavor(obj.getClass(),
 855                                              mimeType, mimeType);
 856             }
 857         }
 858         return transferFlavors;
 859     }
 860 
 861     /**
 862      * Return the Transfer Data of type DataFlavor from InputStream.
 863      * @param df        the DataFlavor
 864      * @param ds        the DataSource
 865      * @return          the constructed Object




  37 import java.awt.datatransfer.UnsupportedFlavorException;
  38 
  39 /**
  40  * The DataHandler class provides a consistent interface to data
  41  * available in many different sources and formats.
  42  * It manages simple stream to string conversions and related operations
  43  * using DataContentHandlers.
  44  * It provides access to commands that can operate on the data.
  45  * The commands are found using a CommandMap. <p>
  46  *
  47  * <b>DataHandler and the Transferable Interface</b><p>
  48  * DataHandler implements the Transferable interface so that data can
  49  * be used in AWT data transfer operations, such as cut and paste and
  50  * drag and drop. The implementation of the Transferable interface
  51  * relies on the availability of an installed DataContentHandler
  52  * object corresponding to the MIME type of the data represented in
  53  * the specific instance of the DataHandler.<p>
  54  *
  55  * <b>DataHandler and CommandMaps</b><p>
  56  * The DataHandler keeps track of the current CommandMap that it uses to
  57  * service requests for commands ({@code getCommand, getAllCommands, 
  58  * getPreferredCommands}).
  59  * Each instance of a DataHandler may have a CommandMap associated with
  60  * it using the {@code setCommandMap} method.  If a CommandMap was
  61  * not set, DataHandler calls the {@code getDefaultCommandMap}
  62  * method in CommandMap and uses the value it returns. See
  63  * <i>CommandMap</i> for more information. <p>
  64  *
  65  * <b>DataHandler and URLs</b><p>
  66  * The current DataHandler implementation creates a private
  67  * instance of URLDataSource when it is constructed with a URL.
  68  *
  69  * @see javax.activation.CommandMap
  70  * @see javax.activation.DataContentHandler
  71  * @see javax.activation.DataSource
  72  * @see javax.activation.URLDataSource
  73  *
  74  * @since 1.6
  75  */
  76 
  77 public class DataHandler implements Transferable {
  78 
  79     // Use the datasource to indicate whether we were started via the
  80     // DataSource constructor or the object constructor.
  81     private DataSource dataSource = null;


  88     private String objectMimeType = null;
  89 
  90     // Keep track of the CommandMap
  91     private CommandMap currentCommandMap = null;
  92 
  93     // our transfer flavors
  94     private static final DataFlavor emptyFlavors[] = new DataFlavor[0];
  95     private DataFlavor transferFlavors[] = emptyFlavors;
  96 
  97     // our DataContentHandler
  98     private DataContentHandler dataContentHandler = null;
  99     private DataContentHandler factoryDCH = null;
 100 
 101     // our DataContentHandlerFactory
 102     private static DataContentHandlerFactory factory = null;
 103     private DataContentHandlerFactory oldFactory = null;
 104     // the short representation of the ContentType (sans params)
 105     private String shortType = null;
 106 
 107     /**
 108      * Create a {@code DataHandler} instance referencing the
 109      * specified DataSource.  The data exists in a byte stream form.
 110      * The DataSource will provide an InputStream to access the data.
 111      *
 112      * @param ds        the DataSource
 113      */
 114     public DataHandler(DataSource ds) {
 115         // save a reference to the incoming DS
 116         dataSource = ds;
 117         oldFactory = factory; // keep track of the factory
 118     }
 119 
 120     /**
 121      * Create a {@code DataHandler} instance representing an object
 122      * of this MIME type.  This constructor is
 123      * used when the application already has an in-memory representation
 124      * of the data in the form of a Java Object.
 125      *
 126      * @param obj       the Java Object
 127      * @param mimeType  the MIME type of the object
 128      */
 129     public DataHandler(Object obj, String mimeType) {
 130         object = obj;
 131         objectMimeType = mimeType;
 132         oldFactory = factory; // keep track of the factory
 133     }
 134 
 135     /**
 136      * Create a {@code DataHandler} instance referencing a URL.
 137      * The DataHandler internally creates a {@code URLDataSource}
 138      * instance to represent the URL.
 139      *
 140      * @param url       a URL object
 141      */
 142     public DataHandler(URL url) {
 143         dataSource = new URLDataSource(url);
 144         oldFactory = factory; // keep track of the factory
 145     }
 146 
 147     /**
 148      * Return the CommandMap for this instance of DataHandler.
 149      */
 150     private synchronized CommandMap getCommandMap() {
 151         if (currentCommandMap != null)
 152             return currentCommandMap;
 153         else
 154             return CommandMap.getDefaultCommandMap();
 155     }
 156 
 157     /**


 164      * constructs a DataSource from the data used to construct
 165      * the DataHandler. DataSources created for DataHandlers <b>not</b>
 166      * instantiated with a DataSource are cached for performance
 167      * reasons.
 168      *
 169      * @return  a valid DataSource object for this DataHandler
 170      */
 171     public DataSource getDataSource() {
 172         if (dataSource == null) {
 173             // create one on the fly
 174             if (objDataSource == null)
 175                 objDataSource = new DataHandlerDataSource(this);
 176             return objDataSource;
 177         }
 178         return dataSource;
 179     }
 180 
 181     /**
 182      * Return the name of the data object. If this DataHandler
 183      * was created with a DataSource, this method calls through
 184      * to the {@code DataSource.getName} method, otherwise it
 185      * returns <i>null</i>.
 186      *
 187      * @return  the name of the object
 188      */
 189     public String getName() {
 190         if (dataSource != null)
 191             return dataSource.getName();
 192         else
 193             return null;
 194     }
 195 
 196     /**
 197      * Return the MIME type of this object as retrieved from
 198      * the source object. Note that this is the <i>full</i>
 199      * type with parameters.
 200      *
 201      * @return  the MIME type
 202      */
 203     public String getContentType() {
 204         if (dataSource != null) // data source case
 205             return dataSource.getContentType();
 206         else
 207             return objectMimeType; // obj/type case
 208     }
 209 
 210     /**
 211      * Get the InputStream for this object. <p>
 212      *
 213      * For DataHandlers instantiated with a DataSource, the DataHandler
 214      * calls the {@code DataSource.getInputStream} method and
 215      * returns the result to the caller.
 216      * <p>
 217      * For DataHandlers instantiated with an Object, the DataHandler
 218      * first attempts to find a DataContentHandler for the Object. If
 219      * the DataHandler can not find a DataContentHandler for this MIME
 220      * type, it throws an UnsupportedDataTypeException.  If it is
 221      * successful, it creates a pipe and a thread.  The thread uses the
 222      * DataContentHandler's {@code writeTo} method to write the
 223      * stream data into one end of the pipe.  The other end of the pipe
 224      * is returned to the caller.  Because a thread is created to copy
 225      * the data, IOExceptions that may occur during the copy can not be
 226      * propagated back to the caller. The result is an empty stream.
 227      *
 228      * @return  the InputStream representing this data
 229      * @exception IOException   if an I/O error occurs
 230      *
 231      * @see javax.activation.DataContentHandler#writeTo
 232      * @see javax.activation.UnsupportedDataTypeException
 233      */
 234     public InputStream getInputStream() throws IOException {
 235         InputStream ins = null;
 236 
 237         if (dataSource != null) {
 238             ins = dataSource.getInputStream();
 239         } else {
 240             DataContentHandler dch = getDataContentHandler();
 241             // we won't even try if we can't get a dch
 242             if (dch == null)
 243                 throw new UnsupportedDataTypeException(
 244                                 "no DCH for MIME type " + getBaseType());
 245 
 246             if (dch instanceof ObjectDataContentHandler) {


 264                 public void run() {
 265                     try {
 266                         fdch.writeTo(object, objectMimeType, pos);
 267                     } catch (IOException e) {
 268 
 269                     } finally {
 270                         try {
 271                             pos.close();
 272                         } catch (IOException ie) { }
 273                     }
 274                 }
 275             },
 276                       "DataHandler.getInputStream").start();
 277             ins = pin;
 278         }
 279 
 280         return ins;
 281     }
 282 
 283     /**
 284      * Write the data to an {@code OutputStream}.<p>
 285      *
 286      * If the DataHandler was created with a DataSource, writeTo
 287      * retrieves the InputStream and copies the bytes from the
 288      * InputStream to the OutputStream passed in.
 289      * <p>
 290      * If the DataHandler was created with an object, writeTo
 291      * retrieves the DataContentHandler for the object's type.
 292      * If the DataContentHandler was found, it calls the
 293      * {@code writeTo} method on the {@code DataContentHandler}.
 294      *
 295      * @param os        the OutputStream to write to
 296      * @exception IOException   if an I/O error occurs
 297      */
 298     public void writeTo(OutputStream os) throws IOException {
 299         // for the DataSource case
 300         if (dataSource != null) {
 301             InputStream is = null;
 302             byte data[] = new byte[8*1024];
 303             int bytes_read;
 304 
 305             is = dataSource.getInputStream();
 306 
 307             try {
 308                 while ((bytes_read = is.read(data)) > 0) {
 309                     os.write(data, 0, bytes_read);
 310                 }
 311             } finally {
 312                 is.close();
 313                 is = null;
 314             }
 315         } else { // for the Object case
 316             DataContentHandler dch = getDataContentHandler();
 317             dch.writeTo(object, objectMimeType, os);
 318         }
 319     }
 320 
 321     /**
 322      * Get an OutputStream for this DataHandler to allow overwriting
 323      * the underlying data.
 324      * If the DataHandler was created with a DataSource, the
 325      * DataSource's {@code getOutputStream} method is called.
 326      * Otherwise, {@code null} is returned.
 327      *
 328      * @return the OutputStream
 329      *
 330      * @see javax.activation.DataSource#getOutputStream
 331      * @see javax.activation.URLDataSource
 332      */
 333     public OutputStream getOutputStream() throws IOException {
 334         if (dataSource != null)
 335             return dataSource.getOutputStream();
 336         else
 337             return null;
 338     }
 339 
 340     /**
 341      * Return the DataFlavors in which this data is available. <p>
 342      *
 343      * Returns an array of DataFlavor objects indicating the flavors
 344      * the data can be provided in. The array is usually ordered
 345      * according to preference for providing the data, from most
 346      * richly descriptive to least richly descriptive.<p>
 347      *
 348      * The DataHandler attempts to find a DataContentHandler that
 349      * corresponds to the MIME type of the data. If one is located,
 350      * the DataHandler calls the DataContentHandler's
 351      * {@code getTransferDataFlavors} method. <p>
 352      *
 353      * If a DataContentHandler can <i>not</i> be located, and if the
 354      * DataHandler was created with a DataSource (or URL), one
 355      * DataFlavor is returned that represents this object's MIME type
 356      * and the {@code java.io.InputStream} class.  If the
 357      * DataHandler was created with an object and a MIME type,
 358      * getTransferDataFlavors returns one DataFlavor that represents
 359      * this object's MIME type and the object's class.
 360      *
 361      * @return  an array of data flavors in which this data can be transferred
 362      * @see javax.activation.DataContentHandler#getTransferDataFlavors
 363      */
 364     public synchronized DataFlavor[] getTransferDataFlavors() {
 365         if (factory != oldFactory) // if the factory has changed, clear cache
 366             transferFlavors = emptyFlavors;
 367 
 368         // if it's not set, set it...
 369         if (transferFlavors == emptyFlavors)
 370             transferFlavors = getDataContentHandler().getTransferDataFlavors();
 371 
 372         if (transferFlavors == emptyFlavors)
 373             return transferFlavors;
 374         else
 375             return transferFlavors.clone();
 376 
 377     }
 378 
 379     /**
 380      * Returns whether the specified data flavor is supported
 381      * for this object.<p>
 382      *
 383      * This method iterates through the DataFlavors returned from
 384      * {@code getTransferDataFlavors}, comparing each with
 385      * the specified flavor.
 386      *
 387      * @param flavor    the requested flavor for the data
 388      * @return          true if the data flavor is supported
 389      * @see javax.activation.DataHandler#getTransferDataFlavors
 390      */
 391     public boolean isDataFlavorSupported(DataFlavor flavor) {
 392         DataFlavor[] lFlavors = getTransferDataFlavors();
 393 
 394         for (int i = 0; i < lFlavors.length; i++) {
 395             if (lFlavors[i].equals(flavor))
 396                 return true;
 397         }
 398         return false;
 399     }
 400 
 401     /**
 402      * Returns an object that represents the data to be
 403      * transferred. The class of the object returned is defined by the
 404      * representation class of the data flavor.<p>
 405      *
 406      * <b>For DataHandler's created with DataSources or URLs:</b><p>
 407      *
 408      * The DataHandler attempts to locate a DataContentHandler
 409      * for this MIME type. If one is found, the passed in DataFlavor
 410      * and the type of the data are passed to its {@code getTransferData}
 411      * method. If the DataHandler fails to locate a DataContentHandler
 412      * and the flavor specifies this object's MIME type and the
 413      * {@code java.io.InputStream} class, this object's InputStream
 414      * is returned.
 415      * Otherwise it throws an UnsupportedFlavorException. <p>
 416      *
 417      * <b>For DataHandler's created with Objects:</b><p>
 418      *
 419      * The DataHandler attempts to locate a DataContentHandler
 420      * for this MIME type. If one is found, the passed in DataFlavor
 421      * and the type of the data are passed to its getTransferData
 422      * method. If the DataHandler fails to locate a DataContentHandler
 423      * and the flavor specifies this object's MIME type and its class,
 424      * this DataHandler's referenced object is returned.
 425      * Otherwise it throws an UnsupportedFlavorException.
 426      *
 427      * @param flavor    the requested flavor for the data
 428      * @return          the object
 429      * @exception UnsupportedFlavorException    if the data could not be
 430      *                  converted to the requested flavor
 431      * @exception IOException   if an I/O error occurs
 432      * @see javax.activation.ActivationDataFlavor
 433      */
 434     public Object getTransferData(DataFlavor flavor)
 435                                 throws UnsupportedFlavorException, IOException {
 436         return getDataContentHandler().getTransferData(flavor, dataSource);
 437     }
 438 
 439     /**
 440      * Set the CommandMap for use by this DataHandler.
 441      * Setting it to {@code null} causes the CommandMap to revert
 442      * to the CommandMap returned by the
 443      * {@code CommandMap.getDefaultCommandMap} method.
 444      * Changing the CommandMap, or setting it to {@code null},
 445      * clears out any data cached from the previous CommandMap.
 446      *
 447      * @param commandMap        the CommandMap to use in this DataHandler
 448      *
 449      * @see javax.activation.CommandMap#setDefaultCommandMap
 450      */
 451     public synchronized void setCommandMap(CommandMap commandMap) {
 452         if (commandMap != currentCommandMap || commandMap == null) {
 453             // clear cached values...
 454             transferFlavors = emptyFlavors;
 455             dataContentHandler = null;
 456 
 457             currentCommandMap = commandMap;
 458         }
 459     }
 460 
 461     /**
 462      * Return the <i>preferred</i> commands for this type of data.
 463      * This method calls the {@code getPreferredCommands} method
 464      * in the CommandMap associated with this instance of DataHandler.
 465      * This method returns an array that represents a subset of
 466      * available commands. In cases where multiple commands for the
 467      * MIME type represented by this DataHandler are present, the
 468      * installed CommandMap chooses the appropriate commands.
 469      *
 470      * @return  the CommandInfo objects representing the preferred commands
 471      *
 472      * @see javax.activation.CommandMap#getPreferredCommands
 473      */
 474     public CommandInfo[] getPreferredCommands() {
 475         if (dataSource != null)
 476             return getCommandMap().getPreferredCommands(getBaseType(),
 477                                                         dataSource);
 478         else
 479             return getCommandMap().getPreferredCommands(getBaseType());
 480     }
 481 
 482     /**
 483      * Return all the commands for this type of data.
 484      * This method returns an array containing all commands
 485      * for the type of data represented by this DataHandler. The
 486      * MIME type for the underlying data represented by this DataHandler
 487      * is used to call through to the {@code getAllCommands} method
 488      * of the CommandMap associated with this DataHandler.
 489      *
 490      * @return  the CommandInfo objects representing all the commands
 491      *
 492      * @see javax.activation.CommandMap#getAllCommands
 493      */
 494     public CommandInfo[] getAllCommands() {
 495         if (dataSource != null)
 496             return getCommandMap().getAllCommands(getBaseType(), dataSource);
 497         else
 498             return getCommandMap().getAllCommands(getBaseType());
 499     }
 500 
 501     /**
 502      * Get the command <i>cmdName</i>. Use the search semantics as
 503      * defined by the CommandMap installed in this DataHandler. The
 504      * MIME type for the underlying data represented by this DataHandler
 505      * is used to call through to the {@code getCommand} method
 506      * of the CommandMap associated with this DataHandler.
 507      *
 508      * @param cmdName   the command name
 509      * @return  the CommandInfo corresponding to the command
 510      *
 511      * @see javax.activation.CommandMap#getCommand
 512      */
 513     public CommandInfo getCommand(String cmdName) {
 514         if (dataSource != null)
 515             return getCommandMap().getCommand(getBaseType(), cmdName,
 516                                                                 dataSource);
 517         else
 518             return getCommandMap().getCommand(getBaseType(), cmdName);
 519     }
 520 
 521     /**
 522      * Return the data in its preferred Object form. <p>
 523      *
 524      * If the DataHandler was instantiated with an object, return
 525      * the object. <p>
 526      *
 527      * If the DataHandler was instantiated with a DataSource,
 528      * this method uses a DataContentHandler to return the content
 529      * object for the data represented by this DataHandler. If no
 530      * {@code DataContentHandler} can be found for the
 531      * the type of this data, the DataHandler returns an
 532      * InputStream for the data.
 533      *
 534      * @return the content.
 535      * @exception IOException if an IOException occurs during
 536      *                              this operation.
 537      */
 538     public Object getContent() throws IOException {
 539         if (object != null)
 540             return object;
 541         else
 542             return getDataContentHandler().getContent(getDataSource());
 543     }
 544 
 545     /**
 546      * A convenience method that takes a CommandInfo object
 547      * and instantiates the corresponding command, usually
 548      * a JavaBean component.
 549      * <p>
 550      * This method calls the CommandInfo's {@code getCommandObject}
 551      * method with the {@code ClassLoader} used to load
 552      * the {@code javax.activation.DataHandler} class itself.
 553      *
 554      * @param cmdinfo   the CommandInfo corresponding to a command
 555      * @return  the instantiated command object
 556      */
 557     public Object getBean(CommandInfo cmdinfo) {
 558         Object bean = null;
 559 
 560         try {
 561             // make the bean
 562             ClassLoader cld = null;
 563             // First try the "application's" class loader.
 564             cld = SecuritySupport.getContextClassLoader();
 565             if (cld == null)
 566                 cld = this.getClass().getClassLoader();
 567             bean = cmdinfo.getCommandObject(this, cld);
 568         } catch (IOException e) {
 569         } catch (ClassNotFoundException e) { }
 570 
 571         return bean;
 572     }


 684         factory = newFactory;
 685     }
 686 }
 687 
 688 /**
 689  * The DataHanderDataSource class implements the
 690  * DataSource interface when the DataHandler is constructed
 691  * with an Object and a mimeType string.
 692  */
 693 class DataHandlerDataSource implements DataSource {
 694     DataHandler dataHandler = null;
 695 
 696     /**
 697      * The constructor.
 698      */
 699     public DataHandlerDataSource(DataHandler dh) {
 700         this.dataHandler = dh;
 701     }
 702 
 703     /**
 704      * Returns an {@code InputStream} representing this object.
 705      * @return  the {@code InputStream}
 706      */
 707     public InputStream getInputStream() throws IOException {
 708         return dataHandler.getInputStream();
 709     }
 710 
 711     /**
 712      * Returns the {@code OutputStream} for this object.
 713      * @return  the {@code OutputStream}
 714      */
 715     public OutputStream getOutputStream() throws IOException {
 716         return dataHandler.getOutputStream();
 717     }
 718 
 719     /**
 720      * Returns the MIME type of the data represented by this object.
 721      * @return  the MIME type
 722      */
 723     public String getContentType() {
 724         return dataHandler.getContentType();
 725     }
 726 
 727     /**
 728      * Returns the name of this object.
 729      * @return  the name of this object
 730      */
 731     public String getName() {
 732         return dataHandler.getName(); // what else would it be?
 733     }


 737  * DataSourceDataContentHandler
 738  *
 739  * This is a <i>private</i> DataContentHandler that wraps the real
 740  * DataContentHandler in the case where the DataHandler was instantiated
 741  * with a DataSource.
 742  */
 743 class DataSourceDataContentHandler implements DataContentHandler {
 744     private DataSource ds = null;
 745     private DataFlavor transferFlavors[] = null;
 746     private DataContentHandler dch = null;
 747 
 748     /**
 749      * The constructor.
 750      */
 751     public DataSourceDataContentHandler(DataContentHandler dch, DataSource ds) {
 752         this.ds = ds;
 753         this.dch = dch;
 754     }
 755 
 756     /**
 757      * Return the DataFlavors for this {@code DataContentHandler}.
 758      * @return  the DataFlavors
 759      */
 760     public DataFlavor[] getTransferDataFlavors() {
 761 
 762         if (transferFlavors == null) {
 763             if (dch != null) { // is there a dch?
 764                 transferFlavors = dch.getTransferDataFlavors();
 765             } else {
 766                 transferFlavors = new DataFlavor[1];
 767                 transferFlavors[0] =
 768                     new ActivationDataFlavor(ds.getContentType(),
 769                                              ds.getContentType());
 770             }
 771         }
 772         return transferFlavors;
 773     }
 774 
 775     /**
 776      * Return the Transfer Data of type DataFlavor from InputStream.
 777      * @param df        the DataFlavor


 825 
 826     /**
 827      * The constructor.
 828      */
 829     public ObjectDataContentHandler(DataContentHandler dch,
 830                                     Object obj, String mimeType) {
 831         this.obj = obj;
 832         this.mimeType = mimeType;
 833         this.dch = dch;
 834     }
 835 
 836     /**
 837      * Return the DataContentHandler for this object.
 838      * Used only by the DataHandler class.
 839      */
 840     public DataContentHandler getDCH() {
 841         return dch;
 842     }
 843 
 844     /**
 845      * Return the DataFlavors for this {@code DataContentHandler}.
 846      * @return  the DataFlavors
 847      */
 848     public synchronized DataFlavor[] getTransferDataFlavors() {
 849         if (transferFlavors == null) {
 850             if (dch != null) {
 851                 transferFlavors = dch.getTransferDataFlavors();
 852             } else {
 853                 transferFlavors = new DataFlavor[1];
 854                 transferFlavors[0] = new ActivationDataFlavor(obj.getClass(),
 855                                              mimeType, mimeType);
 856             }
 857         }
 858         return transferFlavors;
 859     }
 860 
 861     /**
 862      * Return the Transfer Data of type DataFlavor from InputStream.
 863      * @param df        the DataFlavor
 864      * @param ds        the DataSource
 865      * @return          the constructed Object


< prev index next >