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