Frames | No Frames |
1: /* DataFlavor.java -- A type of data to transfer via the clipboard. 2: Copyright (C) 1999, 2001, 2004, 2005, 2006 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.awt.datatransfer; 40: 41: import java.io.ByteArrayInputStream; 42: import java.io.IOException; 43: import java.io.InputStream; 44: import java.io.InputStreamReader; 45: import java.io.ObjectInput; 46: import java.io.ObjectOutput; 47: import java.io.OptionalDataException; 48: import java.io.Reader; 49: import java.io.Serializable; 50: import java.io.StringReader; 51: import java.io.UnsupportedEncodingException; 52: import java.nio.ByteBuffer; 53: import java.nio.CharBuffer; 54: import java.nio.charset.Charset; 55: import java.rmi.Remote; 56: 57: /** 58: * This class represents a particular data format used for transferring 59: * data via the clipboard. 60: * 61: * @author Aaron M. Renn (arenn@urbanophile.com) 62: */ 63: public class DataFlavor implements java.io.Externalizable, Cloneable 64: { 65: static final long serialVersionUID = 8367026044764648243L; 66: 67: // FIXME: Serialization: Need to write methods for. 68: 69: /** 70: * This is the data flavor used for tranferring plain text. The MIME 71: * type is "text/plain; charset=unicode". The representation class 72: * is <code>java.io.InputStream</code>. 73: * 74: * @deprecated The charset unicode is platform specific and InputStream 75: * deals with bytes not chars. Use <code>getRederForText()</code>. 76: */ 77: public static final DataFlavor plainTextFlavor = 78: new DataFlavor("text/plain; charset=unicode; class=java.io.InputStream", 79: "plain unicode text"); 80: 81: /** 82: * This is the data flavor used for transferring Java strings. The 83: * MIME type is "application/x-java-serialized-object" and the 84: * representation class is <code>java.lang.String</code>. 85: */ 86: public static final DataFlavor stringFlavor = 87: new DataFlavor(java.lang.String.class, "Java Unicode String"); 88: 89: /** 90: * This is a data flavor used for transferring lists of files. The 91: * representation type is a <code>java.util.List</code>, with each 92: * element of the list being a <code>java.io.File</code>. 93: */ 94: public static final DataFlavor javaFileListFlavor = 95: new DataFlavor("application/x-java-file-list; class=java.util.List", 96: "Java File List"); 97: 98: /** 99: * 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