1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaf_classes/javax/activation/DataHandler.java Wed Apr 27 01:27:09 2016 +0800 1.3 @@ -0,0 +1,899 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package javax.activation; 1.30 + 1.31 +import java.io.InputStream; 1.32 +import java.io.IOException; 1.33 +import java.io.OutputStream; 1.34 +import java.io.PipedInputStream; 1.35 +import java.io.PipedOutputStream; 1.36 +import java.io.OutputStreamWriter; 1.37 +import java.net.URL; 1.38 +import java.awt.datatransfer.Transferable; 1.39 +import java.awt.datatransfer.DataFlavor; 1.40 +import java.awt.datatransfer.UnsupportedFlavorException; 1.41 + 1.42 +/** 1.43 + * The DataHandler class provides a consistent interface to data 1.44 + * available in many different sources and formats. 1.45 + * It manages simple stream to string conversions and related operations 1.46 + * using DataContentHandlers. 1.47 + * It provides access to commands that can operate on the data. 1.48 + * The commands are found using a CommandMap. <p> 1.49 + * 1.50 + * <b>DataHandler and the Transferable Interface</b><p> 1.51 + * DataHandler implements the Transferable interface so that data can 1.52 + * be used in AWT data transfer operations, such as cut and paste and 1.53 + * drag and drop. The implementation of the Transferable interface 1.54 + * relies on the availability of an installed DataContentHandler 1.55 + * object corresponding to the MIME type of the data represented in 1.56 + * the specific instance of the DataHandler.<p> 1.57 + * 1.58 + * <b>DataHandler and CommandMaps</b><p> 1.59 + * The DataHandler keeps track of the current CommandMap that it uses to 1.60 + * service requests for commands (<code>getCommand</code>, 1.61 + * <code>getAllCommands</code>, <code>getPreferredCommands</code>). 1.62 + * Each instance of a DataHandler may have a CommandMap associated with 1.63 + * it using the <code>setCommandMap</code> method. If a CommandMap was 1.64 + * not set, DataHandler calls the <code>getDefaultCommandMap</code> 1.65 + * method in CommandMap and uses the value it returns. See 1.66 + * <i>CommandMap</i> for more information. <p> 1.67 + * 1.68 + * <b>DataHandler and URLs</b><p> 1.69 + * The current DataHandler implementation creates a private 1.70 + * instance of URLDataSource when it is constructed with a URL. 1.71 + * 1.72 + * @see javax.activation.CommandMap 1.73 + * @see javax.activation.DataContentHandler 1.74 + * @see javax.activation.DataSource 1.75 + * @see javax.activation.URLDataSource 1.76 + * 1.77 + * @since 1.6 1.78 + */ 1.79 + 1.80 +public class DataHandler implements Transferable { 1.81 + 1.82 + // Use the datasource to indicate whether we were started via the 1.83 + // DataSource constructor or the object constructor. 1.84 + private DataSource dataSource = null; 1.85 + private DataSource objDataSource = null; 1.86 + 1.87 + // The Object and mimetype from the constructor (if passed in). 1.88 + // object remains null if it was instantiated with a 1.89 + // DataSource. 1.90 + private Object object = null; 1.91 + private String objectMimeType = null; 1.92 + 1.93 + // Keep track of the CommandMap 1.94 + private CommandMap currentCommandMap = null; 1.95 + 1.96 + // our transfer flavors 1.97 + private static final DataFlavor emptyFlavors[] = new DataFlavor[0]; 1.98 + private DataFlavor transferFlavors[] = emptyFlavors; 1.99 + 1.100 + // our DataContentHandler 1.101 + private DataContentHandler dataContentHandler = null; 1.102 + private DataContentHandler factoryDCH = null; 1.103 + 1.104 + // our DataContentHandlerFactory 1.105 + private static DataContentHandlerFactory factory = null; 1.106 + private DataContentHandlerFactory oldFactory = null; 1.107 + // the short representation of the ContentType (sans params) 1.108 + private String shortType = null; 1.109 + 1.110 + /** 1.111 + * Create a <code>DataHandler</code> instance referencing the 1.112 + * specified DataSource. The data exists in a byte stream form. 1.113 + * The DataSource will provide an InputStream to access the data. 1.114 + * 1.115 + * @param ds the DataSource 1.116 + */ 1.117 + public DataHandler(DataSource ds) { 1.118 + // save a reference to the incoming DS 1.119 + dataSource = ds; 1.120 + oldFactory = factory; // keep track of the factory 1.121 + } 1.122 + 1.123 + /** 1.124 + * Create a <code>DataHandler</code> instance representing an object 1.125 + * of this MIME type. This constructor is 1.126 + * used when the application already has an in-memory representation 1.127 + * of the data in the form of a Java Object. 1.128 + * 1.129 + * @param obj the Java Object 1.130 + * @param mimeType the MIME type of the object 1.131 + */ 1.132 + public DataHandler(Object obj, String mimeType) { 1.133 + object = obj; 1.134 + objectMimeType = mimeType; 1.135 + oldFactory = factory; // keep track of the factory 1.136 + } 1.137 + 1.138 + /** 1.139 + * Create a <code>DataHandler</code> instance referencing a URL. 1.140 + * The DataHandler internally creates a <code>URLDataSource</code> 1.141 + * instance to represent the URL. 1.142 + * 1.143 + * @param url a URL object 1.144 + */ 1.145 + public DataHandler(URL url) { 1.146 + dataSource = new URLDataSource(url); 1.147 + oldFactory = factory; // keep track of the factory 1.148 + } 1.149 + 1.150 + /** 1.151 + * Return the CommandMap for this instance of DataHandler. 1.152 + */ 1.153 + private synchronized CommandMap getCommandMap() { 1.154 + if (currentCommandMap != null) 1.155 + return currentCommandMap; 1.156 + else 1.157 + return CommandMap.getDefaultCommandMap(); 1.158 + } 1.159 + 1.160 + /** 1.161 + * Return the DataSource associated with this instance 1.162 + * of DataHandler. 1.163 + * <p> 1.164 + * For DataHandlers that have been instantiated with a DataSource, 1.165 + * this method returns the DataSource that was used to create the 1.166 + * DataHandler object. In other cases the DataHandler 1.167 + * constructs a DataSource from the data used to construct 1.168 + * the DataHandler. DataSources created for DataHandlers <b>not</b> 1.169 + * instantiated with a DataSource are cached for performance 1.170 + * reasons. 1.171 + * 1.172 + * @return a valid DataSource object for this DataHandler 1.173 + */ 1.174 + public DataSource getDataSource() { 1.175 + if (dataSource == null) { 1.176 + // create one on the fly 1.177 + if (objDataSource == null) 1.178 + objDataSource = new DataHandlerDataSource(this); 1.179 + return objDataSource; 1.180 + } 1.181 + return dataSource; 1.182 + } 1.183 + 1.184 + /** 1.185 + * Return the name of the data object. If this DataHandler 1.186 + * was created with a DataSource, this method calls through 1.187 + * to the <code>DataSource.getName</code> method, otherwise it 1.188 + * returns <i>null</i>. 1.189 + * 1.190 + * @return the name of the object 1.191 + */ 1.192 + public String getName() { 1.193 + if (dataSource != null) 1.194 + return dataSource.getName(); 1.195 + else 1.196 + return null; 1.197 + } 1.198 + 1.199 + /** 1.200 + * Return the MIME type of this object as retrieved from 1.201 + * the source object. Note that this is the <i>full</i> 1.202 + * type with parameters. 1.203 + * 1.204 + * @return the MIME type 1.205 + */ 1.206 + public String getContentType() { 1.207 + if (dataSource != null) // data source case 1.208 + return dataSource.getContentType(); 1.209 + else 1.210 + return objectMimeType; // obj/type case 1.211 + } 1.212 + 1.213 + /** 1.214 + * Get the InputStream for this object. <p> 1.215 + * 1.216 + * For DataHandlers instantiated with a DataSource, the DataHandler 1.217 + * calls the <code>DataSource.getInputStream</code> method and 1.218 + * returns the result to the caller. 1.219 + * <p> 1.220 + * For DataHandlers instantiated with an Object, the DataHandler 1.221 + * first attempts to find a DataContentHandler for the Object. If 1.222 + * the DataHandler can not find a DataContentHandler for this MIME 1.223 + * type, it throws an UnsupportedDataTypeException. If it is 1.224 + * successful, it creates a pipe and a thread. The thread uses the 1.225 + * DataContentHandler's <code>writeTo</code> method to write the 1.226 + * stream data into one end of the pipe. The other end of the pipe 1.227 + * is returned to the caller. Because a thread is created to copy 1.228 + * the data, IOExceptions that may occur during the copy can not be 1.229 + * propagated back to the caller. The result is an empty stream.<p> 1.230 + * 1.231 + * @return the InputStream representing this data 1.232 + * @exception IOException if an I/O error occurs 1.233 + * 1.234 + * @see javax.activation.DataContentHandler#writeTo 1.235 + * @see javax.activation.UnsupportedDataTypeException 1.236 + */ 1.237 + public InputStream getInputStream() throws IOException { 1.238 + InputStream ins = null; 1.239 + 1.240 + if (dataSource != null) { 1.241 + ins = dataSource.getInputStream(); 1.242 + } else { 1.243 + DataContentHandler dch = getDataContentHandler(); 1.244 + // we won't even try if we can't get a dch 1.245 + if (dch == null) 1.246 + throw new UnsupportedDataTypeException( 1.247 + "no DCH for MIME type " + getBaseType()); 1.248 + 1.249 + if (dch instanceof ObjectDataContentHandler) { 1.250 + if (((ObjectDataContentHandler)dch).getDCH() == null) 1.251 + throw new UnsupportedDataTypeException( 1.252 + "no object DCH for MIME type " + getBaseType()); 1.253 + } 1.254 + // there is none but the default^^^^^^^^^^^^^^^^ 1.255 + final DataContentHandler fdch = dch; 1.256 + 1.257 + // from bill s. 1.258 + // ce n'est pas une pipe! 1.259 + // 1.260 + // NOTE: This block of code needs to throw exceptions, but 1.261 + // can't because it is in another thread!!! ARG! 1.262 + // 1.263 + final PipedOutputStream pos = new PipedOutputStream(); 1.264 + PipedInputStream pin = new PipedInputStream(pos); 1.265 + new Thread( 1.266 + new Runnable() { 1.267 + public void run() { 1.268 + try { 1.269 + fdch.writeTo(object, objectMimeType, pos); 1.270 + } catch (IOException e) { 1.271 + 1.272 + } finally { 1.273 + try { 1.274 + pos.close(); 1.275 + } catch (IOException ie) { } 1.276 + } 1.277 + } 1.278 + }, 1.279 + "DataHandler.getInputStream").start(); 1.280 + ins = pin; 1.281 + } 1.282 + 1.283 + return ins; 1.284 + } 1.285 + 1.286 + /** 1.287 + * Write the data to an <code>OutputStream</code>.<p> 1.288 + * 1.289 + * If the DataHandler was created with a DataSource, writeTo 1.290 + * retrieves the InputStream and copies the bytes from the 1.291 + * InputStream to the OutputStream passed in. 1.292 + * <p> 1.293 + * If the DataHandler was created with an object, writeTo 1.294 + * retrieves the DataContentHandler for the object's type. 1.295 + * If the DataContentHandler was found, it calls the 1.296 + * <code>writeTo</code> method on the <code>DataContentHandler</code>. 1.297 + * 1.298 + * @param os the OutputStream to write to 1.299 + * @exception IOException if an I/O error occurs 1.300 + */ 1.301 + public void writeTo(OutputStream os) throws IOException { 1.302 + // for the DataSource case 1.303 + if (dataSource != null) { 1.304 + InputStream is = null; 1.305 + byte data[] = new byte[8*1024]; 1.306 + int bytes_read; 1.307 + 1.308 + is = dataSource.getInputStream(); 1.309 + 1.310 + try { 1.311 + while ((bytes_read = is.read(data)) > 0) { 1.312 + os.write(data, 0, bytes_read); 1.313 + } 1.314 + } finally { 1.315 + is.close(); 1.316 + is = null; 1.317 + } 1.318 + } else { // for the Object case 1.319 + DataContentHandler dch = getDataContentHandler(); 1.320 + dch.writeTo(object, objectMimeType, os); 1.321 + } 1.322 + } 1.323 + 1.324 + /** 1.325 + * Get an OutputStream for this DataHandler to allow overwriting 1.326 + * the underlying data. 1.327 + * If the DataHandler was created with a DataSource, the 1.328 + * DataSource's <code>getOutputStream</code> method is called. 1.329 + * Otherwise, <code>null</code> is returned. 1.330 + * 1.331 + * @return the OutputStream 1.332 + * 1.333 + * @see javax.activation.DataSource#getOutputStream 1.334 + * @see javax.activation.URLDataSource 1.335 + */ 1.336 + public OutputStream getOutputStream() throws IOException { 1.337 + if (dataSource != null) 1.338 + return dataSource.getOutputStream(); 1.339 + else 1.340 + return null; 1.341 + } 1.342 + 1.343 + /** 1.344 + * Return the DataFlavors in which this data is available. <p> 1.345 + * 1.346 + * Returns an array of DataFlavor objects indicating the flavors 1.347 + * the data can be provided in. The array is usually ordered 1.348 + * according to preference for providing the data, from most 1.349 + * richly descriptive to least richly descriptive.<p> 1.350 + * 1.351 + * The DataHandler attempts to find a DataContentHandler that 1.352 + * corresponds to the MIME type of the data. If one is located, 1.353 + * the DataHandler calls the DataContentHandler's 1.354 + * <code>getTransferDataFlavors</code> method. <p> 1.355 + * 1.356 + * If a DataContentHandler can <i>not</i> be located, and if the 1.357 + * DataHandler was created with a DataSource (or URL), one 1.358 + * DataFlavor is returned that represents this object's MIME type 1.359 + * and the <code>java.io.InputStream</code> class. If the 1.360 + * DataHandler was created with an object and a MIME type, 1.361 + * getTransferDataFlavors returns one DataFlavor that represents 1.362 + * this object's MIME type and the object's class. 1.363 + * 1.364 + * @return an array of data flavors in which this data can be transferred 1.365 + * @see javax.activation.DataContentHandler#getTransferDataFlavors 1.366 + */ 1.367 + public synchronized DataFlavor[] getTransferDataFlavors() { 1.368 + if (factory != oldFactory) // if the factory has changed, clear cache 1.369 + transferFlavors = emptyFlavors; 1.370 + 1.371 + // if it's not set, set it... 1.372 + if (transferFlavors == emptyFlavors) 1.373 + transferFlavors = getDataContentHandler().getTransferDataFlavors(); 1.374 + 1.375 + if (transferFlavors == emptyFlavors) 1.376 + return transferFlavors; 1.377 + else 1.378 + return transferFlavors.clone(); 1.379 + 1.380 + } 1.381 + 1.382 + /** 1.383 + * Returns whether the specified data flavor is supported 1.384 + * for this object.<p> 1.385 + * 1.386 + * This method iterates through the DataFlavors returned from 1.387 + * <code>getTransferDataFlavors</code>, comparing each with 1.388 + * the specified flavor. 1.389 + * 1.390 + * @param flavor the requested flavor for the data 1.391 + * @return true if the data flavor is supported 1.392 + * @see javax.activation.DataHandler#getTransferDataFlavors 1.393 + */ 1.394 + public boolean isDataFlavorSupported(DataFlavor flavor) { 1.395 + DataFlavor[] lFlavors = getTransferDataFlavors(); 1.396 + 1.397 + for (int i = 0; i < lFlavors.length; i++) { 1.398 + if (lFlavors[i].equals(flavor)) 1.399 + return true; 1.400 + } 1.401 + return false; 1.402 + } 1.403 + 1.404 + /** 1.405 + * Returns an object that represents the data to be 1.406 + * transferred. The class of the object returned is defined by the 1.407 + * representation class of the data flavor.<p> 1.408 + * 1.409 + * <b>For DataHandler's created with DataSources or URLs:</b><p> 1.410 + * 1.411 + * The DataHandler attempts to locate a DataContentHandler 1.412 + * for this MIME type. If one is found, the passed in DataFlavor 1.413 + * and the type of the data are passed to its <code>getTransferData</code> 1.414 + * method. If the DataHandler fails to locate a DataContentHandler 1.415 + * and the flavor specifies this object's MIME type and the 1.416 + * <code>java.io.InputStream</code> class, this object's InputStream 1.417 + * is returned. 1.418 + * Otherwise it throws an UnsupportedFlavorException. <p> 1.419 + * 1.420 + * <b>For DataHandler's created with Objects:</b><p> 1.421 + * 1.422 + * The DataHandler attempts to locate a DataContentHandler 1.423 + * for this MIME type. If one is found, the passed in DataFlavor 1.424 + * and the type of the data are passed to its getTransferData 1.425 + * method. If the DataHandler fails to locate a DataContentHandler 1.426 + * and the flavor specifies this object's MIME type and its class, 1.427 + * this DataHandler's referenced object is returned. 1.428 + * Otherwise it throws an UnsupportedFlavorException. 1.429 + * 1.430 + * @param flavor the requested flavor for the data 1.431 + * @return the object 1.432 + * @exception UnsupportedFlavorException if the data could not be 1.433 + * converted to the requested flavor 1.434 + * @exception IOException if an I/O error occurs 1.435 + * @see javax.activation.ActivationDataFlavor 1.436 + */ 1.437 + public Object getTransferData(DataFlavor flavor) 1.438 + throws UnsupportedFlavorException, IOException { 1.439 + return getDataContentHandler().getTransferData(flavor, dataSource); 1.440 + } 1.441 + 1.442 + /** 1.443 + * Set the CommandMap for use by this DataHandler. 1.444 + * Setting it to <code>null</code> causes the CommandMap to revert 1.445 + * to the CommandMap returned by the 1.446 + * <code>CommandMap.getDefaultCommandMap</code> method. 1.447 + * Changing the CommandMap, or setting it to <code>null</code>, 1.448 + * clears out any data cached from the previous CommandMap. 1.449 + * 1.450 + * @param commandMap the CommandMap to use in this DataHandler 1.451 + * 1.452 + * @see javax.activation.CommandMap#setDefaultCommandMap 1.453 + */ 1.454 + public synchronized void setCommandMap(CommandMap commandMap) { 1.455 + if (commandMap != currentCommandMap || commandMap == null) { 1.456 + // clear cached values... 1.457 + transferFlavors = emptyFlavors; 1.458 + dataContentHandler = null; 1.459 + 1.460 + currentCommandMap = commandMap; 1.461 + } 1.462 + } 1.463 + 1.464 + /** 1.465 + * Return the <i>preferred</i> commands for this type of data. 1.466 + * This method calls the <code>getPreferredCommands</code> method 1.467 + * in the CommandMap associated with this instance of DataHandler. 1.468 + * This method returns an array that represents a subset of 1.469 + * available commands. In cases where multiple commands for the 1.470 + * MIME type represented by this DataHandler are present, the 1.471 + * installed CommandMap chooses the appropriate commands. 1.472 + * 1.473 + * @return the CommandInfo objects representing the preferred commands 1.474 + * 1.475 + * @see javax.activation.CommandMap#getPreferredCommands 1.476 + */ 1.477 + public CommandInfo[] getPreferredCommands() { 1.478 + if (dataSource != null) 1.479 + return getCommandMap().getPreferredCommands(getBaseType(), 1.480 + dataSource); 1.481 + else 1.482 + return getCommandMap().getPreferredCommands(getBaseType()); 1.483 + } 1.484 + 1.485 + /** 1.486 + * Return all the commands for this type of data. 1.487 + * This method returns an array containing all commands 1.488 + * for the type of data represented by this DataHandler. The 1.489 + * MIME type for the underlying data represented by this DataHandler 1.490 + * is used to call through to the <code>getAllCommands</code> method 1.491 + * of the CommandMap associated with this DataHandler. 1.492 + * 1.493 + * @return the CommandInfo objects representing all the commands 1.494 + * 1.495 + * @see javax.activation.CommandMap#getAllCommands 1.496 + */ 1.497 + public CommandInfo[] getAllCommands() { 1.498 + if (dataSource != null) 1.499 + return getCommandMap().getAllCommands(getBaseType(), dataSource); 1.500 + else 1.501 + return getCommandMap().getAllCommands(getBaseType()); 1.502 + } 1.503 + 1.504 + /** 1.505 + * Get the command <i>cmdName</i>. Use the search semantics as 1.506 + * defined by the CommandMap installed in this DataHandler. The 1.507 + * MIME type for the underlying data represented by this DataHandler 1.508 + * is used to call through to the <code>getCommand</code> method 1.509 + * of the CommandMap associated with this DataHandler. 1.510 + * 1.511 + * @param cmdName the command name 1.512 + * @return the CommandInfo corresponding to the command 1.513 + * 1.514 + * @see javax.activation.CommandMap#getCommand 1.515 + */ 1.516 + public CommandInfo getCommand(String cmdName) { 1.517 + if (dataSource != null) 1.518 + return getCommandMap().getCommand(getBaseType(), cmdName, 1.519 + dataSource); 1.520 + else 1.521 + return getCommandMap().getCommand(getBaseType(), cmdName); 1.522 + } 1.523 + 1.524 + /** 1.525 + * Return the data in its preferred Object form. <p> 1.526 + * 1.527 + * If the DataHandler was instantiated with an object, return 1.528 + * the object. <p> 1.529 + * 1.530 + * If the DataHandler was instantiated with a DataSource, 1.531 + * this method uses a DataContentHandler to return the content 1.532 + * object for the data represented by this DataHandler. If no 1.533 + * <code>DataContentHandler</code> can be found for the 1.534 + * the type of this data, the DataHandler returns an 1.535 + * InputStream for the data. 1.536 + * 1.537 + * @return the content. 1.538 + * @exception IOException if an IOException occurs during 1.539 + * this operation. 1.540 + */ 1.541 + public Object getContent() throws IOException { 1.542 + if (object != null) 1.543 + return object; 1.544 + else 1.545 + return getDataContentHandler().getContent(getDataSource()); 1.546 + } 1.547 + 1.548 + /** 1.549 + * A convenience method that takes a CommandInfo object 1.550 + * and instantiates the corresponding command, usually 1.551 + * a JavaBean component. 1.552 + * <p> 1.553 + * This method calls the CommandInfo's <code>getCommandObject</code> 1.554 + * method with the <code>ClassLoader</code> used to load 1.555 + * the <code>javax.activation.DataHandler</code> class itself. 1.556 + * 1.557 + * @param cmdinfo the CommandInfo corresponding to a command 1.558 + * @return the instantiated command object 1.559 + */ 1.560 + public Object getBean(CommandInfo cmdinfo) { 1.561 + Object bean = null; 1.562 + 1.563 + try { 1.564 + // make the bean 1.565 + ClassLoader cld = null; 1.566 + // First try the "application's" class loader. 1.567 + cld = SecuritySupport.getContextClassLoader(); 1.568 + if (cld == null) 1.569 + cld = this.getClass().getClassLoader(); 1.570 + bean = cmdinfo.getCommandObject(this, cld); 1.571 + } catch (IOException e) { 1.572 + } catch (ClassNotFoundException e) { } 1.573 + 1.574 + return bean; 1.575 + } 1.576 + 1.577 + /** 1.578 + * Get the DataContentHandler for this DataHandler: <p> 1.579 + * 1.580 + * If a DataContentHandlerFactory is set, use it. 1.581 + * Otherwise look for an object to serve DCH in the 1.582 + * following order: <p> 1.583 + * 1.584 + * 1) if a factory is set, use it <p> 1.585 + * 2) if a CommandMap is set, use it <p> 1.586 + * 3) use the default CommandMap <p> 1.587 + * 1.588 + * In any case, wrap the real DataContentHandler with one of our own 1.589 + * to handle any missing cases, fill in defaults, and to ensure that 1.590 + * we always have a non-null DataContentHandler. 1.591 + * 1.592 + * @return the requested DataContentHandler 1.593 + */ 1.594 + private synchronized DataContentHandler getDataContentHandler() { 1.595 + 1.596 + // make sure the factory didn't change 1.597 + if (factory != oldFactory) { 1.598 + oldFactory = factory; 1.599 + factoryDCH = null; 1.600 + dataContentHandler = null; 1.601 + transferFlavors = emptyFlavors; 1.602 + } 1.603 + 1.604 + if (dataContentHandler != null) 1.605 + return dataContentHandler; 1.606 + 1.607 + String simpleMT = getBaseType(); 1.608 + 1.609 + if (factoryDCH == null && factory != null) 1.610 + factoryDCH = factory.createDataContentHandler(simpleMT); 1.611 + 1.612 + if (factoryDCH != null) 1.613 + dataContentHandler = factoryDCH; 1.614 + 1.615 + if (dataContentHandler == null) { 1.616 + if (dataSource != null) 1.617 + dataContentHandler = getCommandMap(). 1.618 + createDataContentHandler(simpleMT, dataSource); 1.619 + else 1.620 + dataContentHandler = getCommandMap(). 1.621 + createDataContentHandler(simpleMT); 1.622 + } 1.623 + 1.624 + // getDataContentHandler always uses these 'wrapper' handlers 1.625 + // to make sure it returns SOMETHING meaningful... 1.626 + if (dataSource != null) 1.627 + dataContentHandler = new DataSourceDataContentHandler( 1.628 + dataContentHandler, 1.629 + dataSource); 1.630 + else 1.631 + dataContentHandler = new ObjectDataContentHandler( 1.632 + dataContentHandler, 1.633 + object, 1.634 + objectMimeType); 1.635 + return dataContentHandler; 1.636 + } 1.637 + 1.638 + /** 1.639 + * Use the MimeType class to extract the MIME type/subtype, 1.640 + * ignoring the parameters. The type is cached. 1.641 + */ 1.642 + private synchronized String getBaseType() { 1.643 + if (shortType == null) { 1.644 + String ct = getContentType(); 1.645 + try { 1.646 + MimeType mt = new MimeType(ct); 1.647 + shortType = mt.getBaseType(); 1.648 + } catch (MimeTypeParseException e) { 1.649 + shortType = ct; 1.650 + } 1.651 + } 1.652 + return shortType; 1.653 + } 1.654 + 1.655 + /** 1.656 + * Sets the DataContentHandlerFactory. The DataContentHandlerFactory 1.657 + * is called first to find DataContentHandlers. 1.658 + * The DataContentHandlerFactory can only be set once. 1.659 + * <p> 1.660 + * If the DataContentHandlerFactory has already been set, 1.661 + * this method throws an Error. 1.662 + * 1.663 + * @param newFactory the DataContentHandlerFactory 1.664 + * @exception Error if the factory has already been defined. 1.665 + * 1.666 + * @see javax.activation.DataContentHandlerFactory 1.667 + */ 1.668 + public static synchronized void setDataContentHandlerFactory( 1.669 + DataContentHandlerFactory newFactory) { 1.670 + if (factory != null) 1.671 + throw new Error("DataContentHandlerFactory already defined"); 1.672 + 1.673 + SecurityManager security = System.getSecurityManager(); 1.674 + if (security != null) { 1.675 + try { 1.676 + // if it's ok with the SecurityManager, it's ok with me... 1.677 + security.checkSetFactory(); 1.678 + } catch (SecurityException ex) { 1.679 + // otherwise, we also allow it if this code and the 1.680 + // factory come from the same class loader (e.g., 1.681 + // the JAF classes were loaded with the applet classes). 1.682 + if (DataHandler.class.getClassLoader() != 1.683 + newFactory.getClass().getClassLoader()) 1.684 + throw ex; 1.685 + } 1.686 + } 1.687 + factory = newFactory; 1.688 + } 1.689 +} 1.690 + 1.691 +/** 1.692 + * The DataHanderDataSource class implements the 1.693 + * DataSource interface when the DataHandler is constructed 1.694 + * with an Object and a mimeType string. 1.695 + */ 1.696 +class DataHandlerDataSource implements DataSource { 1.697 + DataHandler dataHandler = null; 1.698 + 1.699 + /** 1.700 + * The constructor. 1.701 + */ 1.702 + public DataHandlerDataSource(DataHandler dh) { 1.703 + this.dataHandler = dh; 1.704 + } 1.705 + 1.706 + /** 1.707 + * Returns an <code>InputStream</code> representing this object. 1.708 + * @return the <code>InputStream</code> 1.709 + */ 1.710 + public InputStream getInputStream() throws IOException { 1.711 + return dataHandler.getInputStream(); 1.712 + } 1.713 + 1.714 + /** 1.715 + * Returns the <code>OutputStream</code> for this object. 1.716 + * @return the <code>OutputStream</code> 1.717 + */ 1.718 + public OutputStream getOutputStream() throws IOException { 1.719 + return dataHandler.getOutputStream(); 1.720 + } 1.721 + 1.722 + /** 1.723 + * Returns the MIME type of the data represented by this object. 1.724 + * @return the MIME type 1.725 + */ 1.726 + public String getContentType() { 1.727 + return dataHandler.getContentType(); 1.728 + } 1.729 + 1.730 + /** 1.731 + * Returns the name of this object. 1.732 + * @return the name of this object 1.733 + */ 1.734 + public String getName() { 1.735 + return dataHandler.getName(); // what else would it be? 1.736 + } 1.737 +} 1.738 + 1.739 +/* 1.740 + * DataSourceDataContentHandler 1.741 + * 1.742 + * This is a <i>private</i> DataContentHandler that wraps the real 1.743 + * DataContentHandler in the case where the DataHandler was instantiated 1.744 + * with a DataSource. 1.745 + */ 1.746 +class DataSourceDataContentHandler implements DataContentHandler { 1.747 + private DataSource ds = null; 1.748 + private DataFlavor transferFlavors[] = null; 1.749 + private DataContentHandler dch = null; 1.750 + 1.751 + /** 1.752 + * The constructor. 1.753 + */ 1.754 + public DataSourceDataContentHandler(DataContentHandler dch, DataSource ds) { 1.755 + this.ds = ds; 1.756 + this.dch = dch; 1.757 + } 1.758 + 1.759 + /** 1.760 + * Return the DataFlavors for this <code>DataContentHandler</code>. 1.761 + * @return the DataFlavors 1.762 + */ 1.763 + public DataFlavor[] getTransferDataFlavors() { 1.764 + 1.765 + if (transferFlavors == null) { 1.766 + if (dch != null) { // is there a dch? 1.767 + transferFlavors = dch.getTransferDataFlavors(); 1.768 + } else { 1.769 + transferFlavors = new DataFlavor[1]; 1.770 + transferFlavors[0] = 1.771 + new ActivationDataFlavor(ds.getContentType(), 1.772 + ds.getContentType()); 1.773 + } 1.774 + } 1.775 + return transferFlavors; 1.776 + } 1.777 + 1.778 + /** 1.779 + * Return the Transfer Data of type DataFlavor from InputStream. 1.780 + * @param df the DataFlavor 1.781 + * @param ds the DataSource 1.782 + * @return the constructed Object 1.783 + */ 1.784 + public Object getTransferData(DataFlavor df, DataSource ds) throws 1.785 + UnsupportedFlavorException, IOException { 1.786 + 1.787 + if (dch != null) 1.788 + return dch.getTransferData(df, ds); 1.789 + else if (df.equals(getTransferDataFlavors()[0])) // only have one now 1.790 + return ds.getInputStream(); 1.791 + else 1.792 + throw new UnsupportedFlavorException(df); 1.793 + } 1.794 + 1.795 + public Object getContent(DataSource ds) throws IOException { 1.796 + 1.797 + if (dch != null) 1.798 + return dch.getContent(ds); 1.799 + else 1.800 + return ds.getInputStream(); 1.801 + } 1.802 + 1.803 + /** 1.804 + * Write the object to the output stream. 1.805 + */ 1.806 + public void writeTo(Object obj, String mimeType, OutputStream os) 1.807 + throws IOException { 1.808 + if (dch != null) 1.809 + dch.writeTo(obj, mimeType, os); 1.810 + else 1.811 + throw new UnsupportedDataTypeException( 1.812 + "no DCH for content type " + ds.getContentType()); 1.813 + } 1.814 +} 1.815 + 1.816 +/* 1.817 + * ObjectDataContentHandler 1.818 + * 1.819 + * This is a <i>private</i> DataContentHandler that wraps the real 1.820 + * DataContentHandler in the case where the DataHandler was instantiated 1.821 + * with an object. 1.822 + */ 1.823 +class ObjectDataContentHandler implements DataContentHandler { 1.824 + private DataFlavor transferFlavors[] = null; 1.825 + private Object obj; 1.826 + private String mimeType; 1.827 + private DataContentHandler dch = null; 1.828 + 1.829 + /** 1.830 + * The constructor. 1.831 + */ 1.832 + public ObjectDataContentHandler(DataContentHandler dch, 1.833 + Object obj, String mimeType) { 1.834 + this.obj = obj; 1.835 + this.mimeType = mimeType; 1.836 + this.dch = dch; 1.837 + } 1.838 + 1.839 + /** 1.840 + * Return the DataContentHandler for this object. 1.841 + * Used only by the DataHandler class. 1.842 + */ 1.843 + public DataContentHandler getDCH() { 1.844 + return dch; 1.845 + } 1.846 + 1.847 + /** 1.848 + * Return the DataFlavors for this <code>DataContentHandler</code>. 1.849 + * @return the DataFlavors 1.850 + */ 1.851 + public synchronized DataFlavor[] getTransferDataFlavors() { 1.852 + if (transferFlavors == null) { 1.853 + if (dch != null) { 1.854 + transferFlavors = dch.getTransferDataFlavors(); 1.855 + } else { 1.856 + transferFlavors = new DataFlavor[1]; 1.857 + transferFlavors[0] = new ActivationDataFlavor(obj.getClass(), 1.858 + mimeType, mimeType); 1.859 + } 1.860 + } 1.861 + return transferFlavors; 1.862 + } 1.863 + 1.864 + /** 1.865 + * Return the Transfer Data of type DataFlavor from InputStream. 1.866 + * @param df the DataFlavor 1.867 + * @param ds the DataSource 1.868 + * @return the constructed Object 1.869 + */ 1.870 + public Object getTransferData(DataFlavor df, DataSource ds) 1.871 + throws UnsupportedFlavorException, IOException { 1.872 + 1.873 + if (dch != null) 1.874 + return dch.getTransferData(df, ds); 1.875 + else if (df.equals(getTransferDataFlavors()[0])) // only have one now 1.876 + return obj; 1.877 + else 1.878 + throw new UnsupportedFlavorException(df); 1.879 + 1.880 + } 1.881 + 1.882 + public Object getContent(DataSource ds) { 1.883 + return obj; 1.884 + } 1.885 + 1.886 + /** 1.887 + * Write the object to the output stream. 1.888 + */ 1.889 + public void writeTo(Object obj, String mimeType, OutputStream os) 1.890 + throws IOException { 1.891 + if (dch != null) 1.892 + dch.writeTo(obj, mimeType, os); 1.893 + else if (obj instanceof byte[]) 1.894 + os.write((byte[])obj); 1.895 + else if (obj instanceof String) { 1.896 + OutputStreamWriter osw = new OutputStreamWriter(os); 1.897 + osw.write((String)obj); 1.898 + osw.flush(); 1.899 + } else throw new UnsupportedDataTypeException( 1.900 + "no object DCH for MIME type " + this.mimeType); 1.901 + } 1.902 +}