();
  }
  /**
   * Returns the (System)FlavorMap for the current thread's
   * ClassLoader.
   */
  public static FlavorMap getDefaultFlavorMap ()
  {
    ClassLoader classLoader = Thread.currentThread()
        .getContextClassLoader();
    //if ContextClassLoader not set, use system default
    if (classLoader == null)
      {
        classLoader = ClassLoader.getSystemClassLoader();
      }
    synchronized(systemFlavorMaps)
      {
        FlavorMap map = (FlavorMap)
            systemFlavorMaps.get(classLoader);
        if (map == null)
          {
            map = new SystemFlavorMap();
            systemFlavorMaps.put(classLoader, map);
          }
        return map;
      }
  }
  /**
   * Encodes a MIME type for use as a String native. The format
   * of an encoded representation of a MIME type is implementation-dependent.
   * The only restrictions are:
   * 
   * - The encoded representation is nullif and only if the
   * MIME typeStringisnull.
*- The encoded representations for two non-nullMIME type
   *Strings are equal if and only if theseStrings
   * are equal according toString.equals(Object).
*
*
   * The present implementation of this method returns the specified MIME
   * type String prefixed with gnu.java:.
   *
   * @param mime the MIME type to encode
   * @return the encoded String, or null if
   *         mimeType is null
   */
  public static String encodeJavaMIMEType (String mime)
  {
    if (mime != null)
      return GNU_JAVA_MIME_PREFIX + mime;
    else
      return null;
  }
  /**
   * Encodes a DataFlavor for use as a String
   * native. The format of an encoded DataFlavor is
   * implementation-dependent. The only restrictions are:
   * 
   * - The encoded representation is nullif and only if the
   * specifiedDataFlavorisnullor its MIME type
   *Stringisnull.
*- The encoded representations for two non-null*DataFlavors with non-nullMIME type
   *Strings are equal if and only if the MIME type
   *Strings of theseDataFlavors are equal
   * according toString.equals(Object).
*
*
   * The present implementation of this method returns the MIME type
   * String of the specified DataFlavor prefixed
   * with gnu.java:.
   *
   * @param df the DataFlavor to encode
   * @return the encoded String, or null if
   *         flav is null or has a null MIME type
   */
  public static String encodeDataFlavor (DataFlavor df)
  {
    if (df != null)
      {
        return encodeJavaMIMEType(df.getMimeType());
      }
    else
      return null;
  }
  /**
   * Returns true if the native type name can be represented as
   * a java mime type. Returns false if parameter is
   * null.
   */
  public static boolean isJavaMIMEType (String name)
  {
    return (name != null && name.startsWith(GNU_JAVA_MIME_PREFIX));
  }
  /**
   * Decodes a String native for use as a Java MIME type.
   *
   * @param name the String to decode
   * @return the decoded Java MIME type, or null if nat
   *         is not an encoded String native
   */
  public static String decodeJavaMIMEType (String name)
  {
    if (isJavaMIMEType(name))
      {
        return name.substring(GNU_JAVA_MIME_PREFIX.length());
      }
    else
      return null;
  }
  /**
   * Returns the data flavor given the native type name
   * or null when no such data flavor exists.
   */
  public static DataFlavor decodeDataFlavor (String name)
    throws ClassNotFoundException
  {
    String javaMIMEType = decodeJavaMIMEType (name);
    if (javaMIMEType != null)
      return new DataFlavor (javaMIMEType);
    else
      return null;
  }
  /**
   * Returns a List of DataFlavors to which the specified
   * String native can be translated by the data transfer
   * subsystem. The List will be sorted from best
   * DataFlavor to worst. That is, the first DataFlavor
   *  will best reflect data in the specified native to a Java
   * application.
   * 
   * If the specified native is previously unknown to the data transfer
   * subsystem, and that native has been properly encoded, then invoking
   * this method will establish a mapping in both directions between the
   * specified native and a DataFlavor whose MIME type is a decoded
   * version of the native.
   */
  public List getFlavorsForNative(String nat)
  {
    List ret = new ArrayList();
    if (nat == null)
      {
        Collection> all = nativeToFlavorMap.values();
        for (List list : all)
          {
            for (DataFlavor flav : list)
              {
                if (! ret.contains(flav))
                  ret.add(flav);
              }
          }
      }
    else
      {
        List list = nativeToFlavorMap.get(nat);
        if (list != null)
          ret.addAll(list);
      }
    return ret;
  }
  public List getNativesForFlavor (DataFlavor flav)
  {
    List ret = new ArrayList();
    if (flav == null)
      {
        Collection> all = flavorToNativeMap.values();
        for (List list : all)
          {
            for (String nat : list)
              {
                if (! ret.contains(nat))
                  ret.add(nat);
              }
          }
      }
    else
      {
        List list = flavorToNativeMap.get(flav);
        if (list != null)
          ret.addAll(list);
      }
    return ret;
  }
  /**
   * Adds a mapping from a single String native to a single
   * DataFlavor. Unlike getFlavorsForNative, the
   * mapping will only be established in one direction, and the native will
   * not be encoded. To establish a two-way mapping, call
   * addUnencodedNativeForFlavor as well. The new mapping will
   * be of lower priority than any existing mapping.
   * This method has no effect if a mapping from the specified
   * String native to the specified or equal
   * DataFlavor already exists.
   *
   * @param nativeStr the String native key for the mapping
   * @param flavor the DataFlavor value for the mapping
   * @throws NullPointerException if nat or flav is null
   *
   * @see #addUnencodedNativeForFlavor
   * @since 1.4
   */
  public synchronized void addFlavorForUnencodedNative(String nativeStr,
                                                       DataFlavor flavor)
  {
    if ((nativeStr == null) || (flavor == null))
      throw new NullPointerException();
    List flavors = nativeToFlavorMap.get(nativeStr);
    if (flavors == null)
      {
        flavors = new ArrayList();
        nativeToFlavorMap.put(nativeStr, flavors);
      }
    else
      {
        if (! flavors.contains(flavor))
          flavors.add(flavor);
      }
  }
  /**
   * Adds a mapping from the specified DataFlavor (and all
   * DataFlavors equal to the specified DataFlavor)
   * to the specified String native.
   * Unlike getNativesForFlavor, the mapping will only be
   * established in one direction, and the native will not be encoded. To
   * establish a two-way mapping, call
   * addFlavorForUnencodedNative as well. The new mapping will
   * be of lower priority than any existing mapping.
   * This method has no effect if a mapping from the specified or equal
   * DataFlavor to the specified String native
   * already exists.
   *
   * @param flavor the DataFlavor key for the mapping
   * @param nativeStr the String native value for the mapping
   * @throws NullPointerException if flav or nat is null
   *
   * @see #addFlavorForUnencodedNative
   * @since 1.4
   */
  public synchronized void addUnencodedNativeForFlavor(DataFlavor flavor,
                                                       String nativeStr)
  {
    if ((nativeStr == null) || (flavor == null))
      throw new NullPointerException();
    List natives = flavorToNativeMap.get(flavor);
    if (natives == null)
      {
        natives = new ArrayList();
        flavorToNativeMap.put(flavor, natives);
      }
    else
      {
        if (! natives.contains(nativeStr))
          natives.add(nativeStr);
      }
  }
  /**
   * Discards the current mappings for the specified DataFlavor
   * and all DataFlavors equal to the specified
   * DataFlavor, and creates new mappings to the
   * specified String natives.
   * Unlike getNativesForFlavor, the mappings will only be
   * established in one direction, and the natives will not be encoded. To
   * establish two-way mappings, call setFlavorsForNative
   * as well. The first native in the array will represent the highest
   * priority mapping. Subsequent natives will represent mappings of
   * decreasing priority.
   * 
   * If the array contains several elements that reference equal
   * String natives, this method will establish new mappings
   * for the first of those elements and ignore the rest of them.
   * 
   * It is recommended that client code not reset mappings established by the
   * data transfer subsystem. This method should only be used for
   * application-level mappings.
   *
   * @param flavor the DataFlavor key for the mappings
   * @param natives the String native values for the mappings
   * @throws NullPointerException if flav or natives is null
   *         or if natives contains null elements
   *
   * @see #setFlavorsForNative
   * @since 1.4
   */
  public synchronized void setNativesForFlavor(DataFlavor flavor,
                                               String[] natives)
  {
    if ((natives == null) || (flavor == null))
      throw new NullPointerException();
    flavorToNativeMap.remove(flavor);
    for (int i = 0; i < natives.length; i++)
      {
        addUnencodedNativeForFlavor(flavor, natives[i]);
      }
  }
  /**
   * Discards the current mappings for the specified String
   * native, and creates new mappings to the specified
   * DataFlavors. Unlike getFlavorsForNative, the
   * mappings will only be established in one direction, and the natives need
   * not be encoded. To establish two-way mappings, call
   * setNativesForFlavor as well. The first
   * DataFlavor in the array will represent the highest priority
   * mapping. Subsequent DataFlavors will represent mappings of
   * decreasing priority.
   * 
   * If the array contains several elements that reference equal
   * DataFlavors, this method will establish new mappings
   * for the first of those elements and ignore the rest of them.
   * 
   * It is recommended that client code not reset mappings established by the
   * data transfer subsystem. This method should only be used for
   * application-level mappings.
   *
   * @param nativeStr the String native key for the mappings
   * @param flavors the DataFlavor values for the mappings
   * @throws NullPointerException if nat or flavors is null
   *         or if flavors contains null elements
   *
   * @see #setNativesForFlavor
   * @since 1.4
   */
  public synchronized void setFlavorsForNative(String nativeStr,
                                               DataFlavor[] flavors)
  {
    if ((nativeStr == null) || (flavors == null))
      throw new NullPointerException();
    nativeToFlavorMap.remove(nativeStr);
    for (int i = 0; i < flavors.length; i++)
      {
        addFlavorForUnencodedNative(nativeStr, flavors[i]);
      }
  }
} // class SystemFlavorMap