Frames | No Frames |
1: /* SystemFlavorMap.java -- Maps between native flavor names and MIME types. 2: Copyright (C) 2001, 2004 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 gnu.classpath.NotImplementedException; 42: 43: import java.util.ArrayList; 44: import java.util.HashMap; 45: import java.util.List; 46: import java.util.Map; 47: import java.util.WeakHashMap; 48: 49: /** 50: * This class maps between native platform type names and DataFlavors. 51: * 52: * XXX - The current implementation does no mapping at all. 53: * 54: * @author Mark Wielaard (mark@klomp.org) 55: * 56: * @since 1.2 57: */ 58: public final class SystemFlavorMap implements FlavorMap, FlavorTable 59: { 60: /** 61: * The map which maps the thread's <code>ClassLoaders</code> to 62: * <code>SystemFlavorMaps</code>. 63: */ 64: private static final Map systemFlavorMaps = new WeakHashMap(); 65: 66: /** 67: * Constant which is used to prefix encode Java MIME types. 68: */ 69: private static final String GNU_JAVA_MIME_PREFIX = "gnu.java:"; 70: 71: /** 72: * This map maps native <code>String</code>s to lists of 73: * <code>DataFlavor</code>s 74: */ 75: private HashMap nativeToFlavorMap = new HashMap(); 76: 77: /** 78: * This map maps <code>DataFlavor</code>s to lists of native 79: * <code>String</code>s 80: */ 81: private HashMap flavorToNativeMap = new HashMap(); 82: 83: /** 84: * Private constructor. 85: */ 86: private SystemFlavorMap () 87: { 88: } 89: 90: /** 91: * Maps the specified <code>DataFlavor</code> objects to the native 92: * data type name. The returned <code>Map</code> has keys that are 93: * the data flavors and values that are strings. The returned map 94: * may be modified. This can be useful for implementing nested mappings. 95: * 96: * @param flavors An array of data flavors to map 97: * or null for all data flavors. 98: * 99: * @return A <code>Map</code> of native data types to data flavors. 100: */ 101: public Map getNativesForFlavors (DataFlavor[] flavors) 102: { 103: return new HashMap(); 104: } 105: 106: /** 107: * Maps the specified native type names to <code>DataFlavor</code>'s. 108: * The returned <code>Map</code> has keys that are strings and values 109: * that are <code>DataFlavor</code>'s. The returned map may be 110: * modified. This can be useful for implementing nested mappings. 111: * 112: * @param natives An array of native types to map 113: * or null for all native types. 114: * 115: * @return A <code>Map</code> of data flavors to native type names. 116: */ 117: public Map getFlavorsForNatives (String[] natives) 118: { 119: return new HashMap(); 120: } 121: 122: /** 123: * Returns the (System)FlavorMap for the current thread's 124: * ClassLoader. 125: */ 126: public static FlavorMap getDefaultFlavorMap () 127: { 128: ClassLoader classLoader = Thread.currentThread() 129: .getContextClassLoader(); 130: 131: //if ContextClassLoader not set, use system default 132: if (classLoader == null) 133: { 134: classLoader = ClassLoader.getSystemClassLoader(); 135: } 136: 137: synchronized(systemFlavorMaps) 138: { 139: FlavorMap map = (FlavorMap) 140: systemFlavorMaps.get(classLoader); 141: if (map == null) 142: { 143: map = new SystemFlavorMap(); 144: systemFlavorMaps.put(classLoader, map); 145: } 146: return map; 147: } 148: } 149: 150: /** 151: * Encodes a MIME type for use as a <code>String</code> native. The format 152: * of an encoded representation of a MIME type is implementation-dependent. 153: * The only restrictions are: 154: * <ul> 155: * <li>The encoded representation is <code>null</code> if and only if the 156: * MIME type <code>String</code> is <code>null</code>.</li> 157: * <li>The encoded representations for two non-<code>null</code> MIME type 158: * <code>String</code>s are equal if and only if these <code>String</code>s 159: * are equal according to <code>String.equals(Object)</code>.</li> 160: * </ul> 161: * <p> 162: * The present implementation of this method returns the specified MIME 163: * type <code>String</code> prefixed with <code>gnu.java:</code>. 164: * 165: * @param mime the MIME type to encode 166: * @return the encoded <code>String</code>, or <code>null</code> if 167: * mimeType is <code>null</code> 168: */ 169: public static String encodeJavaMIMEType (String mime) 170: { 171: if (mime != null) 172: return GNU_JAVA_MIME_PREFIX + mime; 173: else 174: return null; 175: } 176: 177: /** 178: * Encodes a <code>DataFlavor</code> for use as a <code>String</code> 179: * native. The format of an encoded <code>DataFlavor</code> is 180: * implementation-dependent. The only restrictions are: 181: * <ul> 182: * <li>The encoded representation is <code>null</code> if and only if the 183: * specified <code>DataFlavor</code> is <code>null</code> or its MIME type 184: * <code>String</code> is <code>null</code>.</li> 185: * <li>The encoded representations for two non-<code>null</code> 186: * <code>DataFlavor</code>s with non-<code>null</code> MIME type 187: * <code>String</code>s are equal if and only if the MIME type 188: * <code>String</code>s of these <code>DataFlavor</code>s are equal 189: * according to <code>String.equals(Object)</code>.</li> 190: * </ul> 191: * <p> 192: * The present implementation of this method returns the MIME type 193: * <code>String</code> of the specified <code>DataFlavor</code> prefixed 194: * with <code>gnu.java:</code>. 195: * 196: * @param df the <code>DataFlavor</code> to encode 197: * @return the encoded <code>String</code>, or <code>null</code> if 198: * flav is <code>null</code> or has a <code>null</code> MIME type 199: */ 200: public static String encodeDataFlavor (DataFlavor df) 201: { 202: if (df != null) 203: { 204: return encodeJavaMIMEType(df.getMimeType()); 205: } 206: else 207: return null; 208: } 209: 210: /** 211: * Returns true if the native type name can be represented as 212: * a java mime type. Returns <code>false</code> if parameter is 213: * <code>null</code>. 214: */ 215: public static boolean isJavaMIMEType (String name) 216: { 217: return (name != null && name.startsWith(GNU_JAVA_MIME_PREFIX)); 218: } 219: 220: /** 221: * Decodes a <code>String</code> native for use as a Java MIME type. 222: * 223: * @param name the <code>String</code> to decode 224: * @return the decoded Java MIME type, or <code>null</code> if nat 225: * is not an encoded <code>String</code> native 226: */ 227: public static String decodeJavaMIMEType (String name) 228: { 229: if (isJavaMIMEType(name)) 230: { 231: return name.substring(GNU_JAVA_MIME_PREFIX.length()); 232: } 233: else 234: return null; 235: } 236: 237: /** 238: * Returns the data flavor given the native type name 239: * or null when no such data flavor exists. 240: */ 241: public static DataFlavor decodeDataFlavor (String name) 242: throws ClassNotFoundException 243: { 244: String javaMIMEType = decodeJavaMIMEType (name); 245: 246: if (javaMIMEType != null) 247: return new DataFlavor (javaMIMEType); 248: else 249: return null; 250: } 251: 252: /** 253: * Returns a List of <code>DataFlavors</code> to which the specified 254: * <code>String</code> native can be translated by the data transfer 255: * subsystem. The <code>List</code> will be sorted from best 256: * <code>DataFlavor</code> to worst. That is, the first <code>DataFlavor 257: * </code> will best reflect data in the specified native to a Java 258: * application. 259: * <p> 260: * If the specified native is previously unknown to the data transfer 261: * subsystem, and that native has been properly encoded, then invoking 262: * this method will establish a mapping in both directions between the 263: * specified native and a DataFlavor whose MIME type is a decoded 264: * version of the native. 265: */ 266: public List getFlavorsForNative (String nat) 267: throws NotImplementedException 268: { 269: throw new Error ("Not implemented"); 270: } 271: 272: public List getNativesForFlavor (DataFlavor flav) 273: throws NotImplementedException 274: { 275: throw new Error ("Not implemented"); 276: } 277: 278: /** 279: * Adds a mapping from a single <code>String</code> native to a single 280: * <code>DataFlavor</code>. Unlike <code>getFlavorsForNative</code>, the 281: * mapping will only be established in one direction, and the native will 282: * not be encoded. To establish a two-way mapping, call 283: * <code>addUnencodedNativeForFlavor</code> as well. The new mapping will 284: * be of lower priority than any existing mapping. 285: * This method has no effect if a mapping from the specified 286: * <code>String</code> native to the specified or equal 287: * <code>DataFlavor</code> already exists. 288: * 289: * @param nativeStr the <code>String</code> native key for the mapping 290: * @param flavor the <code>DataFlavor</code> value for the mapping 291: * @throws NullPointerException if nat or flav is <code>null</code> 292: * 293: * @see #addUnencodedNativeForFlavor 294: * @since 1.4 295: */ 296: public synchronized void addFlavorForUnencodedNative(String nativeStr, 297: DataFlavor flavor) 298: { 299: if ((nativeStr == null) || (flavor == null)) 300: throw new NullPointerException(); 301: List flavors = (List) nativeToFlavorMap.get(nativeStr); 302: if (flavors == null) 303: { 304: flavors = new ArrayList(); 305: nativeToFlavorMap.put(nativeStr, flavors); 306: } 307: else 308: { 309: if (! flavors.contains(flavor)) 310: flavors.add(flavor); 311: } 312: } 313: 314: /** 315: * Adds a mapping from the specified <code>DataFlavor</code> (and all 316: * <code>DataFlavor</code>s equal to the specified <code>DataFlavor</code>) 317: * to the specified <code>String</code> native. 318: * Unlike <code>getNativesForFlavor</code>, the mapping will only be 319: * established in one direction, and the native will not be encoded. To 320: * establish a two-way mapping, call 321: * <code>addFlavorForUnencodedNative</code> as well. The new mapping will 322: * be of lower priority than any existing mapping. 323: * This method has no effect if a mapping from the specified or equal 324: * <code>DataFlavor</code> to the specified <code>String</code> native 325: * already exists. 326: * 327: * @param flavor the <code>DataFlavor</code> key for the mapping 328: * @param nativeStr the <code>String</code> native value for the mapping 329: * @throws NullPointerException if flav or nat is <code>null</code> 330: * 331: * @see #addFlavorForUnencodedNative 332: * @since 1.4 333: */ 334: public synchronized void addUnencodedNativeForFlavor(DataFlavor flavor, 335: String nativeStr) 336: { 337: if ((nativeStr == null) || (flavor == null)) 338: throw new NullPointerException(); 339: List natives = (List) flavorToNativeMap.get(flavor); 340: if (natives == null) 341: { 342: natives = new ArrayList(); 343: flavorToNativeMap.put(flavor, natives); 344: } 345: else 346: { 347: if (! natives.contains(nativeStr)) 348: natives.add(nativeStr); 349: } 350: } 351: 352: /** 353: * Discards the current mappings for the specified <code>DataFlavor</code> 354: * and all <code>DataFlavor</code>s equal to the specified 355: * <code>DataFlavor</code>, and creates new mappings to the 356: * specified <code>String</code> natives. 357: * Unlike <code>getNativesForFlavor</code>, the mappings will only be 358: * established in one direction, and the natives will not be encoded. To 359: * establish two-way mappings, call <code>setFlavorsForNative</code> 360: * as well. The first native in the array will represent the highest 361: * priority mapping. Subsequent natives will represent mappings of 362: * decreasing priority. 363: * <p> 364: * If the array contains several elements that reference equal 365: * <code>String</code> natives, this method will establish new mappings 366: * for the first of those elements and ignore the rest of them. 367: * <p> 368: * It is recommended that client code not reset mappings established by the 369: * data transfer subsystem. This method should only be used for 370: * application-level mappings. 371: * 372: * @param flavor the <code>DataFlavor</code> key for the mappings 373: * @param natives the <code>String</code> native values for the mappings 374: * @throws NullPointerException if flav or natives is <code>null</code> 375: * or if natives contains <code>null</code> elements 376: * 377: * @see #setFlavorsForNative 378: * @since 1.4 379: */ 380: public synchronized void setNativesForFlavor(DataFlavor flavor, 381: String[] natives) 382: { 383: if ((natives == null) || (flavor == null)) 384: throw new NullPointerException(); 385: 386: flavorToNativeMap.remove(flavor); 387: for (int i = 0; i < natives.length; i++) 388: { 389: addUnencodedNativeForFlavor(flavor, natives[i]); 390: } 391: } 392: 393: /** 394: * Discards the current mappings for the specified <code>String</code> 395: * native, and creates new mappings to the specified 396: * <code>DataFlavor</code>s. Unlike <code>getFlavorsForNative</code>, the 397: * mappings will only be established in one direction, and the natives need 398: * not be encoded. To establish two-way mappings, call 399: * <code>setNativesForFlavor</code> as well. The first 400: * <code>DataFlavor</code> in the array will represent the highest priority 401: * mapping. Subsequent <code>DataFlavor</code>s will represent mappings of 402: * decreasing priority. 403: * <p> 404: * If the array contains several elements that reference equal 405: * <code>DataFlavor</code>s, this method will establish new mappings 406: * for the first of those elements and ignore the rest of them. 407: * <p> 408: * It is recommended that client code not reset mappings established by the 409: * data transfer subsystem. This method should only be used for 410: * application-level mappings. 411: * 412: * @param nativeStr the <code>String</code> native key for the mappings 413: * @param flavors the <code>DataFlavor</code> values for the mappings 414: * @throws NullPointerException if nat or flavors is <code>null</code> 415: * or if flavors contains <code>null</code> elements 416: * 417: * @see #setNativesForFlavor 418: * @since 1.4 419: */ 420: public synchronized void setFlavorsForNative(String nativeStr, 421: DataFlavor[] flavors) 422: { 423: if ((nativeStr == null) || (flavors == null)) 424: throw new NullPointerException(); 425: 426: nativeToFlavorMap.remove(nativeStr); 427: for (int i = 0; i < flavors.length; i++) 428: { 429: addFlavorForUnencodedNative(nativeStr, flavors[i]); 430: } 431: } 432: 433: } // class SystemFlavorMap