Source for java.awt.datatransfer.SystemFlavorMap

   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