java.io.InputStream.
 *
 * @deprecated The charset unicode is platform specific and InputStream
 * deals with bytes not chars. Use getRederForText().
 */
public static final DataFlavor plainTextFlavor;
/**
 * This is the data flavor used for transferring Java strings.  The
 * MIME type is "application/x-java-serialized-object" and the 
 * representation class is java.lang.String.
 */
public static final DataFlavor stringFlavor;
/**
 * This is a data flavor used for transferring lists of files.  The
 * representation type is a java.util.List, with each element of 
 * the list being a java.io.File.
 */
public static final DataFlavor javaFileListFlavor;
public static final DataFlavor imageFlavor;
/**
 * This is the MIME type used for transferring a serialized object.
 * The representation class is the type of object be deserialized.
 */
public static final String javaSerializedObjectMimeType =
  "application/x-java-serialized-object";
/**
 * This is the MIME type used to transfer a Java object reference within
 * the same JVM.  The representation class is the class of the object
 * being transferred.
 */
public static final String javaJVMLocalObjectMimeType =
  "application/x-java-jvm-local-object";
/**
 * This is the MIME type used to transfer a link to a remote object.
 * The representation class is the type of object being linked to.
 */
public static final String javaRemoteObjectMimeType =
  "application/x-java-remote-object";
static
{
  plainTextFlavor
      = new DataFlavor(java.io.InputStream.class,
		       "text/plain; charset=unicode",
		       "plain unicode text");
  stringFlavor
      = new DataFlavor(java.lang.String.class,
		       "Java Unicode String");
  javaFileListFlavor
      = new DataFlavor(java.util.List.class,
		       "Java File List");
  // javaFileListFlavor.mimeType = "application/x-java-file-list";
  imageFlavor
      = new DataFlavor(java.awt.Image.class,
                       "Java Image");
}
/*************************************************************************/
/*
 * Instance Variables
 */
// The MIME type for this flavor
private final String mimeType;
// The representation class for this flavor
private final Class representationClass;
// The human readable name of this flavor
private String humanPresentableName;
/*************************************************************************/
/*
 * Static Methods
 */
/**
 * This method attempts to load the named class.  The following class
 * loaders are searched in order: the bootstrap class loader, the
 * system class loader, the context class loader (if it exists), and
 * the specified fallback class loader.
 *
 * @param className The name of the class to load.
 * @param classLoader The class loader to use if all others fail, which
 * may be null.
 *
 * @exception ClassNotFoundException If the class cannot be loaded.
 */
protected static final Class
tryToLoadClass(String className, ClassLoader classLoader)
               throws ClassNotFoundException
{
  try
    {
      return(Class.forName(className));
    }
  catch(Exception e) { ; }
  // Commented out for Java 1.1
  /*
  try
    {
      return(className.getClass().getClassLoader().findClass(className));
    }
  catch(Exception e) { ; }
  try
    {
      return(ClassLoader.getSystemClassLoader().findClass(className));
    }
  catch(Exception e) { ; }
  */
  // FIXME: What is the context class loader?
  /*
  try
    {
    }
  catch(Exception e) { ; }
  */
  if (classLoader != null)
    return(classLoader.loadClass(className));
  else
    throw new ClassNotFoundException(className);
}
/*************************************************************************/
/*
 * Constructors
 */
/**
 * Empty public constructor needed for externalization.
 * Should not be used for normal instantiation.
 */
public
DataFlavor()
{
    mimeType = null;
    representationClass = null;
    humanPresentableName = null;
}
/*************************************************************************/
/**
 * Private constructor.
 */
private
DataFlavor(Class representationClass,
	   String mimeType,
	   String humanPresentableName)
{
    this.representationClass = representationClass;
    this.mimeType = mimeType;
    if (humanPresentableName != null)
	this.humanPresentableName = humanPresentableName;
    else
	this.humanPresentableName = mimeType;
}
/*************************************************************************/
/**
 * Initializes a new instance of DataFlavor.  The class
 * and human readable name are specified, the MIME type will be
 * "application/x-java-serialized-object". If the human readable name
 * is not specified (null) then the human readable name
 * will be the same as the MIME type.
 *
 * @param representationClass The representation class for this object.
 * @param humanPresentableName The display name of the object.
 */
public
DataFlavor(Class representationClass, String humanPresentableName)
{
    this(representationClass,
       "application/x-java-serialized-object"
       + "; class="
       + representationClass.getName(),
       humanPresentableName);
}
/*************************************************************************/
/**
 * Initializes a new instance of DataFlavor with the
 * specified MIME type and description.  If the MIME type has a
 * "class=java.io.InputStream. If the human readable name
 * is not specified (null) then the human readable name
 * will be the same as the MIME type.
 *
 * @param mimeType The MIME type for this flavor.
 * @param humanPresentableName The display name of this flavor.
 * @param classLoader The class loader for finding classes if the default
 * class loaders do not work.
 *
 * @exception IllegalArgumentException If the representation class
 * specified cannot be loaded.
 * @exception ClassNotFoundException If the class is not loaded.
 */
public
DataFlavor(String mimeType, String humanPresentableName, 
           ClassLoader classLoader) throws ClassNotFoundException
{
  this(getRepresentationClassFromMime(mimeType, classLoader),
       mimeType, humanPresentableName);
}
private static Class
getRepresentationClassFromMime(String mimeString, ClassLoader classLoader)
{
  String classname = getParameter("class", mimeString);
  if (classname != null)
    {
      try
        {
          return tryToLoadClass(classname, classLoader);
        }
      catch(Exception e)
        {
          throw new IllegalArgumentException("classname: " + e.getMessage());
        }
    }
  else
    {
      return java.io.InputStream.class;
    }
}
/*************************************************************************/
/**
 * Initializes a new instance of DataFlavor with the
 * specified MIME type and description.  If the MIME type has a
 * "class=java.io.InputStream. If the human readable name
 * is not specified (null) then the human readable name
 * will be the same as the MIME type. This is the same as calling
 * new DataFlavor(mimeType, humanPresentableName, null).
 *
 * @param mimeType The MIME type for this flavor.
 * @param humanPresentableName The display name of this flavor.
 * @param classLoader The class loader for finding classes.
 *
 * @exception IllegalArgumentException If the representation class
 * specified cannot be loaded.
 */
public
DataFlavor(String mimeType, String humanPresentableName)
{
  this (getRepresentationClassFromMime (mimeType, null), humanPresentableName);
}
/*************************************************************************/
/**
 * Initializes a new instance of DataFlavor with the specified
 * MIME type.  This type can have a "class=" parameter to specify the
 * representation class, and then the class must exist or an exception will
 * be thrown. If there is no "class=" parameter then the representation class
 * will be java.io.InputStream. This is the same as calling
 * new DataFlavor(mimeType, null).
 *
 * @param mimeType The MIME type for this flavor.
 *
 * @exception IllegalArgumentException If a class is not specified in
 * the MIME type.
 * @exception ClassNotFoundException If the class cannot be loaded.
 */
public
DataFlavor(String mimeType) throws ClassNotFoundException
{
  this(mimeType, null);
}
/*************************************************************************/
/**
 * Returns the MIME type of this flavor.
 *
 * @return The MIME type for this flavor.
 */
public String
getMimeType()
{
  return(mimeType);
}
/*************************************************************************/
/**
 * Returns the representation class for this flavor.
 *
 * @return The representation class for this flavor.
 */
public Class
getRepresentationClass()
{
  return(representationClass);
}
/*************************************************************************/
/**
 * Returns the human presentable name for this flavor.
 *
 * @return The human presentable name for this flavor.
 */
public String
getHumanPresentableName()
{
  return(humanPresentableName);
} 
/*************************************************************************/
/**
 * Returns the primary MIME type for this flavor.
 *
 * @return The primary MIME type for this flavor.
 */
public String
getPrimaryType()
{
  int idx = mimeType.indexOf("/");
  if (idx == -1)
    return(mimeType);
  return(mimeType.substring(0, idx));
}
/*************************************************************************/
/**
 * Returns the MIME subtype for this flavor.
 *
 * @return The MIME subtype for this flavor.
 */
public String
getSubType()
{
  int idx = mimeType.indexOf("/");
  if (idx == -1)
    return("");
  String subtype = mimeType.substring(idx + 1);
  idx = subtype.indexOf(" ");
  if (idx == -1)
    return(subtype);
  else
    return(subtype.substring(0, idx));
}
/*************************************************************************/
/**
 * Returns the value of the named MIME type parameter, or null
 * if the parameter does not exist. Given the parameter name and the mime
 * string.
 *
 * @param paramName The name of the parameter.
 * @param mimeString The mime string from where the name should be found.
 *
 * @return The value of the parameter or null.
 */
private static String
getParameter(String paramName, String mimeString)
{
  int idx = mimeString.indexOf(paramName + "=");
  if (idx == -1)
    return(null);
  String value = mimeString.substring(idx + paramName.length() + 2);
  idx = value.indexOf(" ");
  if (idx == -1)
    return(value);
  else
    return(value.substring(0, idx));
}
/*************************************************************************/
/**
 * Returns the value of the named MIME type parameter, or null
 * if the parameter does not exist.
 *
 * @param paramName The name of the paramter.
 *
 * @return The value of the parameter.
 */
public String
getParameter(String paramName)
{
  return getParameter(paramName, mimeType);
}
/*************************************************************************/
/**
 * Sets the human presentable name to the specified value.
 *
 * @param humanPresentableName The new display name.
 */
public void
setHumanPresentableName(String humanPresentableName)
{
  this.humanPresentableName = humanPresentableName;
}
/*************************************************************************/
/**
 * Tests the MIME type of this object for equality against the specified
 * MIME type.
 *
 * @param mimeType The MIME type to test against.
 *
 * @return true if the MIME type is equal to this object's
 * MIME type, false otherwise.
 *
 * @exception NullPointerException If mimeType is null.
 */
public boolean
isMimeTypeEqual(String mimeType)
{
  // FIXME: Need to handle default attributes and parameters
  return(this.mimeType.equals(mimeType));
}
/*************************************************************************/
/**
 * Tests the MIME type of this object for equality against the specified
 * data flavor's MIME type
 *
 * @param flavor The flavor to test against.
 *
 * @return true if the flavor's MIME type is equal to this 
 * object's MIME type, false otherwise.
 */
public boolean
isMimeTypeEqual(DataFlavor flavor)
{
  return(isMimeTypeEqual(flavor.getMimeType()));
}
/*************************************************************************/
/**
 * Tests whether or not this flavor represents a serialized object.
 *
 * @return true if this flavor represents a serialized
 * object, false otherwise.
 */
public boolean
isMimeTypeSerializedObject()
{
  return(mimeType.startsWith(javaSerializedObjectMimeType));
}
/*************************************************************************/
/**
 * Tests whether or not this flavor has a representation class of
 * java.io.InputStream.
 *
 * @param true if the representation class of this flavor
 * is java.io.InputStream, false otherwise.
 */
public boolean
isRepresentationClassInputStream()
{
  return(representationClass.getName().equals("java.io.InputStream"));
}
/*************************************************************************/
/**
 * Tests whether the representation class for this flavor is
 * serializable.
 *
 * @param true if the representation class is serializable,
 * false otherwise.
 */
public boolean
isRepresentationClassSerializable()
{
  Class[] interfaces = representationClass.getInterfaces();
  int i = 0;
  while (i < interfaces.length)
    {
      if (interfaces[i].getName().equals("java.io.Serializable"))
        return(true);
      ++i;
    }
  return(false);
}
/*************************************************************************/
/**
 * Tests whether the representation class for his flavor is remote.
 *
 * @return true if the representation class is remote,
 * false otherwise.
 */
public boolean
isRepresentationClassRemote()
{
  // FIXME: Implement
  throw new RuntimeException("Not implemented");
}
/*************************************************************************/
/**
 * Tests whether or not this flavor represents a serialized object.
 *
 * @return true if this flavor represents a serialized
 * object, false otherwise.
 */
public boolean
isFlavorSerializedObjectType()
{
  // FIXME: What is the diff between this and isMimeTypeSerializedObject?
  return(mimeType.startsWith(javaSerializedObjectMimeType));
}
/*************************************************************************/
/**
 * Tests whether or not this flavor represents a remote object.
 *
 * @return true if this flavor represents a remote object,
 * false otherwise.
 */
public boolean
isFlavorRemoteObjectType()
{
  return(mimeType.startsWith(javaRemoteObjectMimeType));
}
/*************************************************************************/
/**
 * Tests whether or not this flavor represents a list of files.
 *
 * @return true if this flavor represents a list of files,
 * false otherwise.
 */
public boolean
isFlavorJavaFileListType()
{
  if (this.mimeType.equals(javaFileListFlavor.mimeType) &&
      this.representationClass.equals(javaFileListFlavor.representationClass))
    return(true);
  return(false);
}
/*************************************************************************/
/**
 * Returns a copy of this object.
 *
 * @return A copy of this object.
 *
 * @exception CloneNotSupportedException If the object's class does not support
 * the Cloneable interface. Subclasses that override the clone method can also
 * throw this exception to indicate that an instance cannot be cloned.
 */
public Object clone () throws CloneNotSupportedException
{
  try
    {
      return(super.clone());
    }
  catch(Exception e)
    {
      return(null);
    }
}
/*************************************************************************/
/**
 * This method test the specified DataFlavor for equality
 * against this object.  This will be true if the MIME type and
 * representation type are the equal.
 *
 * @param flavor The DataFlavor to test against.
 *
 * @return true if the flavor is equal to this object,
 * false otherwise.
 */
public boolean
equals(DataFlavor flavor)
{
  if (flavor == null)
    return(false);
  if (!this.mimeType.toLowerCase().equals(flavor.mimeType.toLowerCase()))
    return(false);
  if (!this.representationClass.equals(flavor.representationClass))
    return(false);
  return(true);
}
/*************************************************************************/
/**
 * This method test the specified Object for equality
 * against this object.  This will be true if the following conditions
 * are met:
 * *
null.
 * DataFlavor.
 * Object to test against.
 *
 * @return true if the flavor is equal to this object,
 * false otherwise.
 */
public boolean
equals(Object obj)
{
  if (obj == null)
    return(false);
  if (!(obj instanceof DataFlavor))
    return(false);
  return(equals((DataFlavor)obj));
}
/*************************************************************************/
/**
 * Tests whether or not the specified string is equal to the MIME type
 * of this object.
 *
 * @param str The string to test against.
 *
 * @return true if the string is equal to this object's MIME
 * type, false otherwise.
 *
 * @deprecated Not compatible with hashCode().
 *             Use isMimeTypeEqual()
 */
public boolean
equals(String str)
{
  return(isMimeTypeEqual(str));
}
/*************************************************************************/
/**
 * Returns the hash code for this data flavor.
 * The hash code is based on the (lower case) mime type and the
 * representation class.
 */
public int
hashCode()
{
  return(mimeType.toLowerCase().hashCode()^representationClass.hashCode());
}
/*************************************************************************/
/**
 * Returns true when the given DataFlavor
 * matches this one.
 */
public boolean
match(DataFlavor dataFlavor)
{
  // XXX - How is this different from equals?
  return(equals(dataFlavor));
}
/*************************************************************************/
/**
 * This method exists for backward compatibility.  It simply returns
 * the same name/value pair passed in.
 *
 * @param name The parameter name.
 * @param value The parameter value.
 *
 * @return The name/value pair.
 *
 * @deprecated
 */
protected String
normalizeMimeTypeParameter(String name, String value)
{
  return(name + "=" + value);
}
/*************************************************************************/
/**
 * This method exists for backward compatibility.  It simply returns
 * the MIME type string unchanged.
 *
 * @param type The MIME type.
 * 
 * @return The MIME type.
 *
 * @deprecated
 */
protected String
normalizeMimeType(String type)
{
  return(type);
}
/*************************************************************************/
/**
 * Serialize this class.
 *
 * @param stream The ObjectOutput stream to serialize to.
 *
 * @exception IOException If an error occurs.
 */
public void
writeExternal(ObjectOutput stream) throws IOException
{
  // FIXME: Implement me
}
/*************************************************************************/
/**
 * De-serialize this class.
 *
 * @param stream The ObjectInput stream to deserialize from.
 *
 * @exception IOException If an error ocurs.
 * @exception ClassNotFoundException If the class for an object being restored
 * cannot be found.
 */
public void
readExternal(ObjectInput stream) throws IOException, ClassNotFoundException
{
  // FIXME: Implement me
}
/*************************************************************************/
/**
 * Returns a string representation of this DataFlavor. Including the
 * representation class name, MIME type and human presentable name.
 */
public String
toString()
{
  return("DataFlavor[representationClass="
         + representationClass.getName()
         + ",mimeType="
         + mimeType
         + "humanPresentableName="
         + humanPresentableName);
}
/*************************************************************************/
/**
 * XXX - Currently returns plainTextFlavor.
 */
public static final DataFlavor
getTextPlainUnicodeFlavor()
{
  return(plainTextFlavor);
}
/*************************************************************************/
/**
 * XXX - Currently returns java.io.InputStream.
 *
 * @since 1.3
 */
public final Class
getDefaultRepresentationClass()
{
  return(java.io.InputStream.class);
}
/*************************************************************************/
/**
 * XXX - Currently returns java.io.InputStream.
 */
public final String
getDefaultRepresentationClassAsString()
{
  return(getDefaultRepresentationClass().getName());
}
/*************************************************************************/
/**
 * Selects the best supported text flavor on this implementation.
 * Returns null when none of the given flavors is liked.
 *
 * The DataFlavor returned the first data flavor in the
 * array that has either a representation class which is (a subclass of)
 * Reader or String, or has a representation
 * class which is (a subclass of) InputStream and has a
 * primary MIME type of "text" and has an supported encoding.
 */
public static final DataFlavor
selectBestTextFlavor(DataFlavor[] availableFlavors)
{
  for(int i=0; iTransferable.
 *
 * If the representation class is a (subclass of) Reader
 * then an instance of the representation class is returned. If the
 * representatation class is a String then a
 * StringReader is returned. And if the representation class
 * is a (subclass of) InputStream and the primary MIME type
 * is "text" then a InputStreamReader for the correct charset
 * encoding is returned.
 *
 * @param transferable The Transferable for which a text
 *                     Reader is requested.
 *
 * @exception IllegalArgumentException If the representation class is not one
 * of the seven listed above or the Transferable has null data.
 * @exception NullPointerException If the Transferable is null.
 * @exception UnsupportedFlavorException when the transferable doesn't
 * support this DataFlavor. Or if the representable class
 * isn't a (subclass of) Reader, String,
 * InputStream and/or the primary MIME type isn't "text".
 * @exception IOException when any IOException occurs.
 * @exception UnsupportedEncodingException if the "charset" isn't supported
 * on this platform.
 */
public Reader getReaderForText(Transferable transferable)
  throws UnsupportedFlavorException, IOException
{
    if (!transferable.isDataFlavorSupported(this))
        throw new UnsupportedFlavorException(this);
    if (Reader.class.isAssignableFrom(representationClass))
        return((Reader)transferable.getTransferData(this));
    if (String.class.isAssignableFrom(representationClass))
        return(new StringReader((String)transferable.getTransferData(this)));
    if (InputStream.class.isAssignableFrom(representationClass)
        && "text".equals(getPrimaryType()))
      {
        InputStream in = (InputStream)transferable.getTransferData(this);
        String encoding = getParameter("charset");
        if (encoding == null)
            encoding = "us-ascii";
        return(new InputStreamReader(in, encoding));
      }
    throw new UnsupportedFlavorException(this);
}
  /**
   * Returns whether the representation class for this DataFlavor is
   * @see java.nio.ByteBuffer or a subclass thereof.
   *
   * @since 1.4
   */
  public boolean isRepresentationClassByteBuffer ()
  {
    return ByteBuffer.class.isAssignableFrom (representationClass);
  }
  /**
   * Returns whether the representation class for this DataFlavor is
   * @see java.nio.CharBuffer or a subclass thereof.
   *
   * @since 1.4
   */
  public boolean isRepresentationClassCharBuffer ()
  {
    return CharBuffer.class.isAssignableFrom (representationClass);
  }
  /**
   * Returns whether the representation class for this DataFlavor is
   * @see java.io.Reader or a subclass thereof.
   *
   * @since 1.4
   */
  public boolean isRepresentationClassReader ()
  {
    return Reader.class.isAssignableFrom (representationClass);
  }
} // class DataFlavor