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

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 494
2fcd3ddb57a6
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

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

mercurial