001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: /*
038: * @(#)DataHandler.java 1.41 07/05/14
039: */
040:
041: package javax.activation;
042:
043: import java.io.InputStream;
044: import java.io.IOException;
045: import java.io.OutputStream;
046: import java.io.PipedInputStream;
047: import java.io.PipedOutputStream;
048: import java.io.OutputStreamWriter;
049: import java.net.URL;
050: import java.awt.datatransfer.Transferable;
051: import java.awt.datatransfer.DataFlavor;
052: import java.awt.datatransfer.UnsupportedFlavorException;
053:
054: /**
055: * The DataHandler class provides a consistent interface to data
056: * available in many different sources and formats.
057: * It manages simple stream to string conversions and related operations
058: * using DataContentHandlers.
059: * It provides access to commands that can operate on the data.
060: * The commands are found using a CommandMap. <p>
061: *
062: * <b>DataHandler and the Transferable Interface</b><p>
063: * DataHandler implements the Transferable interface so that data can
064: * be used in AWT data transfer operations, such as cut and paste and
065: * drag and drop. The implementation of the Transferable interface
066: * relies on the availability of an installed DataContentHandler
067: * object corresponding to the MIME type of the data represented in
068: * the specific instance of the DataHandler.<p>
069: *
070: * <b>DataHandler and CommandMaps</b><p>
071: * The DataHandler keeps track of the current CommandMap that it uses to
072: * service requests for commands (<code>getCommand</code>,
073: * <code>getAllCommands</code>, <code>getPreferredCommands</code>).
074: * Each instance of a DataHandler may have a CommandMap associated with
075: * it using the <code>setCommandMap</code> method. If a CommandMap was
076: * not set, DataHandler calls the <code>getDefaultCommandMap</code>
077: * method in CommandMap and uses the value it returns. See
078: * <i>CommandMap</i> for more information. <p>
079: *
080: * <b>DataHandler and URLs</b><p>
081: * The current DataHandler implementation creates a private
082: * instance of URLDataSource when it is constructed with a URL.
083: *
084: * @see javax.activation.CommandMap
085: * @see javax.activation.DataContentHandler
086: * @see javax.activation.DataSource
087: * @see javax.activation.URLDataSource
088: */
089:
090: public class DataHandler implements Transferable {
091:
092: // Use the datasource to indicate whether we were started via the
093: // DataSource constructor or the object constructor.
094: private DataSource dataSource = null;
095: private DataSource objDataSource = null;
096:
097: // The Object and mimetype from the constructor (if passed in).
098: // object remains null if it was instantiated with a
099: // 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 "
263: + getBaseType());
264: }
265: // there is none but the default^^^^^^^^^^^^^^^^
266: final DataContentHandler fdch = dch;
267:
268: // from bill s.
269: // ce n'est pas une pipe!
270: //
271: // NOTE: This block of code needs to throw exceptions, but
272: // can't because it is in another thread!!! ARG!
273: //
274: final PipedOutputStream pos = new PipedOutputStream();
275: PipedInputStream pin = new PipedInputStream(pos);
276: new Thread(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()
384: .getTransferDataFlavors();
385: return transferFlavors;
386: }
387:
388: /**
389: * Returns whether the specified data flavor is supported
390: * for this object.<p>
391: *
392: * This method iterates through the DataFlavors returned from
393: * <code>getTransferDataFlavors</code>, comparing each with
394: * the specified flavor.
395: *
396: * @param flavor the requested flavor for the data
397: * @return true if the data flavor is supported
398: * @see javax.activation.DataHandler#getTransferDataFlavors
399: */
400: public boolean isDataFlavorSupported(DataFlavor flavor) {
401: DataFlavor[] lFlavors = getTransferDataFlavors();
402:
403: for (int i = 0; i < lFlavors.length; i++) {
404: if (lFlavors[i].equals(flavor))
405: return true;
406: }
407: return false;
408: }
409:
410: /**
411: * Returns an object that represents the data to be
412: * transferred. The class of the object returned is defined by the
413: * representation class of the data flavor.<p>
414: *
415: * <b>For DataHandler's created with DataSources or URLs:</b><p>
416: *
417: * The DataHandler attempts to locate a DataContentHandler
418: * for this MIME type. If one is found, the passed in DataFlavor
419: * and the type of the data are passed to its <code>getTransferData</code>
420: * method. If the DataHandler fails to locate a DataContentHandler
421: * and the flavor specifies this object's MIME type and the
422: * <code>java.io.InputStream</code> class, this object's InputStream
423: * is returned.
424: * Otherwise it throws an UnsupportedFlavorException. <p>
425: *
426: * <b>For DataHandler's created with Objects:</b><p>
427: *
428: * The DataHandler attempts to locate a DataContentHandler
429: * for this MIME type. If one is found, the passed in DataFlavor
430: * and the type of the data are passed to its getTransferData
431: * method. If the DataHandler fails to locate a DataContentHandler
432: * and the flavor specifies this object's MIME type and its class,
433: * this DataHandler's referenced object is returned.
434: * Otherwise it throws an UnsupportedFlavorException.
435: *
436: * @param flavor the requested flavor for the data
437: * @return the object
438: * @exception UnsupportedFlavorException if the data could not be
439: * converted to the requested flavor
440: * @exception IOException if an I/O error occurs
441: * @see javax.activation.ActivationDataFlavor
442: */
443: public Object getTransferData(DataFlavor flavor)
444: throws UnsupportedFlavorException, IOException {
445: return getDataContentHandler().getTransferData(flavor,
446: dataSource);
447: }
448:
449: /**
450: * Set the CommandMap for use by this DataHandler.
451: * Setting it to <code>null</code> causes the CommandMap to revert
452: * to the CommandMap returned by the
453: * <code>CommandMap.getDefaultCommandMap</code> method.
454: * Changing the CommandMap, or setting it to <code>null</code>,
455: * clears out any data cached from the previous CommandMap.
456: *
457: * @param commandMap the CommandMap to use in this DataHandler
458: *
459: * @see javax.activation.CommandMap#setDefaultCommandMap
460: */
461: public synchronized void setCommandMap(CommandMap commandMap) {
462: if (commandMap != currentCommandMap || commandMap == null) {
463: // clear cached values...
464: transferFlavors = emptyFlavors;
465: dataContentHandler = null;
466:
467: currentCommandMap = commandMap;
468: }
469: }
470:
471: /**
472: * Return the <i>preferred</i> commands for this type of data.
473: * This method calls the <code>getPreferredCommands</code> method
474: * in the CommandMap associated with this instance of DataHandler.
475: * This method returns an array that represents a subset of
476: * available commands. In cases where multiple commands for the
477: * MIME type represented by this DataHandler are present, the
478: * installed CommandMap chooses the appropriate commands.
479: *
480: * @return the CommandInfo objects representing the preferred commands
481: *
482: * @see javax.activation.CommandMap#getPreferredCommands
483: */
484: public CommandInfo[] getPreferredCommands() {
485: if (dataSource != null)
486: return getCommandMap().getPreferredCommands(getBaseType(),
487: dataSource);
488: else
489: return getCommandMap().getPreferredCommands(getBaseType());
490: }
491:
492: /**
493: * Return all the commands for this type of data.
494: * This method returns an array containing all commands
495: * for the type of data represented by this DataHandler. The
496: * MIME type for the underlying data represented by this DataHandler
497: * is used to call through to the <code>getAllCommands</code> method
498: * of the CommandMap associated with this DataHandler.
499: *
500: * @return the CommandInfo objects representing all the commands
501: *
502: * @see javax.activation.CommandMap#getAllCommands
503: */
504: public CommandInfo[] getAllCommands() {
505: if (dataSource != null)
506: return getCommandMap().getAllCommands(getBaseType(),
507: dataSource);
508: else
509: return getCommandMap().getAllCommands(getBaseType());
510: }
511:
512: /**
513: * Get the command <i>cmdName</i>. Use the search semantics as
514: * defined by the CommandMap installed in this DataHandler. The
515: * MIME type for the underlying data represented by this DataHandler
516: * is used to call through to the <code>getCommand</code> method
517: * of the CommandMap associated with this DataHandler.
518: *
519: * @param cmdName the command name
520: * @return the CommandInfo corresponding to the command
521: *
522: * @see javax.activation.CommandMap#getCommand
523: */
524: public CommandInfo getCommand(String cmdName) {
525: if (dataSource != null)
526: return getCommandMap().getCommand(getBaseType(), cmdName,
527: dataSource);
528: else
529: return getCommandMap().getCommand(getBaseType(), cmdName);
530: }
531:
532: /**
533: * Return the data in its preferred Object form. <p>
534: *
535: * If the DataHandler was instantiated with an object, return
536: * the object. <p>
537: *
538: * If the DataHandler was instantiated with a DataSource,
539: * this method uses a DataContentHandler to return the content
540: * object for the data represented by this DataHandler. If no
541: * <code>DataContentHandler</code> can be found for the
542: * the type of this data, the DataHandler returns an
543: * InputStream for the data.
544: *
545: * @return the content.
546: * @exception IOException if an IOException occurs during
547: * this operation.
548: */
549: public Object getContent() throws IOException {
550: if (object != null)
551: return object;
552: else
553: return getDataContentHandler().getContent(getDataSource());
554: }
555:
556: /**
557: * A convenience method that takes a CommandInfo object
558: * and instantiates the corresponding command, usually
559: * a JavaBean component.
560: * <p>
561: * This method calls the CommandInfo's <code>getCommandObject</code>
562: * method with the <code>ClassLoader</code> used to load
563: * the <code>javax.activation.DataHandler</code> class itself.
564: *
565: * @param cmdinfo the CommandInfo corresponding to a command
566: * @return the instantiated command object
567: */
568: public Object getBean(CommandInfo cmdinfo) {
569: Object bean = null;
570:
571: try {
572: // make the bean
573: ClassLoader cld = null;
574: // First try the "application's" class loader.
575: cld = SecuritySupport.getContextClassLoader();
576: if (cld == null)
577: cld = this .getClass().getClassLoader();
578: bean = cmdinfo.getCommandObject(this , cld);
579: } catch (IOException e) {
580: } catch (ClassNotFoundException e) {
581: }
582:
583: return bean;
584: }
585:
586: /**
587: * Get the DataContentHandler for this DataHandler: <p>
588: *
589: * If a DataContentHandlerFactory is set, use it.
590: * Otherwise look for an object to serve DCH in the
591: * following order: <p>
592: *
593: * 1) if a factory is set, use it <p>
594: * 2) if a CommandMap is set, use it <p>
595: * 3) use the default CommandMap <p>
596: *
597: * In any case, wrap the real DataContentHandler with one of our own
598: * to handle any missing cases, fill in defaults, and to ensure that
599: * we always have a non-null DataContentHandler.
600: *
601: * @return the requested DataContentHandler
602: */
603: private synchronized DataContentHandler getDataContentHandler() {
604:
605: // make sure the factory didn't change
606: if (factory != oldFactory) {
607: oldFactory = factory;
608: factoryDCH = null;
609: dataContentHandler = null;
610: transferFlavors = emptyFlavors;
611: }
612:
613: if (dataContentHandler != null)
614: return dataContentHandler;
615:
616: String simpleMT = getBaseType();
617:
618: if (factoryDCH == null && factory != null)
619: factoryDCH = factory.createDataContentHandler(simpleMT);
620:
621: if (factoryDCH != null)
622: dataContentHandler = factoryDCH;
623:
624: if (dataContentHandler == null) {
625: if (dataSource != null)
626: dataContentHandler = getCommandMap()
627: .createDataContentHandler(simpleMT, dataSource);
628: else
629: dataContentHandler = getCommandMap()
630: .createDataContentHandler(simpleMT);
631: }
632:
633: // getDataContentHandler always uses these 'wrapper' handlers
634: // to make sure it returns SOMETHING meaningful...
635: if (dataSource != null)
636: dataContentHandler = new DataSourceDataContentHandler(
637: dataContentHandler, dataSource);
638: else
639: dataContentHandler = new ObjectDataContentHandler(
640: dataContentHandler, object, objectMimeType);
641: return dataContentHandler;
642: }
643:
644: /**
645: * Use the MimeType class to extract the MIME type/subtype,
646: * ignoring the parameters. The type is cached.
647: */
648: private synchronized String getBaseType() {
649: if (shortType == null) {
650: String ct = getContentType();
651: try {
652: MimeType mt = new MimeType(ct);
653: shortType = mt.getBaseType();
654: } catch (MimeTypeParseException e) {
655: shortType = ct;
656: }
657: }
658: return shortType;
659: }
660:
661: /**
662: * Sets the DataContentHandlerFactory. The DataContentHandlerFactory
663: * is called first to find DataContentHandlers.
664: * The DataContentHandlerFactory can only be set once.
665: * <p>
666: * If the DataContentHandlerFactory has already been set,
667: * this method throws an Error.
668: *
669: * @param newFactory the DataContentHandlerFactory
670: * @exception Error if the factory has already been defined.
671: *
672: * @see javax.activation.DataContentHandlerFactory
673: */
674: public static synchronized void setDataContentHandlerFactory(
675: DataContentHandlerFactory newFactory) {
676: if (factory != null)
677: throw new Error("DataContentHandlerFactory already defined");
678:
679: SecurityManager security = System.getSecurityManager();
680: if (security != null) {
681: try {
682: // if it's ok with the SecurityManager, it's ok with me...
683: security.checkSetFactory();
684: } catch (SecurityException ex) {
685: // otherwise, we also allow it if this code and the
686: // factory come from the same class loader (e.g.,
687: // the JAF classes were loaded with the applet classes).
688: if (DataHandler.class.getClassLoader() != newFactory
689: .getClass().getClassLoader())
690: throw ex;
691: }
692: }
693: factory = newFactory;
694: }
695: }
696:
697: /**
698: * The DataHanderDataSource class implements the
699: * DataSource interface when the DataHandler is constructed
700: * with an Object and a mimeType string.
701: */
702: class DataHandlerDataSource implements DataSource {
703: DataHandler dataHandler = null;
704:
705: /**
706: * The constructor.
707: */
708: public DataHandlerDataSource(DataHandler dh) {
709: this .dataHandler = dh;
710: }
711:
712: /**
713: * Returns an <code>InputStream</code> representing this object.
714: * @return the <code>InputStream</code>
715: */
716: public InputStream getInputStream() throws IOException {
717: return dataHandler.getInputStream();
718: }
719:
720: /**
721: * Returns the <code>OutputStream</code> for this object.
722: * @return the <code>OutputStream</code>
723: */
724: public OutputStream getOutputStream() throws IOException {
725: return dataHandler.getOutputStream();
726: }
727:
728: /**
729: * Returns the MIME type of the data represented by this object.
730: * @return the MIME type
731: */
732: public String getContentType() {
733: return dataHandler.getContentType();
734: }
735:
736: /**
737: * Returns the name of this object.
738: * @return the name of this object
739: */
740: public String getName() {
741: return dataHandler.getName(); // what else would it be?
742: }
743: }
744:
745: /*
746: * DataSourceDataContentHandler
747: *
748: * This is a <i>private</i> DataContentHandler that wraps the real
749: * DataContentHandler in the case where the DataHandler was instantiated
750: * with a DataSource.
751: */
752: class DataSourceDataContentHandler implements DataContentHandler {
753: private DataSource ds = null;
754: private DataFlavor transferFlavors[] = null;
755: private DataContentHandler dch = null;
756:
757: /**
758: * The constructor.
759: */
760: public DataSourceDataContentHandler(DataContentHandler dch,
761: DataSource ds) {
762: this .ds = ds;
763: this .dch = dch;
764: }
765:
766: /**
767: * Return the DataFlavors for this <code>DataContentHandler</code>.
768: * @return the DataFlavors
769: */
770: public DataFlavor[] getTransferDataFlavors() {
771:
772: if (transferFlavors == null) {
773: if (dch != null) { // is there a dch?
774: transferFlavors = dch.getTransferDataFlavors();
775: } else {
776: transferFlavors = new DataFlavor[1];
777: transferFlavors[0] = new ActivationDataFlavor(ds
778: .getContentType(), ds.getContentType());
779: }
780: }
781: return transferFlavors;
782: }
783:
784: /**
785: * Return the Transfer Data of type DataFlavor from InputStream.
786: * @param df the DataFlavor
787: * @param ds the DataSource
788: * @return the constructed Object
789: */
790: public Object getTransferData(DataFlavor df, DataSource ds)
791: throws UnsupportedFlavorException, IOException {
792:
793: if (dch != null)
794: return dch.getTransferData(df, ds);
795: else if (df.equals(getTransferDataFlavors()[0])) // only have one now
796: return ds.getInputStream();
797: else
798: throw new UnsupportedFlavorException(df);
799: }
800:
801: public Object getContent(DataSource ds) throws IOException {
802:
803: if (dch != null)
804: return dch.getContent(ds);
805: else
806: return ds.getInputStream();
807: }
808:
809: /**
810: * Write the object to the output stream.
811: */
812: public void writeTo(Object obj, String mimeType, OutputStream os)
813: throws IOException {
814: if (dch != null)
815: dch.writeTo(obj, mimeType, os);
816: else
817: throw new UnsupportedDataTypeException(
818: "no DCH for content type " + ds.getContentType());
819: }
820: }
821:
822: /*
823: * ObjectDataContentHandler
824: *
825: * This is a <i>private</i> DataContentHandler that wraps the real
826: * DataContentHandler in the case where the DataHandler was instantiated
827: * with an object.
828: */
829: class ObjectDataContentHandler implements DataContentHandler {
830: private DataFlavor transferFlavors[] = null;
831: private Object obj;
832: private String mimeType;
833: private DataContentHandler dch = null;
834:
835: /**
836: * The constructor.
837: */
838: public ObjectDataContentHandler(DataContentHandler dch, Object obj,
839: String mimeType) {
840: this .obj = obj;
841: this .mimeType = mimeType;
842: this .dch = dch;
843: }
844:
845: /**
846: * Return the DataContentHandler for this object.
847: * Used only by the DataHandler class.
848: */
849: public DataContentHandler getDCH() {
850: return dch;
851: }
852:
853: /**
854: * Return the DataFlavors for this <code>DataContentHandler</code>.
855: * @return the DataFlavors
856: */
857: public synchronized DataFlavor[] getTransferDataFlavors() {
858: if (transferFlavors == null) {
859: if (dch != null) {
860: transferFlavors = dch.getTransferDataFlavors();
861: } else {
862: transferFlavors = new DataFlavor[1];
863: transferFlavors[0] = new ActivationDataFlavor(obj
864: .getClass(), mimeType, mimeType);
865: }
866: }
867: return transferFlavors;
868: }
869:
870: /**
871: * Return the Transfer Data of type DataFlavor from InputStream.
872: * @param df the DataFlavor
873: * @param ds the DataSource
874: * @return the constructed Object
875: */
876: public Object getTransferData(DataFlavor df, DataSource ds)
877: throws UnsupportedFlavorException, IOException {
878:
879: if (dch != null)
880: return dch.getTransferData(df, ds);
881: else if (df.equals(getTransferDataFlavors()[0])) // only have one now
882: return obj;
883: else
884: throw new UnsupportedFlavorException(df);
885:
886: }
887:
888: public Object getContent(DataSource ds) {
889: return obj;
890: }
891:
892: /**
893: * Write the object to the output stream.
894: */
895: public void writeTo(Object obj, String mimeType, OutputStream os)
896: throws IOException {
897: if (dch != null)
898: dch.writeTo(obj, mimeType, os);
899: else if (obj instanceof byte[])
900: os.write((byte[]) obj);
901: else if (obj instanceof String) {
902: OutputStreamWriter osw = new OutputStreamWriter(os);
903: osw.write((String) obj);
904: osw.flush();
905: } else
906: throw new UnsupportedDataTypeException(
907: "no object DCH for MIME type " + this.mimeType);
908: }
909: }
|