001 /* DataFlavor.java -- A type of data to transfer via the clipboard.
002 Copyright (C) 1999, 2001, 2004, 2005, 2006 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package java.awt.datatransfer;
040
041 import java.io.ByteArrayInputStream;
042 import java.io.IOException;
043 import java.io.InputStream;
044 import java.io.InputStreamReader;
045 import java.io.ObjectInput;
046 import java.io.ObjectOutput;
047 import java.io.OptionalDataException;
048 import java.io.Reader;
049 import java.io.Serializable;
050 import java.io.StringReader;
051 import java.io.UnsupportedEncodingException;
052 import java.nio.ByteBuffer;
053 import java.nio.CharBuffer;
054 import java.nio.charset.Charset;
055 import java.rmi.Remote;
056
057 /**
058 * This class represents a particular data format used for transferring
059 * data via the clipboard.
060 *
061 * @author Aaron M. Renn (arenn@urbanophile.com)
062 */
063 public class DataFlavor implements java.io.Externalizable, Cloneable
064 {
065 static final long serialVersionUID = 8367026044764648243L;
066
067 // FIXME: Serialization: Need to write methods for.
068
069 /**
070 * This is the data flavor used for tranferring plain text. The MIME
071 * type is "text/plain; charset=unicode". The representation class
072 * is <code>java.io.InputStream</code>.
073 *
074 * @deprecated The charset unicode is platform specific and InputStream
075 * deals with bytes not chars. Use <code>getRederForText()</code>.
076 */
077 public static final DataFlavor plainTextFlavor =
078 new DataFlavor("text/plain; charset=unicode; class=java.io.InputStream",
079 "plain unicode text");
080
081 /**
082 * This is the data flavor used for transferring Java strings. The
083 * MIME type is "application/x-java-serialized-object" and the
084 * representation class is <code>java.lang.String</code>.
085 */
086 public static final DataFlavor stringFlavor =
087 new DataFlavor(java.lang.String.class, "Java Unicode String");
088
089 /**
090 * This is a data flavor used for transferring lists of files. The
091 * representation type is a <code>java.util.List</code>, with each
092 * element of the list being a <code>java.io.File</code>.
093 */
094 public static final DataFlavor javaFileListFlavor =
095 new DataFlavor("application/x-java-file-list; class=java.util.List",
096 "Java File List");
097
098 /**
099 * This is an image flavor used for transferring images. The
100 * representation type is a <code>java.awt.Image</code>.
101 */
102 public static final DataFlavor imageFlavor =
103 new DataFlavor(java.awt.Image.class, "Java Image");
104
105 /**
106 * This is the MIME type used for transferring a serialized object.
107 * The representation class is the type of object be deserialized.
108 */
109 public static final String javaSerializedObjectMimeType =
110 "application/x-java-serialized-object";
111
112 /**
113 * This is the MIME type used to transfer a Java object reference within
114 * the same JVM. The representation class is the class of the object
115 * being transferred.
116 */
117 public static final String javaJVMLocalObjectMimeType =
118 "application/x-java-jvm-local-objectref";
119
120 /**
121 * This is the MIME type used to transfer a link to a remote object.
122 * The representation class is the type of object being linked to.
123 */
124 public static final String javaRemoteObjectMimeType =
125 "application/x-java-remote-object";
126
127 /*
128 * Instance Variables
129 */
130
131 // The MIME type for this flavor
132 private MimeType mimeType;
133
134 // The representation class for this flavor
135 private Class<?> representationClass;
136
137 // The human readable name of this flavor
138 private String humanPresentableName;
139
140 /*
141 * Static Methods
142 */
143
144 /**
145 * This method attempts to load the named class. The following class
146 * loaders are searched in order: the bootstrap class loader, the
147 * system class loader, the context class loader (if it exists), and
148 * the specified fallback class loader.
149 *
150 * @param className The name of the class to load.
151 * @param classLoader The class loader to use if all others fail, which
152 * may be <code>null</code>.
153 *
154 * @exception ClassNotFoundException If the class cannot be loaded.
155 */
156 protected static final Class<?> tryToLoadClass(String className,
157 ClassLoader classLoader)
158 throws ClassNotFoundException
159 {
160 // Bootstrap
161 try
162 {
163 return Class.forName(className);
164 }
165 catch(ClassNotFoundException cnfe)
166 {
167 // Ignored.
168 }
169
170 // System
171 try
172 {
173 ClassLoader loader = ClassLoader.getSystemClassLoader();
174 return Class.forName(className, true, loader);
175 }
176 catch(ClassNotFoundException cnfe)
177 {
178 // Ignored.
179 }
180
181 // Context
182 try
183 {
184 ClassLoader loader = Thread.currentThread().getContextClassLoader();
185 return Class.forName(className, true, loader);
186 }
187 catch(ClassNotFoundException cnfe)
188 {
189 // Ignored.
190 }
191
192 if (classLoader != null)
193 return Class.forName(className, true, classLoader);
194
195 throw new ClassNotFoundException(className);
196 }
197
198 /**
199 * XXX - Currently returns <code>plainTextFlavor</code>.
200 */
201 public static final DataFlavor getTextPlainUnicodeFlavor()
202 {
203 return plainTextFlavor;
204 }
205
206 /**
207 * Selects the best supported text flavor on this implementation.
208 * Returns <code>null</code> when none of the given flavors is liked.
209 *
210 * The <code>DataFlavor</code> returned the first data flavor in the
211 * array that has either a representation class which is (a subclass of)
212 * <code>Reader</code> or <code>String</code>, or has a representation
213 * class which is (a subclass of) <code>InputStream</code> and has a
214 * primary MIME type of "text" and has an supported encoding.
215 */
216 public static final DataFlavor
217 selectBestTextFlavor(DataFlavor[] availableFlavors)
218 {
219 for(int i = 0; i < availableFlavors.length; i++)
220 {
221 DataFlavor df = availableFlavors[i];
222 Class c = df.representationClass;
223
224 // A Reader or String is good.
225 if ((Reader.class.isAssignableFrom(c))
226 || (String.class.isAssignableFrom(c)))
227 return df;
228
229 // A InputStream is good if the mime primary type is "text"
230 if ((InputStream.class.isAssignableFrom(c))
231 && ("text".equals(df.getPrimaryType())))
232 {
233 String encoding = availableFlavors[i].getParameter("charset");
234 if (encoding == null)
235 encoding = "us-ascii";
236 Reader r = null;
237 try
238 {
239 // Try to construct a dummy reader with the found encoding
240 r = new InputStreamReader
241 (new ByteArrayInputStream(new byte[0]), encoding);
242 }
243 catch(UnsupportedEncodingException uee) { /* ignore */ }
244
245 if (r != null)
246 return df;
247 }
248 }
249
250 // Nothing found
251 return null;
252 }
253
254
255 /*
256 * Constructors
257 */
258
259 /**
260 * Empty public constructor needed for externalization.
261 * Should not be used for normal instantiation.
262 */
263 public DataFlavor()
264 {
265 // Used for deserialization only, nothing to do here.
266 }
267
268 /**
269 * Initializes a new instance of <code>DataFlavor</code>. The class
270 * and human readable name are specified, the MIME type will be
271 * "application/x-java-serialized-object". If the human readable name
272 * is not specified (<code>null</code>) then the human readable name
273 * will be the same as the MIME type.
274 *
275 * @param representationClass The representation class for this object.
276 * @param humanPresentableName The display name of the object.
277 */
278 public DataFlavor(Class<?> representationClass, String humanPresentableName)
279 {
280 if (representationClass == null)
281 throw new NullPointerException("representationClass must not be null");
282 try
283 {
284 mimeType = new MimeType(javaSerializedObjectMimeType);
285 }
286 catch (MimeTypeParseException ex)
287 {
288 // Must not happen as we use a constant string.
289 assert false;
290 }
291 if (humanPresentableName == null)
292 humanPresentableName = javaSerializedObjectMimeType;
293 this.humanPresentableName = humanPresentableName;
294 this.representationClass = representationClass;
295 }
296
297 /**
298 * Initializes a new instance of <code>DataFlavor</code> with the
299 * specified MIME type and description. If the MIME type has a
300 * "class=<rep class>" parameter then the representation class will
301 * be the class name specified. Otherwise the class defaults to
302 * <code>java.io.InputStream</code>. If the human readable name
303 * is not specified (<code>null</code>) then the human readable name
304 * will be the same as the MIME type.
305 *
306 * @param mimeType The MIME type for this flavor.
307 * @param humanPresentableName The display name of this flavor.
308 * @param classLoader The class loader for finding classes if the default
309 * class loaders do not work.
310 *
311 * @exception IllegalArgumentException If the representation class
312 * specified cannot be loaded.
313 * @exception ClassNotFoundException If the class is not loaded.
314 */
315 public DataFlavor(String mimeType, String humanPresentableName,
316 ClassLoader classLoader)
317 throws ClassNotFoundException
318 {
319 init(mimeType, humanPresentableName, classLoader);
320 }
321
322 /**
323 * Initializes a new instance of <code>DataFlavor</code> with the
324 * specified MIME type and description. If the MIME type has a
325 * "class=<rep class>" parameter then the representation class will
326 * be the class name specified. Otherwise the class defaults to
327 * <code>java.io.InputStream</code>. If the human readable name
328 * is not specified (<code>null</code>) then the human readable name
329 * will be the same as the MIME type. This is the same as calling
330 * <code>new DataFlavor(mimeType, humanPresentableName, null)</code>.
331 *
332 * @param mimeType The MIME type for this flavor.
333 * @param humanPresentableName The display name of this flavor.
334 *
335 * @exception IllegalArgumentException If the representation class
336 * specified cannot be loaded.
337 */
338 public DataFlavor(String mimeType, String humanPresentableName)
339 {
340 try
341 {
342 init(mimeType, humanPresentableName, getClass().getClassLoader());
343 }
344 catch (ClassNotFoundException ex)
345 {
346 IllegalArgumentException iae =
347 new IllegalArgumentException("Class not found: " + ex.getMessage());
348 iae.initCause(ex);
349 throw iae;
350 }
351 }
352
353 /**
354 * Initializes a new instance of <code>DataFlavor</code> with the specified
355 * MIME type. This type can have a "class=" parameter to specify the
356 * representation class, and then the class must exist or an exception will
357 * be thrown. If there is no "class=" parameter then the representation class
358 * will be <code>java.io.InputStream</code>. This is the same as calling
359 * <code>new DataFlavor(mimeType, null)</code>.
360 *
361 * @param mimeType The MIME type for this flavor.
362 *
363 * @exception IllegalArgumentException If a class is not specified in
364 * the MIME type.
365 * @exception ClassNotFoundException If the class cannot be loaded.
366 */
367 public DataFlavor(String mimeType) throws ClassNotFoundException
368 {
369 init(mimeType, null, getClass().getClassLoader());
370 }
371
372 /**
373 * Called by various constructors to initialize this object.
374 *
375 * @param mime the mime string
376 * @param humanPresentableName the human presentable name
377 * @param loader the class loader to use for loading the representation
378 * class
379 */
380 private void init(String mime, String humanPresentableName,
381 ClassLoader loader)
382 throws ClassNotFoundException
383 {
384 if (mime == null)
385 throw new NullPointerException("The mime type must not be null");
386 try
387 {
388 mimeType = new MimeType(mime);
389 }
390 catch (MimeTypeParseException ex)
391 {
392 IllegalArgumentException iae =
393 new IllegalArgumentException("Invalid mime type");
394 iae.initCause(ex);
395 throw iae;
396 }
397 String className = mimeType.getParameter("class");
398 if (className == null)
399 {
400 if (mimeType.getBaseType().equals(javaSerializedObjectMimeType))
401 throw new IllegalArgumentException("Serialized object type must have"
402 + " a representation class parameter");
403 else
404 representationClass = java.io.InputStream.class;
405 }
406 else
407 representationClass = tryToLoadClass(className, loader);
408 mimeType.addParameter("class", representationClass.getName());
409
410 if (humanPresentableName == null)
411 {
412 humanPresentableName = mimeType.getParameter("humanPresentableName");
413 if (humanPresentableName == null)
414 humanPresentableName = mimeType.getBaseType();
415 }
416 this.humanPresentableName = humanPresentableName;
417 }
418
419 /**
420 * Returns the MIME type of this flavor.
421 *
422 * @return The MIME type for this flavor.
423 */
424 public String getMimeType()
425 {
426 return(mimeType.toString());
427 }
428
429 /**
430 * Returns the representation class for this flavor.
431 *
432 * @return The representation class for this flavor.
433 */
434 public Class<?> getRepresentationClass()
435 {
436 return(representationClass);
437 }
438
439 /**
440 * Returns the human presentable name for this flavor.
441 *
442 * @return The human presentable name for this flavor.
443 */
444 public String getHumanPresentableName()
445 {
446 return(humanPresentableName);
447 }
448
449 /**
450 * Returns the primary MIME type for this flavor.
451 *
452 * @return The primary MIME type for this flavor.
453 */
454 public String getPrimaryType()
455 {
456 return(mimeType.getPrimaryType());
457 }
458
459 /**
460 * Returns the MIME subtype for this flavor.
461 *
462 * @return The MIME subtype for this flavor.
463 */
464 public String getSubType()
465 {
466 return mimeType.getSubType();
467 }
468
469 /**
470 * Returns the value of the named MIME type parameter, or <code>null</code>
471 * if the parameter does not exist.
472 *
473 * @param paramName The name of the paramter.
474 *
475 * @return The value of the parameter.
476 */
477 public String getParameter(String paramName)
478 {
479 if ("humanPresentableName".equals(paramName))
480 return getHumanPresentableName();
481
482 return mimeType.getParameter(paramName);
483 }
484
485 /**
486 * Sets the human presentable name to the specified value.
487 *
488 * @param humanPresentableName The new display name.
489 */
490 public void setHumanPresentableName(String humanPresentableName)
491 {
492 this.humanPresentableName = humanPresentableName;
493 }
494
495 /**
496 * Tests the MIME type of this object for equality against the specified
497 * MIME type. Ignores parameters.
498 *
499 * @param mimeType The MIME type to test against.
500 *
501 * @return <code>true</code> if the MIME type is equal to this object's
502 * MIME type (ignoring parameters), <code>false</code> otherwise.
503 *
504 * @exception NullPointerException If mimeType is null.
505 */
506 public boolean isMimeTypeEqual(String mimeType)
507 {
508 if (mimeType == null)
509 throw new NullPointerException("mimeType must not be null");
510 boolean equal = false;
511 try
512 {
513 if (this.mimeType != null)
514 {
515 MimeType other = new MimeType(mimeType);
516 equal = this.mimeType.matches(other);
517 }
518 }
519 catch (MimeTypeParseException ex)
520 {
521 // Return false in this case.
522 }
523 return equal;
524 }
525
526 /**
527 * Tests the MIME type of this object for equality against the specified
528 * data flavor's MIME type
529 *
530 * @param flavor The flavor to test against.
531 *
532 * @return <code>true</code> if the flavor's MIME type is equal to this
533 * object's MIME type, <code>false</code> otherwise.
534 */
535 public final boolean isMimeTypeEqual(DataFlavor flavor)
536 {
537 return isMimeTypeEqual(flavor.getMimeType());
538 }
539
540 /**
541 * Tests whether or not this flavor represents a serialized object.
542 *
543 * @return <code>true</code> if this flavor represents a serialized
544 * object, <code>false</code> otherwise.
545 */
546 public boolean isMimeTypeSerializedObject()
547 {
548 return isMimeTypeEqual(javaSerializedObjectMimeType);
549 }
550
551 /**
552 * Tests whether or not this flavor has a representation class of
553 * <code>java.io.InputStream</code>.
554 *
555 * @return <code>true</code> if the representation class of this flavor
556 * is <code>java.io.InputStream</code>, <code>false</code> otherwise.
557 */
558 public boolean isRepresentationClassInputStream()
559 {
560 return InputStream.class.isAssignableFrom(representationClass);
561 }
562
563 /**
564 * Tests whether the representation class for this flavor is
565 * serializable.
566 *
567 * @return <code>true</code> if the representation class is serializable,
568 * <code>false</code> otherwise.
569 */
570 public boolean isRepresentationClassSerializable()
571 {
572 return Serializable.class.isAssignableFrom(representationClass);
573 }
574
575 /**
576 * Tests whether the representation class for his flavor is remote.
577 *
578 * @return <code>true</code> if the representation class is remote,
579 * <code>false</code> otherwise.
580 */
581 public boolean isRepresentationClassRemote()
582 {
583 return Remote.class.isAssignableFrom (representationClass);
584 }
585
586 /**
587 * Tests whether or not this flavor represents a serialized object.
588 *
589 * @return <code>true</code> if this flavor represents a serialized
590 * object, <code>false</code> otherwise.
591 */
592 public boolean isFlavorSerializedObjectType()
593 {
594 return isRepresentationClassSerializable()
595 && isMimeTypeEqual(javaSerializedObjectMimeType);
596 }
597
598 /**
599 * Tests whether or not this flavor represents a remote object.
600 *
601 * @return <code>true</code> if this flavor represents a remote object,
602 * <code>false</code> otherwise.
603 */
604 public boolean isFlavorRemoteObjectType()
605 {
606 return isRepresentationClassRemote()
607 && isRepresentationClassSerializable()
608 && isMimeTypeEqual(javaRemoteObjectMimeType);
609 }
610
611 /**
612 * Tests whether or not this flavor represents a list of files.
613 *
614 * @return <code>true</code> if this flavor represents a list of files,
615 * <code>false</code> otherwise.
616 */
617 public boolean isFlavorJavaFileListType()
618 {
619 if (getPrimaryType().equals(javaFileListFlavor.getPrimaryType())
620 && getSubType().equals(javaFileListFlavor.getSubType())
621 && javaFileListFlavor.representationClass
622 .isAssignableFrom(representationClass))
623 return true;
624
625 return false ;
626 }
627
628 /**
629 * Returns a copy of this object.
630 *
631 * @return A copy of this object.
632 *
633 * @exception CloneNotSupportedException If the object's class does not support
634 * the Cloneable interface. Subclasses that override the clone method can also
635 * throw this exception to indicate that an instance cannot be cloned.
636 */
637 public Object clone () throws CloneNotSupportedException
638 {
639 // FIXME - This cannot be right.
640 try
641 {
642 return super.clone();
643 }
644 catch(Exception e)
645 {
646 return null;
647 }
648 }
649
650 /**
651 * This method test the specified <code>DataFlavor</code> for equality
652 * against this object. This will be true if the MIME type and
653 * representation class are the equal. If the primary type is 'text'
654 * then also the value of the charset parameter is compared. In such a
655 * case when the charset parameter isn't given then the charset is
656 * assumed to be equal to the default charset of the platform. All
657 * other parameters are ignored.
658 *
659 * @param flavor The <code>DataFlavor</code> to test against.
660 *
661 * @return <code>true</code> if the flavor is equal to this object,
662 * <code>false</code> otherwise.
663 */
664 public boolean equals(DataFlavor flavor)
665 {
666 if (flavor == null)
667 return false;
668
669 String primary = getPrimaryType();
670 if (! primary.equals(flavor.getPrimaryType()))
671 return false;
672
673 String sub = getSubType();
674 if (! sub.equals(flavor.getSubType()))
675 return false;
676
677 if (! this.representationClass.equals(flavor.representationClass))
678 return false;
679
680 if (primary.equals("text"))
681 if (! isRepresentationClassCharBuffer()
682 && ! isRepresentationClassReader()
683 && representationClass != java.lang.String.class
684 && ! (representationClass.isArray()
685 && representationClass.getComponentType() == Character.TYPE))
686 {
687 String charset = getParameter("charset");
688 String otherset = flavor.getParameter("charset");
689 String defaultset = Charset.defaultCharset().name();
690
691 if (charset == null || charset.equals(defaultset))
692 return (otherset == null || otherset.equals(defaultset));
693
694 return charset.equals(otherset);
695 }
696
697 return true;
698 }
699
700 /**
701 * This method test the specified <code>Object</code> for equality
702 * against this object. This will be true if the following conditions
703 * are met:
704 * <p>
705 * <ul>
706 * <li>The object is not <code>null</code>.</li>
707 * <li>The object is an instance of <code>DataFlavor</code>.</li>
708 * <li>The object's MIME type and representation class are equal to
709 * this object's.</li>
710 * </ul>
711 *
712 * @param obj The <code>Object</code> to test against.
713 *
714 * @return <code>true</code> if the flavor is equal to this object,
715 * <code>false</code> otherwise.
716 */
717 public boolean equals(Object obj)
718 {
719 if (! (obj instanceof DataFlavor))
720 return false;
721
722 return equals((DataFlavor) obj);
723 }
724
725 /**
726 * Tests whether or not the specified string is equal to the MIME type
727 * of this object.
728 *
729 * @param str The string to test against.
730 *
731 * @return <code>true</code> if the string is equal to this object's MIME
732 * type, <code>false</code> otherwise.
733 *
734 * @deprecated Not compatible with <code>hashCode()</code>.
735 * Use <code>isMimeTypeEqual()</code>
736 */
737 public boolean equals(String str)
738 {
739 return isMimeTypeEqual(str);
740 }
741
742 /**
743 * Returns the hash code for this data flavor.
744 * The hash code is based on the (lower case) mime type and the
745 * representation class.
746 */
747 public int hashCode()
748 {
749 return mimeType.toString().hashCode() ^ representationClass.hashCode();
750 }
751
752 /**
753 * Returns <code>true</code> when the given <code>DataFlavor</code>
754 * matches this one.
755 */
756 public boolean match(DataFlavor dataFlavor)
757 {
758 // XXX - How is this different from equals?
759 return equals(dataFlavor);
760 }
761
762 /**
763 * This method exists for backward compatibility. It simply returns
764 * the same name/value pair passed in.
765 *
766 * @param name The parameter name.
767 * @param value The parameter value.
768 *
769 * @return The name/value pair.
770 *
771 * @deprecated
772 */
773 protected String normalizeMimeTypeParameter(String name, String value)
774 {
775 return name + "=" + value;
776 }
777
778 /**
779 * This method exists for backward compatibility. It simply returns
780 * the MIME type string unchanged.
781 *
782 * @param type The MIME type.
783 *
784 * @return The MIME type.
785 *
786 * @deprecated
787 */
788 protected String normalizeMimeType(String type)
789 {
790 return type;
791 }
792
793 /**
794 * Serialize this class.
795 *
796 * @param stream The <code>ObjectOutput</code> stream to serialize to.
797 *
798 * @exception IOException If an error occurs.
799 */
800 public void writeExternal(ObjectOutput stream)
801 throws IOException
802 {
803 if (mimeType != null)
804 {
805 mimeType.addParameter("humanPresentableName", humanPresentableName);
806 stream.writeObject(mimeType);
807 mimeType.removeParameter("humanPresentableName");
808 }
809 else
810 stream.writeObject(null);
811 stream.writeObject(representationClass);
812 }
813
814
815 /**
816 * De-serialize this class.
817 *
818 * @param stream The <code>ObjectInput</code> stream to deserialize from.
819 *
820 * @exception IOException If an error ocurs.
821 * @exception ClassNotFoundException If the class for an object being restored
822 * cannot be found.
823 */
824 public void readExternal(ObjectInput stream)
825 throws IOException, ClassNotFoundException
826 {
827 mimeType = (MimeType) stream.readObject();
828 String className = null;
829 if (mimeType != null)
830 {
831 humanPresentableName =
832 mimeType.getParameter("humanPresentableName");
833 mimeType.removeParameter("humanPresentableName");
834 className = mimeType.getParameter("class");
835 if (className == null)
836 throw new IOException("No class in mime type");
837 }
838 try
839 {
840 representationClass = (Class) stream.readObject();
841 }
842 catch (OptionalDataException ex)
843 {
844 if (ex.eof && ex.length == 0)
845 {
846 if (className != null)
847 representationClass = tryToLoadClass(className,
848 getClass().getClassLoader());
849 }
850 else
851 throw ex;
852 }
853 }
854
855 /**
856 * Returns a string representation of this DataFlavor. Including the
857 * representation class name, MIME type and human presentable name.
858 */
859 public String toString()
860 {
861 return (getClass().getName()
862 + "[representationClass=" + getRepresentationClass().getName()
863 + ",mimeType=" + getMimeType()
864 + ",humanPresentableName=" + getHumanPresentableName()
865 + "]");
866 }
867
868 /**
869 * XXX - Currently returns <code>java.io.InputStream</code>.
870 *
871 * @since 1.3
872 */
873 public final Class<?> getDefaultRepresentationClass()
874 {
875 return java.io.InputStream.class;
876 }
877
878 /**
879 * XXX - Currently returns <code>java.io.InputStream</code>.
880 */
881 public final String getDefaultRepresentationClassAsString()
882 {
883 return getDefaultRepresentationClass().getName();
884 }
885
886 /**
887 * Creates a <code>Reader</code> for a given <code>Transferable</code>.
888 *
889 * If the representation class is a (subclass of) <code>Reader</code>
890 * then an instance of the representation class is returned. If the
891 * representatation class is a <code>String</code> then a
892 * <code>StringReader</code> is returned. And if the representation class
893 * is a (subclass of) <code>InputStream</code> and the primary MIME type
894 * is "text" then a <code>InputStreamReader</code> for the correct charset
895 * encoding is returned.
896 *
897 * @param transferable The <code>Transferable</code> for which a text
898 * <code>Reader</code> is requested.
899 *
900 * @exception IllegalArgumentException If the representation class is not one
901 * of the seven listed above or the Transferable has null data.
902 * @exception NullPointerException If the Transferable is null.
903 * @exception UnsupportedFlavorException when the transferable doesn't
904 * support this <code>DataFlavor</code>. Or if the representable class
905 * isn't a (subclass of) <code>Reader</code>, <code>String</code>,
906 * <code>InputStream</code> and/or the primary MIME type isn't "text".
907 * @exception IOException when any IOException occurs.
908 * @exception UnsupportedEncodingException if the "charset" isn't supported
909 * on this platform.
910 */
911 public Reader getReaderForText(Transferable transferable)
912 throws UnsupportedFlavorException, IOException
913 {
914 if (!transferable.isDataFlavorSupported(this))
915 throw new UnsupportedFlavorException(this);
916
917 if (Reader.class.isAssignableFrom(representationClass))
918 return (Reader)transferable.getTransferData(this);
919
920 if (String.class.isAssignableFrom(representationClass))
921 return new StringReader((String)transferable.getTransferData(this));
922
923 if (InputStream.class.isAssignableFrom(representationClass)
924 && "text".equals(getPrimaryType()))
925 {
926 InputStream in = (InputStream)transferable.getTransferData(this);
927 String encoding = getParameter("charset");
928 if (encoding == null)
929 encoding = "us-ascii";
930 return new InputStreamReader(in, encoding);
931 }
932
933 throw new UnsupportedFlavorException(this);
934 }
935
936 /**
937 * Returns whether the representation class for this DataFlavor is
938 * @see java.nio.ByteBuffer or a subclass thereof.
939 *
940 * @since 1.4
941 */
942 public boolean isRepresentationClassByteBuffer()
943 {
944 return ByteBuffer.class.isAssignableFrom(representationClass);
945 }
946
947 /**
948 * Returns whether the representation class for this DataFlavor is
949 * @see java.nio.CharBuffer or a subclass thereof.
950 *
951 * @since 1.4
952 */
953 public boolean isRepresentationClassCharBuffer()
954 {
955 return CharBuffer.class.isAssignableFrom(representationClass);
956 }
957
958 /**
959 * Returns whether the representation class for this DataFlavor is
960 * @see java.io.Reader or a subclass thereof.
961 *
962 * @since 1.4
963 */
964 public boolean isRepresentationClassReader()
965 {
966 return Reader.class.isAssignableFrom(representationClass);
967 }
968
969 /**
970 * Returns whether this <code>DataFlavor</code> is a valid text flavor for
971 * this implementation of the Java platform. Only flavors equivalent to
972 * <code>DataFlavor.stringFlavor</code> and <code>DataFlavor</code>s with
973 * a primary MIME type of "text" can be valid text flavors.
974 * <p>
975 * If this flavor supports the charset parameter, it must be equivalent to
976 * <code>DataFlavor.stringFlavor</code>, or its representation must be
977 * <code>java.io.Reader</code>, <code>java.lang.String</code>,
978 * <code>java.nio.CharBuffer</code>, <code>java.io.InputStream</code> or
979 * <code>java.nio.ByteBuffer</code>,
980 * If the representation is <code>java.io.InputStream</code> or
981 * <code>java.nio.ByteBuffer</code>, then this flavor's <code>charset</code>
982 * parameter must be supported by this implementation of the Java platform.
983 * If a charset is not specified, then the platform default charset, which
984 * is always supported, is assumed.
985 * <p>
986 * If this flavor does not support the charset parameter, its
987 * representation must be <code>java.io.InputStream</code>,
988 * <code>java.nio.ByteBuffer</code>.
989 * <p>
990 * See <code>selectBestTextFlavor</code> for a list of text flavors which
991 * support the charset parameter.
992 *
993 * @return <code>true</code> if this <code>DataFlavor</code> is a valid
994 * text flavor as described above; <code>false</code> otherwise
995 * @see #selectBestTextFlavor
996 * @since 1.4
997 */
998 public boolean isFlavorTextType() {
999 // FIXME: I'm not 100% sure if this implementation does the same like sun's does
1000 if(equals(DataFlavor.stringFlavor) || getPrimaryType().equals("text"))
1001 {
1002 String charset = getParameter("charset");
1003 Class c = getRepresentationClass();
1004 if(charset != null)
1005 {
1006 if(Reader.class.isAssignableFrom(c)
1007 || CharBuffer.class.isAssignableFrom(c)
1008 || String.class.isAssignableFrom(c))
1009 {
1010 return true;
1011 }
1012 else if(InputStream.class.isAssignableFrom(c)
1013 || ByteBuffer.class.isAssignableFrom(c))
1014 {
1015 return Charset.isSupported(charset);
1016 }
1017 }
1018 else if(InputStream.class.isAssignableFrom(c)
1019 || ByteBuffer.class.isAssignableFrom(c))
1020 {
1021 return true;
1022 }
1023 }
1024 return false;
1025 }
1026 } // class DataFlavor