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

Sun, 15 Dec 2013 23:35:45 +0100

author
mkos
date
Sun, 15 Dec 2013 23:35:45 +0100
changeset 494
2fcd3ddb57a6
parent 286
f50545b5e2f1
child 637
9c07ef4934dd
permissions
-rw-r--r--

8025152: Enhance activation set up
8028388: 9 jaxws tests failed in nightly build with java.lang.ClassCastException
Summary: fix also reviewed by Bill Shannon, Alexander Fomin
Reviewed-by: dfuchs, hawtin, mgrebac
Contributed-by: bill.shannon@oracle.com

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

mercurial