1. /*
  2. * @(#)SystemFlavorMap.java 1.12 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt.datatransfer;
  8. import java.awt.Toolkit;
  9. import java.io.File;
  10. import java.io.InputStream;
  11. import java.io.IOException;
  12. import java.net.URL;
  13. import java.net.MalformedURLException;
  14. import java.util.Enumeration;
  15. import java.util.Hashtable;
  16. import java.util.HashMap;
  17. import java.util.WeakHashMap;
  18. import java.util.Map;
  19. import java.util.Properties;
  20. /**
  21. * <p>
  22. * The SystemFlavorMap is an externally configurable map that maps platform native
  23. * type names (strings) to MIME type strings, and also their associated
  24. * DataFlavors.
  25. * </p>
  26. * This map is used by the DnD system to map platform data types to MIME
  27. * types to enable the transfer of objects between Java and the platform via
  28. * the platform DnD System.
  29. * </p>
  30. *
  31. * @version 1.12
  32. * @since JDK1.2
  33. *
  34. */
  35. public final class SystemFlavorMap implements FlavorMap {
  36. /**
  37. * constant prefix used to tag Java types converted to native platform type
  38. */
  39. private static String JavaMIME = "JAVA_DATAFLAVOR:";
  40. /*
  41. * system singleton
  42. */
  43. private static final WeakHashMap flavorMaps = new WeakHashMap();
  44. /**
  45. * get the default system implementation
  46. */
  47. public static FlavorMap getDefaultFlavorMap() {
  48. ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
  49. if (contextClassLoader == null)
  50. contextClassLoader = ClassLoader.getSystemClassLoader();
  51. FlavorMap fm;
  52. synchronized(flavorMaps) {
  53. if ((fm = (FlavorMap)flavorMaps.get(contextClassLoader)) == null)
  54. flavorMaps.put(contextClassLoader, fm = new SystemFlavorMap());
  55. }
  56. return fm;
  57. }
  58. /**
  59. * construct a SystemFlavorMap
  60. */
  61. private SystemFlavorMap() {
  62. super();
  63. final Properties defaults[] = {null};
  64. final boolean shouldReturn[]= {false};
  65. java.security.AccessController.doPrivileged(
  66. new java.security.PrivilegedAction() {
  67. public Object run() {
  68. String sep = File.separator;
  69. String home = System.getProperty("java.home");
  70. String deffmURL = "file:" +
  71. home +
  72. sep +
  73. "lib" +
  74. sep +
  75. "flavormap.properties";
  76. try {
  77. defaults[0] = new Properties();
  78. defaults[0].load(((URL)new URL(deffmURL)).openStream());
  79. } catch (Exception e) {
  80. System.err.println("Exception:" + e + " while loading default flavormap.properties file URL:" + deffmURL);
  81. defaults[0] = null;
  82. }
  83. nativeToMIME = new Properties(defaults[0]);
  84. String propURLName = Toolkit.getDefaultToolkit().getProperty("AWT.DnD.flavorMapFileURL", null);
  85. InputStream is = null;
  86. if (propURLName != null) try {
  87. is = ((URL)new URL(propURLName)).openStream();
  88. } catch (MalformedURLException fnfe) {
  89. System.err.println(getClass().getName() + ": Malformed URL for flavormap: " + propURLName);
  90. } catch (IOException ioe) {
  91. System.err.println(getClass().getName() + ": IOException during open of flavormap: " + propURLName);
  92. }
  93. if (is != null) try {
  94. nativeToMIME.load(is);
  95. } catch (IOException ioe) {
  96. System.err.println(getClass().getName() + "IOException during load of flavormap: " + propURLName);
  97. shouldReturn[0] = true;
  98. return null;
  99. }
  100. return null;
  101. }
  102. });
  103. if (shouldReturn[0])
  104. return;
  105. int tsize = nativeToMIME.size() + (defaults[0] != null ? defaults[0].size() : 0);
  106. int size = tsize > 0 ? tsize : 1;
  107. flavorToNative = new HashMap(size);
  108. nativeToFlavor = new HashMap(size);
  109. if (tsize > 0) {
  110. Enumeration e = nativeToMIME.propertyNames();
  111. while (e.hasMoreElements()) {
  112. String natives = (String)e.nextElement();
  113. String mime = (String)nativeToMIME.getProperty(natives);
  114. DataFlavor df = null;
  115. // we try the first form of the constructor to see if
  116. // the Mime Type fully specifies a MIME for a DataFlavor
  117. // if that fails we'll construct using another form that
  118. // enforces a default representation class and HPN
  119. try {
  120. df = new DataFlavor(mime);
  121. } catch (Exception ee) {
  122. try {
  123. df = new DataFlavor(mime, (String)null);
  124. } catch (Exception eee) {
  125. eee.printStackTrace();
  126. continue;
  127. }
  128. }
  129. flavorToNative.put(df.getMimeType(), natives);
  130. nativeToFlavor.put(natives, df);
  131. }
  132. }
  133. }
  134. /**
  135. * map flavors to native data types names
  136. */
  137. public synchronized Map getNativesForFlavors(DataFlavor[] flavors) {
  138. int i;
  139. if (flavors == null) return (Map)flavorToNative.clone();
  140. if (flavors.length == 0) return null;
  141. Map map = new HashMap(flavors.length);
  142. for (i = 0; i < flavors.length; i++) {
  143. DataFlavor df = flavors[i];
  144. String mts = df.getMimeType();
  145. String n = (String)flavorToNative.get(mts);
  146. if (n == null) {
  147. String emts = encodeJavaMIMEType(mts);
  148. map.put(df, emts);
  149. nativeToFlavor.put(emts, df);
  150. flavorToNative.put(mts, emts);
  151. } else {
  152. map.put(df, n);
  153. }
  154. }
  155. return map;
  156. }
  157. /**
  158. * map natives to corresponding flavors
  159. */
  160. public synchronized Map getFlavorsForNatives(String[] natives) {
  161. int nonnull = 0;
  162. int i;
  163. if (natives == null) return (Map)nativeToFlavor.clone();
  164. if (natives.length == 0) return new HashMap();
  165. Map map = new HashMap(natives.length);
  166. for (i = 0; i < natives.length ; i++) {
  167. String n = natives[i];
  168. DataFlavor df = null;
  169. if (isJavaMIMEType(natives[i])) {
  170. String emts = natives[i];
  171. if ((df = (DataFlavor)nativeToFlavor.get(emts)) == null) {
  172. String mts = decodeJavaMIMEType(natives[i]);
  173. try {
  174. df = new DataFlavor(mts);
  175. } catch (Exception e) {
  176. System.err.println("Exception \"" + e.getClass().getName() + ": " + e.getMessage() + "\"while constructing DataFlavor for: " + mts);
  177. df = null;
  178. }
  179. if (df != null) {
  180. nativeToFlavor.put(emts, df);
  181. flavorToNative.put(df.getMimeType(), emts);
  182. }
  183. }
  184. } else df = (DataFlavor)nativeToFlavor.get(n);
  185. if (df != null) map.put(n, df);
  186. }
  187. return map;
  188. }
  189. /**
  190. * @return encode a Java MIMEType for use as a native type name
  191. */
  192. public static String encodeJavaMIMEType(String mimeType) {
  193. return JavaMIME + mimeType;
  194. }
  195. /**
  196. * @return encode a Java MIMEType for use as a native type name
  197. */
  198. public static String encodeDataFlavor(DataFlavor df) {
  199. return JavaMIME + df.getMimeType();
  200. }
  201. /**
  202. * @return if the native type string is an encoded Java MIMEType
  203. */
  204. public static boolean isJavaMIMEType(String atom) {
  205. return atom != null && atom.startsWith(JavaMIME, 0);
  206. }
  207. /**
  208. * @return the decoded Java MIMEType string
  209. */
  210. public static String decodeJavaMIMEType(String atom) {
  211. if (!isJavaMIMEType(atom)) return null;
  212. return atom.substring(JavaMIME.length(), atom.length()).trim();
  213. }
  214. /**
  215. * @return the decoded Java MIMEType as a DataFlavor
  216. */
  217. public static DataFlavor decodeDataFlavor(String atom) throws ClassNotFoundException {
  218. if (!isJavaMIMEType(atom)) return null;
  219. return new DataFlavor(atom.substring(JavaMIME.length(), atom.length()).trim());
  220. }
  221. /*
  222. * fields
  223. */
  224. private Properties nativeToMIME;
  225. private HashMap flavorToNative;
  226. private HashMap nativeToFlavor;
  227. }