src/share/classes/java/awt/datatransfer/SystemFlavorMap.java

Print this page




  24  */
  25 
  26 package java.awt.datatransfer;
  27 
  28 import java.awt.Toolkit;
  29 
  30 import java.lang.ref.SoftReference;
  31 
  32 import java.io.BufferedReader;
  33 import java.io.File;
  34 import java.io.InputStreamReader;
  35 import java.io.IOException;
  36 
  37 import java.net.URL;
  38 import java.net.MalformedURLException;
  39 
  40 import java.util.ArrayList;
  41 import java.util.HashMap;
  42 import java.util.HashSet;
  43 import java.util.Iterator;
  44 import java.util.LinkedList;
  45 import java.util.List;
  46 import java.util.Map;
  47 import java.util.Set;
  48 
  49 import sun.awt.AppContext;
  50 import sun.awt.datatransfer.DataTransferer;
  51 
  52 /**
  53  * The SystemFlavorMap is a configurable map between "natives" (Strings), which
  54  * correspond to platform-specific data formats, and "flavors" (DataFlavors),
  55  * which correspond to platform-independent MIME types. This mapping is used
  56  * by the data transfer subsystem to transfer data between Java and native
  57  * applications, and between Java applications in separate VMs.
  58  * <p>
  59  * In the Sun reference implementation, the default SystemFlavorMap is
  60  * initialized by the file <code>jre/lib/flavormap.properties</code> and the
  61  * contents of the URL referenced by the AWT property
  62  * <code>AWT.DnD.flavorMapFileURL</code>. See <code>flavormap.properties</code>
  63  * for details.
  64  *


  86      * from best to worst.
  87      */
  88     private static final String[] UNICODE_TEXT_CLASSES = {
  89         "java.io.Reader", "java.lang.String", "java.nio.CharBuffer", "\"[C\""
  90     };
  91 
  92     /**
  93      * The list of valid, encoded text flavor representation classes, in order
  94      * from best to worst.
  95      */
  96     private static final String[] ENCODED_TEXT_CLASSES = {
  97         "java.io.InputStream", "java.nio.ByteBuffer", "\"[B\""
  98     };
  99 
 100     /**
 101      * A String representing text/plain MIME type.
 102      */
 103     private static final String TEXT_PLAIN_BASE_TYPE = "text/plain";
 104 
 105     /**





 106      * This constant is passed to flavorToNativeLookup() to indicate that a
 107      * a native should be synthesized, stored, and returned by encoding the
 108      * DataFlavor's MIME type in case if the DataFlavor is not found in
 109      * 'flavorToNative' map.
 110      */
 111     private static final boolean SYNTHESIZE_IF_NOT_FOUND = true;
 112 
 113     /**
 114      * Maps native Strings to Lists of DataFlavors (or base type Strings for
 115      * text DataFlavors).
 116      * Do not use the field directly, use getNativeToFlavor() instead.
 117      */
 118     private Map nativeToFlavor = new HashMap();
 119 
 120     /**
 121      * Accessor to nativeToFlavor map.  Since we use lazy initialization we must
 122      * use this accessor instead of direct access to the field which may not be
 123      * initialized yet.  This method will initialize the field if needed.
 124      *
 125      * @return nativeToFlavor
 126      */
 127     private Map getNativeToFlavor() {
 128         if (!isMapInitialized) {
 129             initSystemFlavorMap();
 130         }
 131         return nativeToFlavor;
 132     }
 133 
 134     /**
 135      * Maps DataFlavors (or base type Strings for text DataFlavors) to Lists of
 136      * native Strings.
 137      * Do not use the field directly, use getFlavorToNative() instead.
 138      */
 139     private Map flavorToNative = new HashMap();
 140 
 141     /**
 142      * Accessor to flavorToNative map.  Since we use lazy initialization we must
 143      * use this accessor instead of direct access to the field which may not be
 144      * initialized yet.  This method will initialize the field if needed.
 145      *
 146      * @return flavorToNative
 147      */
 148     private synchronized Map getFlavorToNative() {
 149         if (!isMapInitialized) {
 150             initSystemFlavorMap();
 151         }
 152         return flavorToNative;
 153     }
 154 
 155     /**
 156      * Shows if the object has been initialized.
 157      */
 158     private boolean isMapInitialized = false;
 159 


 394                             mime.removeParameter("terminators");
 395                             value = mime.toString();
 396                         }
 397                     } catch (MimeTypeParseException e) {
 398                         e.printStackTrace();
 399                         continue;
 400                     }
 401 
 402                     DataFlavor flavor;
 403                     try {
 404                         flavor = new DataFlavor(value);
 405                     } catch (Exception e) {
 406                         try {
 407                             flavor = new DataFlavor(value, (String)null);
 408                         } catch (Exception ee) {
 409                             ee.printStackTrace();
 410                             continue;
 411                         }
 412                     }
 413 
 414                     // For text/* flavors, store mappings in separate maps to
 415                     // enable dynamic mapping generation at a run-time.


 416                     if ("text".equals(flavor.getPrimaryType())) {
 417                         store(value, key, getFlavorToNative());
 418                         store(key, value, getNativeToFlavor());
 419                     } else {
 420                         store(flavor, key, getFlavorToNative());
 421                         store(key, flavor, getNativeToFlavor());

 422                     }
 423                 }
 424             }
 425         }
 426     }
 427 
 428     /**
 429      * Copied from java.util.Properties.
 430      */
 431     private boolean continueLine (String line) {
 432         int slashCount = 0;
 433         int index = line.length() - 1;
 434         while((index >= 0) && (line.charAt(index--) == '\\')) {
 435             slashCount++;
 436         }
 437         return (slashCount % 2 == 1);
 438     }
 439 
 440     /**
 441      * Copied from java.util.Properties.


 503      * stored in that location.
 504      */
 505     private void store(Object hashed, Object listed, Map map) {
 506         List list = (List)map.get(hashed);
 507         if (list == null) {
 508             list = new ArrayList(1);
 509             map.put(hashed, list);
 510         }
 511         if (!list.contains(listed)) {
 512             list.add(listed);
 513         }
 514     }
 515 
 516     /**
 517      * Semantically equivalent to 'nativeToFlavor.get(nat)'. This method
 518      * handles the case where 'nat' is not found in 'nativeToFlavor'. In that
 519      * case, a new DataFlavor is synthesized, stored, and returned, if and
 520      * only if the specified native is encoded as a Java MIME type.
 521      */
 522     private List nativeToFlavorLookup(String nat) {
 523         List flavors = (List)getNativeToFlavor().get(nat);
 524 
 525         if (nat != null && !disabledMappingGenerationKeys.contains(nat)) {
 526             DataTransferer transferer = DataTransferer.getInstance();
 527             if (transferer != null) {
 528                 List platformFlavors =
 529                     transferer.getPlatformMappingsForNative(nat);
 530                 if (!platformFlavors.isEmpty()) {
 531                     if (flavors != null) {
 532                         platformFlavors.removeAll(new HashSet(flavors));
 533                         // Prepending the platform-specific mappings ensures
 534                         // that the flavors added with
 535                         // addFlavorForUnencodedNative() are at the end of
 536                         // list.
 537                         platformFlavors.addAll(flavors);
 538                     }
 539                     flavors = platformFlavors;
 540                 }
 541             }
 542         }
 543 


 598                         // Prepend the platform-specific mappings to ensure
 599                         // that the natives added with
 600                         // addUnencodedNativeForFlavor() are at the end of
 601                         // list.
 602                         platformNatives.addAll(natives);
 603                     }
 604                     natives = platformNatives;
 605                 }
 606             }
 607         }
 608 
 609         if (natives == null) {
 610             if (synthesize) {
 611                 String encoded = encodeDataFlavor(flav);
 612                 natives = new ArrayList(1);
 613                 getFlavorToNative().put(flav, natives);
 614                 natives.add(encoded);
 615                 getNativesForFlavorCache.remove(flav);
 616                 getNativesForFlavorCache.remove(null);
 617 
 618                 List flavors = (List)getNativeToFlavor().get(encoded);
 619                 if (flavors == null) {
 620                     flavors = new ArrayList(1);
 621                     getNativeToFlavor().put(encoded, flavors);
 622                 }
 623                 flavors.add(flav);
 624                 getFlavorsForNativeCache.remove(encoded);
 625                 getFlavorsForNativeCache.remove(null);
 626             } else {
 627                 natives = new ArrayList(0);
 628             }
 629         }
 630 
 631         return natives;
 632     }
 633 
 634     /**
 635      * Returns a <code>List</code> of <code>String</code> natives to which the
 636      * specified <code>DataFlavor</code> can be translated by the data transfer
 637      * subsystem. The <code>List</code> will be sorted from best native to
 638      * worst. That is, the first native will best reflect data in the specified


 654      *         specific data formats
 655      *
 656      * @see #encodeDataFlavor
 657      * @since 1.4
 658      */
 659     public synchronized List<String> getNativesForFlavor(DataFlavor flav) {
 660         List retval = null;
 661 
 662         // Check cache, even for null flav
 663         SoftReference ref = (SoftReference)getNativesForFlavorCache.get(flav);
 664         if (ref != null) {
 665             retval = (List)ref.get();
 666             if (retval != null) {
 667                 // Create a copy, because client code can modify the returned
 668                 // list.
 669                 return new ArrayList(retval);
 670             }
 671         }
 672 
 673         if (flav == null) {
 674             retval = new ArrayList(getNativeToFlavor().keySet());
 675         } else if (disabledMappingGenerationKeys.contains(flav)) {
 676             // In this case we shouldn't synthesize a native for this flavor,
 677             // since its mappings were explicitly specified.
 678             retval = flavorToNativeLookup(flav, !SYNTHESIZE_IF_NOT_FOUND);
 679         } else if (DataTransferer.isFlavorCharsetTextType(flav)) {
 680 
 681             // For text/* flavors, flavor-to-native mappings specified in
 682             // flavormap.properties are stored per flavor's base type.
 683             if ("text".equals(flav.getPrimaryType())) {
 684                 retval = (List)getFlavorToNative().get(flav.mimeType.getBaseType());
 685                 if (retval != null) {
 686                     // To prevent the List stored in the map from modification.
 687                     retval = new ArrayList(retval);
 688                 }
 689             }
 690 
 691             // Also include text/plain natives, but don't duplicate Strings
 692             List textPlainList = (List)getFlavorToNative().get(TEXT_PLAIN_BASE_TYPE);
 693 
 694             if (textPlainList != null && !textPlainList.isEmpty()) {


 782      *        <code>DataFlavor</code>s currently known to the data transfer
 783      *        subsystem are returned in a non-deterministic order.
 784      * @return a <code>java.util.List</code> of <code>DataFlavor</code>
 785      *         objects into which platform-specific data in the specified,
 786      *         platform-specific native can be translated
 787      *
 788      * @see #encodeJavaMIMEType
 789      * @since 1.4
 790      */
 791     public synchronized List<DataFlavor> getFlavorsForNative(String nat) {
 792 
 793         // Check cache, even for null nat
 794         SoftReference ref = (SoftReference)getFlavorsForNativeCache.get(nat);
 795         if (ref != null) {
 796             ArrayList retval = (ArrayList)ref.get();
 797             if (retval != null) {
 798                 return (List)retval.clone();
 799             }
 800         }
 801 
 802         LinkedList retval = new LinkedList();

 803 
 804         if (nat == null) {
 805             List natives = getNativesForFlavor(null);
 806             HashSet dups = new HashSet(natives.size());
 807 
 808             for (Iterator natives_iter = natives.iterator();
 809                  natives_iter.hasNext(); )
 810             {
 811                 List flavors =
 812                     getFlavorsForNative((String)natives_iter.next());
 813                 for (Iterator flavors_iter = flavors.iterator();
 814                      flavors_iter.hasNext(); )
 815                 {
 816                     Object flavor = flavors_iter.next();
 817                     if (dups.add(flavor)) {
 818                         retval.add(flavor);
 819                     }
 820                 }
 821             }
 822         } else {
 823             List flavors = nativeToFlavorLookup(nat);

 824 
 825             if (disabledMappingGenerationKeys.contains(nat)) {
 826                 return flavors;
 827             }
 828 
 829             HashSet dups = new HashSet(flavors.size());

















 830 
 831             List flavorsAndbaseTypes = nativeToFlavorLookup(nat);









 832 
 833             for (Iterator flavorsAndbaseTypes_iter =
 834                      flavorsAndbaseTypes.iterator();
 835                  flavorsAndbaseTypes_iter.hasNext(); )
 836             {
 837                 Object value = flavorsAndbaseTypes_iter.next();
 838                 if (value instanceof String) {
 839                     String baseType = (String)value;
 840                     String subType = null;

 841                     try {
 842                         MimeType mimeType = new MimeType(baseType);
 843                         subType = mimeType.getSubType();
 844                     } catch (MimeTypeParseException mtpe) {
 845                         // Cannot happen, since we checked all mappings
 846                         // on load from flavormap.properties.
 847                         assert(false);
 848                     }
 849                     if (DataTransferer.doesSubtypeSupportCharset(subType,
 850                                                                  null)) {
 851                         if (TEXT_PLAIN_BASE_TYPE.equals(baseType) &&
 852                             dups.add(DataFlavor.stringFlavor))
 853                         {
 854                             retval.add(DataFlavor.stringFlavor);
 855                         }
 856 
 857                         for (int i = 0; i < UNICODE_TEXT_CLASSES.length; i++) {






 858                             DataFlavor toAdd = null;
 859                             try {
 860                                 toAdd = new DataFlavor
 861                                     (baseType + ";charset=Unicode;class=" +
 862                                      UNICODE_TEXT_CLASSES[i]);
 863                             } catch (ClassNotFoundException cannotHappen) {
 864                             }
 865                             if (dups.add(toAdd)) {
 866                                 retval.add(toAdd);
 867                             }
 868                         }
 869 
 870                         for (Iterator charset_iter =
 871                                  DataTransferer.standardEncodings();
 872                              charset_iter.hasNext(); )
 873                         {
 874                             String charset = (String)charset_iter.next();
 875 
 876                             for (int i = 0; i < ENCODED_TEXT_CLASSES.length;
 877                                  i++)
 878                             {
 879                                 DataFlavor toAdd = null;
 880                                 try {
 881                                     toAdd = new DataFlavor
 882                                         (baseType + ";charset=" + charset +
 883                                          ";class=" + ENCODED_TEXT_CLASSES[i]);
 884                                 } catch (ClassNotFoundException cannotHappen) {
 885                                 }
 886 




 887                                 // Check for equality to plainTextFlavor so
 888                                 // that we can ensure that the exact charset of
 889                                 // plainTextFlavor, not the canonical charset
 890                                 // or another equivalent charset with a
 891                                 // different name, is used.
 892                                 if (toAdd.equals(DataFlavor.plainTextFlavor)) {
 893                                     toAdd = DataFlavor.plainTextFlavor;


 894                                 }
 895 
 896                                 if (dups.add(toAdd)) {
 897                                     retval.add(toAdd);
 898                                 }
 899                             }
 900                         }
 901 
 902                         if (TEXT_PLAIN_BASE_TYPE.equals(baseType) &&
 903                             dups.add(DataFlavor.plainTextFlavor))
 904                         {
 905                             retval.add(DataFlavor.plainTextFlavor);
 906                         }
 907                     } else {
 908                         // Non-charset text natives should be treated as
 909                         // opaque, 8-bit data in any of its various
 910                         // representations.
 911                         for (int i = 0; i < ENCODED_TEXT_CLASSES.length; i++) {
 912                             DataFlavor toAdd = null;
 913                             try {
 914                                 toAdd = new DataFlavor(baseType +
 915                                      ";class=" + ENCODED_TEXT_CLASSES[i]);
 916                             } catch (ClassNotFoundException cannotHappen) {
 917                             }
 918 
 919                             if (dups.add(toAdd)) {
 920                                 retval.add(toAdd);
 921                             }
 922                         }
 923                     }
 924                 } else {
 925                     DataFlavor flavor = (DataFlavor)value;
 926                     if (dups.add(flavor)) {
 927                         retval.add(flavor);
 928                     }
 929                 }












 930             }


 931         }
 932 
 933         ArrayList arrayList = new ArrayList(retval);
 934         getFlavorsForNativeCache.put(nat, new SoftReference(arrayList));
 935         return (List)arrayList.clone();
 936     }
 937 
 938     /**
 939      * Returns a <code>Map</code> of the specified <code>DataFlavor</code>s to
 940      * their most preferred <code>String</code> native. Each native value will
 941      * be the same as the first native in the List returned by
 942      * <code>getNativesForFlavor</code> for the specified flavor.
 943      * <p>
 944      * If a specified <code>DataFlavor</code> is previously unknown to the
 945      * data transfer subsystem, then invoking this method will establish a
 946      * mapping in both directions between the specified <code>DataFlavor</code>
 947      * and an encoded version of its MIME type as its native.
 948      *
 949      * @param flavors an array of <code>DataFlavor</code>s which will be the
 950      *        key set of the returned <code>Map</code>. If <code>null</code> is
 951      *        specified, a mapping of all <code>DataFlavor</code>s known to the
 952      *        data transfer subsystem to their most preferred
 953      *        <code>String</code> natives will be returned.
 954      * @return a <code>java.util.Map</code> of <code>DataFlavor</code>s to
 955      *         <code>String</code> natives




  24  */
  25 
  26 package java.awt.datatransfer;
  27 
  28 import java.awt.Toolkit;
  29 
  30 import java.lang.ref.SoftReference;
  31 
  32 import java.io.BufferedReader;
  33 import java.io.File;
  34 import java.io.InputStreamReader;
  35 import java.io.IOException;
  36 
  37 import java.net.URL;
  38 import java.net.MalformedURLException;
  39 
  40 import java.util.ArrayList;
  41 import java.util.HashMap;
  42 import java.util.HashSet;
  43 import java.util.Iterator;
  44 import java.util.LinkedHashSet;
  45 import java.util.List;
  46 import java.util.Map;
  47 import java.util.Set;
  48 
  49 import sun.awt.AppContext;
  50 import sun.awt.datatransfer.DataTransferer;
  51 
  52 /**
  53  * The SystemFlavorMap is a configurable map between "natives" (Strings), which
  54  * correspond to platform-specific data formats, and "flavors" (DataFlavors),
  55  * which correspond to platform-independent MIME types. This mapping is used
  56  * by the data transfer subsystem to transfer data between Java and native
  57  * applications, and between Java applications in separate VMs.
  58  * <p>
  59  * In the Sun reference implementation, the default SystemFlavorMap is
  60  * initialized by the file <code>jre/lib/flavormap.properties</code> and the
  61  * contents of the URL referenced by the AWT property
  62  * <code>AWT.DnD.flavorMapFileURL</code>. See <code>flavormap.properties</code>
  63  * for details.
  64  *


  86      * from best to worst.
  87      */
  88     private static final String[] UNICODE_TEXT_CLASSES = {
  89         "java.io.Reader", "java.lang.String", "java.nio.CharBuffer", "\"[C\""
  90     };
  91 
  92     /**
  93      * The list of valid, encoded text flavor representation classes, in order
  94      * from best to worst.
  95      */
  96     private static final String[] ENCODED_TEXT_CLASSES = {
  97         "java.io.InputStream", "java.nio.ByteBuffer", "\"[B\""
  98     };
  99 
 100     /**
 101      * A String representing text/plain MIME type.
 102      */
 103     private static final String TEXT_PLAIN_BASE_TYPE = "text/plain";
 104 
 105     /**
 106      * A String representing text/html MIME type.
 107      */
 108     private static final String HTML_TEXT_BASE_TYPE = "text/html";
 109 
 110     /**
 111      * This constant is passed to flavorToNativeLookup() to indicate that a
 112      * a native should be synthesized, stored, and returned by encoding the
 113      * DataFlavor's MIME type in case if the DataFlavor is not found in
 114      * 'flavorToNative' map.
 115      */
 116     private static final boolean SYNTHESIZE_IF_NOT_FOUND = true;
 117 
 118     /**
 119      * Maps native Strings to Lists of DataFlavors (or base type Strings for
 120      * text DataFlavors).
 121      * Do not use the field directly, use getNativeToFlavor() instead.
 122      */
 123     private final Map<String, List<DataFlavor>> nativeToFlavor = new HashMap<>();
 124 
 125     /**
 126      * Accessor to nativeToFlavor map.  Since we use lazy initialization we must
 127      * use this accessor instead of direct access to the field which may not be
 128      * initialized yet.  This method will initialize the field if needed.
 129      *
 130      * @return nativeToFlavor
 131      */
 132     private Map<String, List<DataFlavor>> getNativeToFlavor() {
 133         if (!isMapInitialized) {
 134             initSystemFlavorMap();
 135         }
 136         return nativeToFlavor;
 137     }
 138 
 139     /**
 140      * Maps DataFlavors (or base type Strings for text DataFlavors) to Lists of
 141      * native Strings.
 142      * Do not use the field directly, use getFlavorToNative() instead.
 143      */
 144     private final Map flavorToNative = new HashMap();
 145 
 146     /**
 147      * Accessor to flavorToNative map.  Since we use lazy initialization we must
 148      * use this accessor instead of direct access to the field which may not be
 149      * initialized yet.  This method will initialize the field if needed.
 150      *
 151      * @return flavorToNative
 152      */
 153     private synchronized Map getFlavorToNative() {
 154         if (!isMapInitialized) {
 155             initSystemFlavorMap();
 156         }
 157         return flavorToNative;
 158     }
 159 
 160     /**
 161      * Shows if the object has been initialized.
 162      */
 163     private boolean isMapInitialized = false;
 164 


 399                             mime.removeParameter("terminators");
 400                             value = mime.toString();
 401                         }
 402                     } catch (MimeTypeParseException e) {
 403                         e.printStackTrace();
 404                         continue;
 405                     }
 406 
 407                     DataFlavor flavor;
 408                     try {
 409                         flavor = new DataFlavor(value);
 410                     } catch (Exception e) {
 411                         try {
 412                             flavor = new DataFlavor(value, (String)null);
 413                         } catch (Exception ee) {
 414                             ee.printStackTrace();
 415                             continue;
 416                         }
 417                     }
 418 
 419                     final LinkedHashSet<DataFlavor> dfs = new LinkedHashSet<>();
 420 
 421                     dfs.add(flavor);
 422 
 423                     if ("text".equals(flavor.getPrimaryType())) {
 424                         dfs.addAll(convertMimeTypeToDataFlavors(value));
 425                     }
 426 
 427                     for (DataFlavor df : dfs) {
 428                         store(df, key, getFlavorToNative());
 429                         store(key, df, getNativeToFlavor());
 430                     }
 431                 }
 432             }
 433         }
 434     }
 435 
 436     /**
 437      * Copied from java.util.Properties.
 438      */
 439     private boolean continueLine (String line) {
 440         int slashCount = 0;
 441         int index = line.length() - 1;
 442         while((index >= 0) && (line.charAt(index--) == '\\')) {
 443             slashCount++;
 444         }
 445         return (slashCount % 2 == 1);
 446     }
 447 
 448     /**
 449      * Copied from java.util.Properties.


 511      * stored in that location.
 512      */
 513     private void store(Object hashed, Object listed, Map map) {
 514         List list = (List)map.get(hashed);
 515         if (list == null) {
 516             list = new ArrayList(1);
 517             map.put(hashed, list);
 518         }
 519         if (!list.contains(listed)) {
 520             list.add(listed);
 521         }
 522     }
 523 
 524     /**
 525      * Semantically equivalent to 'nativeToFlavor.get(nat)'. This method
 526      * handles the case where 'nat' is not found in 'nativeToFlavor'. In that
 527      * case, a new DataFlavor is synthesized, stored, and returned, if and
 528      * only if the specified native is encoded as a Java MIME type.
 529      */
 530     private List nativeToFlavorLookup(String nat) {
 531         List<DataFlavor> flavors = getNativeToFlavor().get(nat);
 532 
 533         if (nat != null && !disabledMappingGenerationKeys.contains(nat)) {
 534             DataTransferer transferer = DataTransferer.getInstance();
 535             if (transferer != null) {
 536                 List platformFlavors =
 537                     transferer.getPlatformMappingsForNative(nat);
 538                 if (!platformFlavors.isEmpty()) {
 539                     if (flavors != null) {
 540                         platformFlavors.removeAll(new HashSet(flavors));
 541                         // Prepending the platform-specific mappings ensures
 542                         // that the flavors added with
 543                         // addFlavorForUnencodedNative() are at the end of
 544                         // list.
 545                         platformFlavors.addAll(flavors);
 546                     }
 547                     flavors = platformFlavors;
 548                 }
 549             }
 550         }
 551 


 606                         // Prepend the platform-specific mappings to ensure
 607                         // that the natives added with
 608                         // addUnencodedNativeForFlavor() are at the end of
 609                         // list.
 610                         platformNatives.addAll(natives);
 611                     }
 612                     natives = platformNatives;
 613                 }
 614             }
 615         }
 616 
 617         if (natives == null) {
 618             if (synthesize) {
 619                 String encoded = encodeDataFlavor(flav);
 620                 natives = new ArrayList(1);
 621                 getFlavorToNative().put(flav, natives);
 622                 natives.add(encoded);
 623                 getNativesForFlavorCache.remove(flav);
 624                 getNativesForFlavorCache.remove(null);
 625 
 626                 List<DataFlavor> flavors = getNativeToFlavor().get(encoded);
 627                 if (flavors == null) {
 628                     flavors = new ArrayList(1);
 629                     getNativeToFlavor().put(encoded, flavors);
 630                 }
 631                 flavors.add(flav);
 632                 getFlavorsForNativeCache.remove(encoded);
 633                 getFlavorsForNativeCache.remove(null);
 634             } else {
 635                 natives = new ArrayList(0);
 636             }
 637         }
 638 
 639         return natives;
 640     }
 641 
 642     /**
 643      * Returns a <code>List</code> of <code>String</code> natives to which the
 644      * specified <code>DataFlavor</code> can be translated by the data transfer
 645      * subsystem. The <code>List</code> will be sorted from best native to
 646      * worst. That is, the first native will best reflect data in the specified


 662      *         specific data formats
 663      *
 664      * @see #encodeDataFlavor
 665      * @since 1.4
 666      */
 667     public synchronized List<String> getNativesForFlavor(DataFlavor flav) {
 668         List retval = null;
 669 
 670         // Check cache, even for null flav
 671         SoftReference ref = (SoftReference)getNativesForFlavorCache.get(flav);
 672         if (ref != null) {
 673             retval = (List)ref.get();
 674             if (retval != null) {
 675                 // Create a copy, because client code can modify the returned
 676                 // list.
 677                 return new ArrayList(retval);
 678             }
 679         }
 680 
 681         if (flav == null) {
 682             retval = new ArrayList<String>(getNativeToFlavor().keySet());
 683         } else if (disabledMappingGenerationKeys.contains(flav)) {
 684             // In this case we shouldn't synthesize a native for this flavor,
 685             // since its mappings were explicitly specified.
 686             retval = flavorToNativeLookup(flav, !SYNTHESIZE_IF_NOT_FOUND);
 687         } else if (DataTransferer.isFlavorCharsetTextType(flav)) {
 688 
 689             // For text/* flavors, flavor-to-native mappings specified in
 690             // flavormap.properties are stored per flavor's base type.
 691             if ("text".equals(flav.getPrimaryType())) {
 692                 retval = (List)getFlavorToNative().get(flav.mimeType.getBaseType());
 693                 if (retval != null) {
 694                     // To prevent the List stored in the map from modification.
 695                     retval = new ArrayList(retval);
 696                 }
 697             }
 698 
 699             // Also include text/plain natives, but don't duplicate Strings
 700             List textPlainList = (List)getFlavorToNative().get(TEXT_PLAIN_BASE_TYPE);
 701 
 702             if (textPlainList != null && !textPlainList.isEmpty()) {


 790      *        <code>DataFlavor</code>s currently known to the data transfer
 791      *        subsystem are returned in a non-deterministic order.
 792      * @return a <code>java.util.List</code> of <code>DataFlavor</code>
 793      *         objects into which platform-specific data in the specified,
 794      *         platform-specific native can be translated
 795      *
 796      * @see #encodeJavaMIMEType
 797      * @since 1.4
 798      */
 799     public synchronized List<DataFlavor> getFlavorsForNative(String nat) {
 800 
 801         // Check cache, even for null nat
 802         SoftReference ref = (SoftReference)getFlavorsForNativeCache.get(nat);
 803         if (ref != null) {
 804             ArrayList retval = (ArrayList)ref.get();
 805             if (retval != null) {
 806                 return (List)retval.clone();
 807             }
 808         }
 809 
 810         final LinkedHashSet <DataFlavor> returnValue =
 811             new LinkedHashSet<>();
 812 
 813         if (nat == null) {
 814             final List<String> natives = getNativesForFlavor(null);

 815 
 816             for (String n : natives)

 817             {
 818                 final List<DataFlavor> flavors = getFlavorsForNative(n);
 819 
 820                 for (DataFlavor df : flavors)

 821                 {
 822                     returnValue.add(df);



 823                 }
 824             }
 825         } else {
 826 
 827             final List<DataFlavor> flavors = nativeToFlavorLookup(nat);
 828 
 829             if (disabledMappingGenerationKeys.contains(nat)) {
 830                 return flavors;
 831             }
 832 
 833             final List<DataFlavor> flavorsAndBaseTypes =
 834                 nativeToFlavorLookup(nat);
 835 
 836             for (DataFlavor df : flavorsAndBaseTypes) {
 837                 returnValue.add(df);
 838                 if ("text".equals(df.getPrimaryType())) {
 839                     try {
 840                         returnValue.addAll(
 841                                 convertMimeTypeToDataFlavors(
 842                                         new MimeType(df.getMimeType()
 843                                         ).getBaseType()));
 844                     } catch (MimeTypeParseException e) {
 845                         e.printStackTrace();
 846                     }
 847                 }
 848             }
 849 
 850         }
 851 
 852         final ArrayList arrayList = new ArrayList(returnValue);
 853         getFlavorsForNativeCache.put(nat, new SoftReference(arrayList));
 854         return (List)arrayList.clone();
 855     }
 856 
 857     private static LinkedHashSet<DataFlavor> convertMimeTypeToDataFlavors(
 858         final String baseType) {
 859 
 860         final LinkedHashSet<DataFlavor> returnValue =
 861             new LinkedHashSet<DataFlavor>();
 862 







 863         String subType = null;
 864 
 865         try {
 866             final MimeType mimeType = new MimeType(baseType);
 867             subType = mimeType.getSubType();
 868         } catch (MimeTypeParseException mtpe) {
 869             // Cannot happen, since we checked all mappings
 870             // on load from flavormap.properties.
 871             assert(false);
 872         }
 873 
 874         if (DataTransferer.doesSubtypeSupportCharset(subType, null)) {
 875             if (TEXT_PLAIN_BASE_TYPE.equals(baseType))

 876             {
 877                 returnValue.add(DataFlavor.stringFlavor);
 878             }
 879 
 880             for (String unicodeClassName : UNICODE_TEXT_CLASSES) {
 881                 final String mimeType = baseType + ";charset=Unicode;class=" +
 882                                             unicodeClassName;
 883 
 884                 final LinkedHashSet<String> mimeTypes =
 885                     handleHtmlMimeTypes(baseType, mimeType);
 886                 for (String mt : mimeTypes) {
 887                     DataFlavor toAdd = null;
 888                     try {
 889                         toAdd = new DataFlavor(mt);


 890                     } catch (ClassNotFoundException cannotHappen) {
 891                     }
 892                     returnValue.add(toAdd);

 893                 }
 894             }
 895 
 896             for (String charset : DataTransferer.standardEncodings()) {




 897 
 898                 for (String encodedTextClass : ENCODED_TEXT_CLASSES) {
 899                     final String mimeType =
 900                             baseType + ";charset=" + charset +
 901                             ";class=" + encodedTextClass;
 902 
 903                     final LinkedHashSet<String> mimeTypes =
 904                         handleHtmlMimeTypes(baseType, mimeType);
 905 
 906                     for (String mt : mimeTypes) {

 907 
 908                         DataFlavor df = null;
 909 
 910                         try {
 911                             df = new DataFlavor(mt);
 912                             // Check for equality to plainTextFlavor so
 913                             // that we can ensure that the exact charset of
 914                             // plainTextFlavor, not the canonical charset
 915                             // or another equivalent charset with a
 916                             // different name, is used.
 917                             if (df.equals(DataFlavor.plainTextFlavor)) {
 918                                 df = DataFlavor.plainTextFlavor;
 919                             }
 920                         } catch (ClassNotFoundException cannotHappen) {
 921                         }
 922 
 923                         returnValue.add(df);

 924                     }
 925                 }
 926             }
 927 
 928             if (TEXT_PLAIN_BASE_TYPE.equals(baseType))

 929             {
 930                 returnValue.add(DataFlavor.plainTextFlavor);
 931             }
 932         } else {
 933             // Non-charset text natives should be treated as
 934             // opaque, 8-bit data in any of its various
 935             // representations.
 936             for (String encodedTextClassName : ENCODED_TEXT_CLASSES) {
 937                 DataFlavor toAdd = null;
 938                 try {
 939                     toAdd = new DataFlavor(baseType +
 940                          ";class=" + encodedTextClassName);
 941                 } catch (ClassNotFoundException cannotHappen) {
 942                 }
 943                 returnValue.add(toAdd);



 944             }
 945         }
 946         return returnValue;




 947     }
 948 
 949     private static final String [] htmlDocumntTypes =
 950         new String [] {"all", "selection", "fragment"};
 951 
 952     private static LinkedHashSet<String> handleHtmlMimeTypes(
 953         String baseType, String mimeType) {
 954 
 955         LinkedHashSet<String> returnValues = new LinkedHashSet<>();
 956 
 957         if (HTML_TEXT_BASE_TYPE.equals(baseType)) {
 958             for (String documentType : htmlDocumntTypes) {
 959                 returnValues.add(mimeType + ";document=" + documentType);
 960             }
 961         } else {
 962             returnValues.add(mimeType);
 963         }
 964 
 965         return returnValues;


 966     }
 967 
 968     /**
 969      * Returns a <code>Map</code> of the specified <code>DataFlavor</code>s to
 970      * their most preferred <code>String</code> native. Each native value will
 971      * be the same as the first native in the List returned by
 972      * <code>getNativesForFlavor</code> for the specified flavor.
 973      * <p>
 974      * If a specified <code>DataFlavor</code> is previously unknown to the
 975      * data transfer subsystem, then invoking this method will establish a
 976      * mapping in both directions between the specified <code>DataFlavor</code>
 977      * and an encoded version of its MIME type as its native.
 978      *
 979      * @param flavors an array of <code>DataFlavor</code>s which will be the
 980      *        key set of the returned <code>Map</code>. If <code>null</code> is
 981      *        specified, a mapping of all <code>DataFlavor</code>s known to the
 982      *        data transfer subsystem to their most preferred
 983      *        <code>String</code> natives will be returned.
 984      * @return a <code>java.util.Map</code> of <code>DataFlavor</code>s to
 985      *         <code>String</code> natives