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 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package java.awt.datatransfer; 040 041import java.io.ByteArrayInputStream; 042import java.io.IOException; 043import java.io.InputStream; 044import java.io.InputStreamReader; 045import java.io.ObjectInput; 046import java.io.ObjectOutput; 047import java.io.OptionalDataException; 048import java.io.Reader; 049import java.io.Serializable; 050import java.io.StringReader; 051import java.io.UnsupportedEncodingException; 052import java.nio.ByteBuffer; 053import java.nio.CharBuffer; 054import java.nio.charset.Charset; 055import 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 */ 063public 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