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

Print this page

        

*** 41,52 **** import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; - import java.util.WeakHashMap; import sun.awt.AppContext; import sun.awt.datatransfer.DataTransferer; /** --- 41,52 ---- import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; + import java.util.Objects; import java.util.Set; import sun.awt.AppContext; import sun.awt.datatransfer.DataTransferer; /**
*** 100,131 **** * A String representing text/html MIME type. */ private static final String HTML_TEXT_BASE_TYPE = "text/html"; /** - * This constant is passed to flavorToNativeLookup() to indicate that a - * a native should be synthesized, stored, and returned by encoding the - * DataFlavor's MIME type in case if the DataFlavor is not found in - * 'flavorToNative' map. - */ - private static final boolean SYNTHESIZE_IF_NOT_FOUND = true; - - /** * Maps native Strings to Lists of DataFlavors (or base type Strings for * text DataFlavors). * Do not use the field directly, use getNativeToFlavor() instead. */ ! private final Map<String, List<DataFlavor>> nativeToFlavor = new HashMap<>(); /** * Accessor to nativeToFlavor map. Since we use lazy initialization we must * use this accessor instead of direct access to the field which may not be * initialized yet. This method will initialize the field if needed. * * @return nativeToFlavor */ ! private Map<String, List<DataFlavor>> getNativeToFlavor() { if (!isMapInitialized) { initSystemFlavorMap(); } return nativeToFlavor; } --- 100,123 ---- * A String representing text/html MIME type. */ private static final String HTML_TEXT_BASE_TYPE = "text/html"; /** * Maps native Strings to Lists of DataFlavors (or base type Strings for * text DataFlavors). * Do not use the field directly, use getNativeToFlavor() instead. */ ! private final Map<String, LinkedHashSet<DataFlavor>> nativeToFlavor = new HashMap<>(); /** * Accessor to nativeToFlavor map. Since we use lazy initialization we must * use this accessor instead of direct access to the field which may not be * initialized yet. This method will initialize the field if needed. * * @return nativeToFlavor */ ! private Map<String, LinkedHashSet<DataFlavor>> getNativeToFlavor() { if (!isMapInitialized) { initSystemFlavorMap(); } return nativeToFlavor; }
*** 133,182 **** /** * Maps DataFlavors (or base type Strings for text DataFlavors) to Lists of * native Strings. * Do not use the field directly, use getFlavorToNative() instead. */ ! private final Map<DataFlavor, List<String>> flavorToNative = new HashMap<>(); /** * Accessor to flavorToNative map. Since we use lazy initialization we must * use this accessor instead of direct access to the field which may not be * initialized yet. This method will initialize the field if needed. * * @return flavorToNative */ ! private synchronized Map<DataFlavor, List<String>> getFlavorToNative() { if (!isMapInitialized) { initSystemFlavorMap(); } return flavorToNative; } /** * Shows if the object has been initialized. */ private boolean isMapInitialized = false; /** * Caches the result of getNativesForFlavor(). Maps DataFlavors to ! * SoftReferences which reference Lists of String natives. */ ! private Map<DataFlavor, SoftReference<List<String>>> getNativesForFlavorCache = new HashMap<>(); /** * Caches the result getFlavorsForNative(). Maps String natives to ! * SoftReferences which reference Lists of DataFlavors. */ ! private Map<String, SoftReference<List<DataFlavor>>> getFlavorsForNativeCache = new HashMap<>(); /** * Dynamic mapping generation used for text mappings should not be applied * to the DataFlavors and String natives for which the mappings have been * explicitly specified with setFlavorsForNative() or * setNativesForFlavor(). This keeps all such keys. */ ! private Set disabledMappingGenerationKeys = new HashSet(); /** * Returns the default FlavorMap for this thread's ClassLoader. * @return the default FlavorMap for this thread's ClassLoader */ --- 125,195 ---- /** * Maps DataFlavors (or base type Strings for text DataFlavors) to Lists of * native Strings. * Do not use the field directly, use getFlavorToNative() instead. */ ! private final Map<DataFlavor, LinkedHashSet<String>> flavorToNative = new HashMap<>(); /** * Accessor to flavorToNative map. Since we use lazy initialization we must * use this accessor instead of direct access to the field which may not be * initialized yet. This method will initialize the field if needed. * * @return flavorToNative */ ! private synchronized Map<DataFlavor, LinkedHashSet<String>> getFlavorToNative() { if (!isMapInitialized) { initSystemFlavorMap(); } return flavorToNative; } /** + * Maps a text DataFlavor primary mime-type to the native. Used only to store + * standard mappings registered in the flavormap.properties + * Do not use this field directly, use getTextTypeToNative() instead. + */ + private final Map<String, LinkedHashSet<String>> textTypeToNative = new HashMap<>(); + + /** + * An accessor to textTypeToNative map. Since we use lazy initialization we + * must use this accessor instead of direct access to the field which may not + * be initialized yet. This method will initialize the field if needed. + * + * @return textTypeToNative + */ + private synchronized Map<String, LinkedHashSet<String>> getTextTypeToNative() { + if (!isMapInitialized) { + initSystemFlavorMap(); + } + return textTypeToNative; + } + + /** * Shows if the object has been initialized. */ private boolean isMapInitialized = false; /** * Caches the result of getNativesForFlavor(). Maps DataFlavors to ! * SoftReferences which reference LinkedHashSet of String natives. */ ! private final SoftCache<DataFlavor, String> nativesForFlavorCache = new SoftCache<>(); /** * Caches the result getFlavorsForNative(). Maps String natives to ! * SoftReferences which reference LinkedHashSet of DataFlavors. */ ! private final SoftCache<String, DataFlavor> flavorsForNativeCache = new SoftCache<>(); /** * Dynamic mapping generation used for text mappings should not be applied * to the DataFlavors and String natives for which the mappings have been * explicitly specified with setFlavorsForNative() or * setNativesForFlavor(). This keeps all such keys. */ ! private Set<Object> disabledMappingGenerationKeys = new HashSet<>(); /** * Returns the default FlavorMap for this thread's ClassLoader. * @return the default FlavorMap for this thread's ClassLoader */
*** 402,424 **** DataFlavor flavor; try { flavor = new DataFlavor(value); } catch (Exception e) { try { ! flavor = new DataFlavor(value, (String)null); } catch (Exception ee) { ee.printStackTrace(); continue; } } final LinkedHashSet<DataFlavor> dfs = new LinkedHashSet<>(); - dfs.add(flavor); if ("text".equals(flavor.getPrimaryType())) { dfs.addAll(convertMimeTypeToDataFlavors(value)); } for (DataFlavor df : dfs) { store(df, key, getFlavorToNative()); store(key, df, getNativeToFlavor()); --- 415,437 ---- DataFlavor flavor; try { flavor = new DataFlavor(value); } catch (Exception e) { try { ! flavor = new DataFlavor(value, null); } catch (Exception ee) { ee.printStackTrace(); continue; } } final LinkedHashSet<DataFlavor> dfs = new LinkedHashSet<>(); dfs.add(flavor); if ("text".equals(flavor.getPrimaryType())) { dfs.addAll(convertMimeTypeToDataFlavors(value)); + store(flavor.mimeType.getBaseType(), key, getTextTypeToNative()); } for (DataFlavor df : dfs) { store(df, key, getFlavorToNative()); store(key, df, getNativeToFlavor());
*** 503,516 **** * Stores the listed object under the specified hash key in map. Unlike a * standard map, the listed object will not replace any object already at * the appropriate Map location, but rather will be appended to a List * stored in that location. */ ! private <H, L> void store(H hashed, L listed, Map<H, List<L>> map) { ! List<L> list = map.get(hashed); if (list == null) { ! list = new ArrayList<>(1); map.put(hashed, list); } if (!list.contains(listed)) { list.add(listed); } --- 516,529 ---- * Stores the listed object under the specified hash key in map. Unlike a * standard map, the listed object will not replace any object already at * the appropriate Map location, but rather will be appended to a List * stored in that location. */ ! private <H, L> void store(H hashed, L listed, Map<H, LinkedHashSet<L>> map) { ! LinkedHashSet<L> list = map.get(hashed); if (list == null) { ! list = new LinkedHashSet<>(1); map.put(hashed, list); } if (!list.contains(listed)) { list.add(listed); }
*** 520,540 **** * Semantically equivalent to 'nativeToFlavor.get(nat)'. This method * handles the case where 'nat' is not found in 'nativeToFlavor'. In that * case, a new DataFlavor is synthesized, stored, and returned, if and * only if the specified native is encoded as a Java MIME type. */ ! private List<DataFlavor> nativeToFlavorLookup(String nat) { ! List<DataFlavor> flavors = getNativeToFlavor().get(nat); if (nat != null && !disabledMappingGenerationKeys.contains(nat)) { DataTransferer transferer = DataTransferer.getInstance(); if (transferer != null) { ! List<DataFlavor> platformFlavors = transferer.getPlatformMappingsForNative(nat); if (!platformFlavors.isEmpty()) { if (flavors != null) { - platformFlavors.removeAll(new HashSet<>(flavors)); // Prepending the platform-specific mappings ensures // that the flavors added with // addFlavorForUnencodedNative() are at the end of // list. platformFlavors.addAll(flavors); --- 533,552 ---- * Semantically equivalent to 'nativeToFlavor.get(nat)'. This method * handles the case where 'nat' is not found in 'nativeToFlavor'. In that * case, a new DataFlavor is synthesized, stored, and returned, if and * only if the specified native is encoded as a Java MIME type. */ ! private LinkedHashSet<DataFlavor> nativeToFlavorLookup(String nat) { ! LinkedHashSet<DataFlavor> flavors = getNativeToFlavor().get(nat); if (nat != null && !disabledMappingGenerationKeys.contains(nat)) { DataTransferer transferer = DataTransferer.getInstance(); if (transferer != null) { ! LinkedHashSet<DataFlavor> platformFlavors = transferer.getPlatformMappingsForNative(nat); if (!platformFlavors.isEmpty()) { if (flavors != null) { // Prepending the platform-specific mappings ensures // that the flavors added with // addFlavorForUnencodedNative() are at the end of // list. platformFlavors.addAll(flavors);
*** 556,605 **** "\"while constructing DataFlavor for: " + decoded); } if (flavor != null) { ! flavors = new ArrayList<>(1); getNativeToFlavor().put(nat, flavors); flavors.add(flavor); ! getFlavorsForNativeCache.remove(nat); ! getFlavorsForNativeCache.remove(null); ! List<String> natives = getFlavorToNative().get(flavor); if (natives == null) { ! natives = new ArrayList<>(1); getFlavorToNative().put(flavor, natives); } natives.add(nat); ! getNativesForFlavorCache.remove(flavor); ! getNativesForFlavorCache.remove(null); } } ! return (flavors != null) ? flavors : new ArrayList<>(0); } /** * Semantically equivalent to 'flavorToNative.get(flav)'. This method * handles the case where 'flav' is not found in 'flavorToNative' depending * on the value of passes 'synthesize' parameter. If 'synthesize' is * SYNTHESIZE_IF_NOT_FOUND a native is synthesized, stored, and returned by * encoding the DataFlavor's MIME type. Otherwise an empty List is returned * and 'flavorToNative' remains unaffected. */ ! private List<String> flavorToNativeLookup(final DataFlavor flav, final boolean synthesize) { ! List<String> natives = getFlavorToNative().get(flav); if (flav != null && !disabledMappingGenerationKeys.contains(flav)) { DataTransferer transferer = DataTransferer.getInstance(); if (transferer != null) { ! List<String> platformNatives = transferer.getPlatformMappingsForFlavor(flav); if (!platformNatives.isEmpty()) { if (natives != null) { - platformNatives.removeAll(new HashSet<>(natives)); // Prepend the platform-specific mappings to ensure // that the natives added with // addUnencodedNativeForFlavor() are at the end of // list. platformNatives.addAll(natives); --- 568,615 ---- "\"while constructing DataFlavor for: " + decoded); } if (flavor != null) { ! flavors = new LinkedHashSet<>(1); getNativeToFlavor().put(nat, flavors); flavors.add(flavor); ! flavorsForNativeCache.remove(nat); ! LinkedHashSet<String> natives = getFlavorToNative().get(flavor); if (natives == null) { ! natives = new LinkedHashSet<>(1); getFlavorToNative().put(flavor, natives); } natives.add(nat); ! nativesForFlavorCache.remove(flavor); } } ! return (flavors != null) ? flavors : new LinkedHashSet<>(0); } /** * Semantically equivalent to 'flavorToNative.get(flav)'. This method * handles the case where 'flav' is not found in 'flavorToNative' depending * on the value of passes 'synthesize' parameter. If 'synthesize' is * SYNTHESIZE_IF_NOT_FOUND a native is synthesized, stored, and returned by * encoding the DataFlavor's MIME type. Otherwise an empty List is returned * and 'flavorToNative' remains unaffected. */ ! private LinkedHashSet<String> flavorToNativeLookup(final DataFlavor flav, final boolean synthesize) { ! ! LinkedHashSet<String> natives = getFlavorToNative().get(flav); if (flav != null && !disabledMappingGenerationKeys.contains(flav)) { DataTransferer transferer = DataTransferer.getInstance(); if (transferer != null) { ! LinkedHashSet<String> platformNatives = transferer.getPlatformMappingsForFlavor(flav); if (!platformNatives.isEmpty()) { if (natives != null) { // Prepend the platform-specific mappings to ensure // that the natives added with // addUnencodedNativeForFlavor() are at the end of // list. platformNatives.addAll(natives);
*** 610,639 **** } if (natives == null) { if (synthesize) { String encoded = encodeDataFlavor(flav); ! natives = new ArrayList<>(1); getFlavorToNative().put(flav, natives); natives.add(encoded); - getNativesForFlavorCache.remove(flav); - getNativesForFlavorCache.remove(null); ! List<DataFlavor> flavors = getNativeToFlavor().get(encoded); if (flavors == null) { ! flavors = new ArrayList<>(1); getNativeToFlavor().put(encoded, flavors); } flavors.add(flav); ! getFlavorsForNativeCache.remove(encoded); ! getFlavorsForNativeCache.remove(null); } else { ! natives = new ArrayList<>(0); } } ! return natives; } /** * Returns a <code>List</code> of <code>String</code> natives to which the * specified <code>DataFlavor</code> can be translated by the data transfer --- 620,648 ---- } if (natives == null) { if (synthesize) { String encoded = encodeDataFlavor(flav); ! natives = new LinkedHashSet<>(1); getFlavorToNative().put(flav, natives); natives.add(encoded); ! LinkedHashSet<DataFlavor> flavors = getNativeToFlavor().get(encoded); if (flavors == null) { ! flavors = new LinkedHashSet<>(1); getNativeToFlavor().put(encoded, flavors); } flavors.add(flav); ! ! nativesForFlavorCache.remove(flav); ! flavorsForNativeCache.remove(encoded); } else { ! natives = new LinkedHashSet<>(0); } } ! return new LinkedHashSet<>(natives); } /** * Returns a <code>List</code> of <code>String</code> natives to which the * specified <code>DataFlavor</code> can be translated by the data transfer
*** 657,763 **** * specific data formats * * @see #encodeDataFlavor * @since 1.4 */ public synchronized List<String> getNativesForFlavor(DataFlavor flav) { ! List<String> retval = null; ! ! // Check cache, even for null flav ! SoftReference<List<String>> ref = getNativesForFlavorCache.get(flav); ! if (ref != null) { ! retval = ref.get(); if (retval != null) { - // Create a copy, because client code can modify the returned - // list. return new ArrayList<>(retval); } - } if (flav == null) { ! retval = new ArrayList<>(getNativeToFlavor().keySet()); } else if (disabledMappingGenerationKeys.contains(flav)) { // In this case we shouldn't synthesize a native for this flavor, // since its mappings were explicitly specified. ! retval = flavorToNativeLookup(flav, !SYNTHESIZE_IF_NOT_FOUND); } else if (DataTransferer.isFlavorCharsetTextType(flav)) { // For text/* flavors, flavor-to-native mappings specified in // flavormap.properties are stored per flavor's base type. if ("text".equals(flav.getPrimaryType())) { ! retval = getAllNativesForType(flav.mimeType.getBaseType()); ! if (retval != null) { ! // To prevent the List stored in the map from modification. ! retval = new ArrayList(retval); } } // Also include text/plain natives, but don't duplicate Strings ! List<String> textPlainList = getAllNativesForType(TEXT_PLAIN_BASE_TYPE); ! ! if (textPlainList != null && !textPlainList.isEmpty()) { ! // To prevent the List stored in the map from modification. ! // This also guarantees that removeAll() is supported. ! textPlainList = new ArrayList<>(textPlainList); ! if (retval != null && !retval.isEmpty()) { ! // Use HashSet to get constant-time performance for search. ! textPlainList.removeAll(new HashSet<>(retval)); ! retval.addAll(textPlainList); ! } else { ! retval = textPlainList; ! } } ! if (retval == null || retval.isEmpty()) { ! retval = flavorToNativeLookup(flav, SYNTHESIZE_IF_NOT_FOUND); } else { // In this branch it is guaranteed that natives explicitly // listed for flav's MIME type were added with // addUnencodedNativeForFlavor(), so they have lower priority. ! List<String> explicitList = ! flavorToNativeLookup(flav, !SYNTHESIZE_IF_NOT_FOUND); ! ! // flavorToNativeLookup() never returns null. ! // It can return an empty List, however. ! if (!explicitList.isEmpty()) { ! // To prevent the List stored in the map from modification. ! // This also guarantees that removeAll() is supported. ! explicitList = new ArrayList<>(explicitList); ! // Use HashSet to get constant-time performance for search. ! explicitList.removeAll(new HashSet<>(retval)); ! retval.addAll(explicitList); ! } } } else if (DataTransferer.isFlavorNoncharsetTextType(flav)) { ! retval = getAllNativesForType(flav.mimeType.getBaseType()); if (retval == null || retval.isEmpty()) { ! retval = flavorToNativeLookup(flav, SYNTHESIZE_IF_NOT_FOUND); } else { // In this branch it is guaranteed that natives explicitly // listed for flav's MIME type were added with // addUnencodedNativeForFlavor(), so they have lower priority. ! List<String> explicitList = ! flavorToNativeLookup(flav, !SYNTHESIZE_IF_NOT_FOUND); ! ! // flavorToNativeLookup() never returns null. ! // It can return an empty List, however. ! if (!explicitList.isEmpty()) { ! // To prevent the List stored in the map from modification. ! // This also guarantees that add/removeAll() are supported. ! retval = new ArrayList<>(retval); ! explicitList = new ArrayList<>(explicitList); ! // Use HashSet to get constant-time performance for search. ! explicitList.removeAll(new HashSet<>(retval)); ! retval.addAll(explicitList); ! } } } else { ! retval = flavorToNativeLookup(flav, SYNTHESIZE_IF_NOT_FOUND); } ! getNativesForFlavorCache.put(flav, new SoftReference<>(retval)); // Create a copy, because client code can modify the returned list. return new ArrayList<>(retval); } /** --- 666,732 ---- * specific data formats * * @see #encodeDataFlavor * @since 1.4 */ + @Override public synchronized List<String> getNativesForFlavor(DataFlavor flav) { ! LinkedHashSet<String> retval = nativesForFlavorCache.check(flav); if (retval != null) { return new ArrayList<>(retval); } if (flav == null) { ! retval = new LinkedHashSet<>(getNativeToFlavor().keySet()); } else if (disabledMappingGenerationKeys.contains(flav)) { // In this case we shouldn't synthesize a native for this flavor, // since its mappings were explicitly specified. ! retval = flavorToNativeLookup(flav, false); } else if (DataTransferer.isFlavorCharsetTextType(flav)) { + retval = new LinkedHashSet<>(0); // For text/* flavors, flavor-to-native mappings specified in // flavormap.properties are stored per flavor's base type. if ("text".equals(flav.getPrimaryType())) { ! LinkedHashSet<String> textTypeNatives = ! getTextTypeToNative().get(flav.mimeType.getBaseType()); ! if (textTypeNatives != null) { ! retval.addAll(textTypeNatives); } } // Also include text/plain natives, but don't duplicate Strings ! LinkedHashSet<String> textTypeNatives = ! getTextTypeToNative().get(TEXT_PLAIN_BASE_TYPE); ! if (textTypeNatives != null) { ! retval.addAll(textTypeNatives); } ! if (retval.isEmpty()) { ! retval = flavorToNativeLookup(flav, true); } else { // In this branch it is guaranteed that natives explicitly // listed for flav's MIME type were added with // addUnencodedNativeForFlavor(), so they have lower priority. ! retval.addAll(flavorToNativeLookup(flav, false)); } } else if (DataTransferer.isFlavorNoncharsetTextType(flav)) { ! retval = getTextTypeToNative().get(flav.mimeType.getBaseType()); if (retval == null || retval.isEmpty()) { ! retval = flavorToNativeLookup(flav, true); } else { // In this branch it is guaranteed that natives explicitly // listed for flav's MIME type were added with // addUnencodedNativeForFlavor(), so they have lower priority. ! retval.addAll(flavorToNativeLookup(flav, false)); } } else { ! retval = flavorToNativeLookup(flav, true); } ! nativesForFlavorCache.put(flav, retval); // Create a copy, because client code can modify the returned list. return new ArrayList<>(retval); } /**
*** 789,854 **** * platform-specific native can be translated * * @see #encodeJavaMIMEType * @since 1.4 */ public synchronized List<DataFlavor> getFlavorsForNative(String nat) { ! ! // Check cache, even for null nat ! SoftReference<List<DataFlavor>> ref = getFlavorsForNativeCache.get(nat); ! if (ref != null) { ! List<DataFlavor> retval = ref.get(); ! if (retval != null) { ! return new ArrayList<>(retval); ! } } - final LinkedHashSet <DataFlavor> returnValue = - new LinkedHashSet<>(); - if (nat == null) { ! final List<String> natives = getNativesForFlavor(null); ! ! for (String n : natives) ! { ! final List<DataFlavor> flavors = getFlavorsForNative(n); ! ! for (DataFlavor df : flavors) ! { ! returnValue.add(df); ! } } } else { ! ! final List<DataFlavor> flavors = nativeToFlavorLookup(nat); ! if (disabledMappingGenerationKeys.contains(nat)) { ! return flavors; } ! final List<DataFlavor> flavorsAndBaseTypes = nativeToFlavorLookup(nat); ! for (DataFlavor df : flavorsAndBaseTypes) { returnValue.add(df); if ("text".equals(df.getPrimaryType())) { ! try { ! returnValue.addAll( ! convertMimeTypeToDataFlavors( ! new MimeType(df.getMimeType() ! ).getBaseType())); ! } catch (MimeTypeParseException e) { ! e.printStackTrace(); } } } ! ! } ! ! final List<DataFlavor> arrayList = new ArrayList<>(returnValue); ! getFlavorsForNativeCache.put(nat, new SoftReference<>(arrayList)); ! return new ArrayList<>(arrayList); } private static Set<DataFlavor> convertMimeTypeToDataFlavors( final String baseType) { --- 758,799 ---- * platform-specific native can be translated * * @see #encodeJavaMIMEType * @since 1.4 */ + @Override public synchronized List<DataFlavor> getFlavorsForNative(String nat) { ! LinkedHashSet<DataFlavor> returnValue = flavorsForNativeCache.check(nat); ! if (returnValue != null) { ! return new ArrayList<>(returnValue); ! } else { ! returnValue = new LinkedHashSet<>(); } if (nat == null) { ! for (String n : getNativesForFlavor(null)) { ! returnValue.addAll(getFlavorsForNative(n)); } } else { ! final LinkedHashSet<DataFlavor> flavors = nativeToFlavorLookup(nat); if (disabledMappingGenerationKeys.contains(nat)) { ! return new ArrayList<>(flavors); } ! final LinkedHashSet<DataFlavor> flavorsWithSynthesized = nativeToFlavorLookup(nat); ! for (DataFlavor df : flavorsWithSynthesized) { returnValue.add(df); if ("text".equals(df.getPrimaryType())) { ! String baseType = df.mimeType.getBaseType(); ! returnValue.addAll(convertMimeTypeToDataFlavors(baseType)); } } } ! flavorsForNativeCache.put(nat, returnValue); ! return new ArrayList<>(returnValue); } private static Set<DataFlavor> convertMimeTypeToDataFlavors( final String baseType) {
*** 860,870 **** final MimeType mimeType = new MimeType(baseType); subType = mimeType.getSubType(); } catch (MimeTypeParseException mtpe) { // Cannot happen, since we checked all mappings // on load from flavormap.properties. - assert(false); } if (DataTransferer.doesSubtypeSupportCharset(subType, null)) { if (TEXT_PLAIN_BASE_TYPE.equals(baseType)) { --- 805,814 ----
*** 938,952 **** } } return returnValue; } ! private static final String [] htmlDocumntTypes = ! new String [] {"all", "selection", "fragment"}; ! private static LinkedHashSet<String> handleHtmlMimeTypes( ! String baseType, String mimeType) { LinkedHashSet<String> returnValues = new LinkedHashSet<>(); if (HTML_TEXT_BASE_TYPE.equals(baseType)) { for (String documentType : htmlDocumntTypes) { --- 882,897 ---- } } return returnValue; } ! private static final String [] htmlDocumntTypes = new String [] {"all", ! "selection", ! "fragment"}; ! private static LinkedHashSet<String> handleHtmlMimeTypes(String baseType, ! String mimeType) { LinkedHashSet<String> returnValues = new LinkedHashSet<>(); if (HTML_TEXT_BASE_TYPE.equals(baseType)) { for (String documentType : htmlDocumntTypes) {
*** 979,996 **** * <code>String</code> natives * * @see #getNativesForFlavor * @see #encodeDataFlavor */ ! public synchronized Map<DataFlavor,String> ! getNativesForFlavors(DataFlavor[] flavors) { // Use getNativesForFlavor to generate extra natives for text flavors // and stringFlavor if (flavors == null) { ! List flavor_list = getFlavorsForNative(null); flavors = new DataFlavor[flavor_list.size()]; flavor_list.toArray(flavors); } Map<DataFlavor, String> retval = new HashMap<>(flavors.length, 1.0f); --- 924,941 ---- * <code>String</code> natives * * @see #getNativesForFlavor * @see #encodeDataFlavor */ ! @Override ! public synchronized Map<DataFlavor,String> getNativesForFlavors(DataFlavor[] flavors) { // Use getNativesForFlavor to generate extra natives for text flavors // and stringFlavor if (flavors == null) { ! List<DataFlavor> flavor_list = getFlavorsForNative(null); flavors = new DataFlavor[flavor_list.size()]; flavor_list.toArray(flavors); } Map<DataFlavor, String> retval = new HashMap<>(flavors.length, 1.0f);
*** 1025,1052 **** * <code>DataFlavor</code>s * * @see #getFlavorsForNative * @see #encodeJavaMIMEType */ ! public synchronized Map<String,DataFlavor> ! getFlavorsForNatives(String[] natives) { // Use getFlavorsForNative to generate extra flavors for text natives - if (natives == null) { ! List native_list = getNativesForFlavor(null); ! natives = new String[native_list.size()]; ! native_list.toArray(natives); } Map<String, DataFlavor> retval = new HashMap<>(natives.length, 1.0f); for (String aNative : natives) { List<DataFlavor> flavors = getFlavorsForNative(aNative); DataFlavor flav = (flavors.isEmpty())? null : flavors.get(0); retval.put(aNative, flav); } - return retval; } /** * Adds a mapping from the specified <code>DataFlavor</code> (and all --- 970,995 ---- * <code>DataFlavor</code>s * * @see #getFlavorsForNative * @see #encodeJavaMIMEType */ ! @Override ! public synchronized Map<String,DataFlavor> getFlavorsForNatives(String[] natives) { // Use getFlavorsForNative to generate extra flavors for text natives if (natives == null) { ! List<String> nativesList = getNativesForFlavor(null); ! natives = new String[nativesList.size()]; ! nativesList.toArray(natives); } Map<String, DataFlavor> retval = new HashMap<>(natives.length, 1.0f); for (String aNative : natives) { List<DataFlavor> flavors = getFlavorsForNative(aNative); DataFlavor flav = (flavors.isEmpty())? null : flavors.get(0); retval.put(aNative, flav); } return retval; } /** * Adds a mapping from the specified <code>DataFlavor</code> (and all
*** 1068,1091 **** * @see #addFlavorForUnencodedNative * @since 1.4 */ public synchronized void addUnencodedNativeForFlavor(DataFlavor flav, String nat) { ! if (flav == null || nat == null) { ! throw new NullPointerException("null arguments not permitted"); ! } ! List<String> natives = getFlavorToNative().get(flav); if (natives == null) { ! natives = new ArrayList<>(1); getFlavorToNative().put(flav, natives); - } else if (natives.contains(nat)) { - return; } natives.add(nat); ! getNativesForFlavorCache.remove(flav); ! getNativesForFlavorCache.remove(null); } /** * Discards the current mappings for the specified <code>DataFlavor</code> * and all <code>DataFlavor</code>s equal to the specified --- 1011,1030 ---- * @see #addFlavorForUnencodedNative * @since 1.4 */ public synchronized void addUnencodedNativeForFlavor(DataFlavor flav, String nat) { ! Objects.requireNonNull(nat, "Null native not permitted"); ! Objects.requireNonNull(flav, "Null flavor not permitted"); ! LinkedHashSet<String> natives = getFlavorToNative().get(flav); if (natives == null) { ! natives = new LinkedHashSet<>(1); getFlavorToNative().put(flav, natives); } natives.add(nat); ! nativesForFlavorCache.remove(flav); } /** * Discards the current mappings for the specified <code>DataFlavor</code> * and all <code>DataFlavor</code>s equal to the specified
*** 1114,1135 **** * @see #setFlavorsForNative * @since 1.4 */ public synchronized void setNativesForFlavor(DataFlavor flav, String[] natives) { ! if (flav == null || natives == null) { ! throw new NullPointerException("null arguments not permitted"); ! } getFlavorToNative().remove(flav); for (String aNative : natives) { addUnencodedNativeForFlavor(flav, aNative); } disabledMappingGenerationKeys.add(flav); ! // Clear the cache to handle the case of empty natives. ! getNativesForFlavorCache.remove(flav); ! getNativesForFlavorCache.remove(null); } /** * Adds a mapping from a single <code>String</code> native to a single * <code>DataFlavor</code>. Unlike <code>getFlavorsForNative</code>, the --- 1053,1071 ---- * @see #setFlavorsForNative * @since 1.4 */ public synchronized void setNativesForFlavor(DataFlavor flav, String[] natives) { ! Objects.requireNonNull(natives, "Null natives not permitted"); ! Objects.requireNonNull(flav, "Null flavors not permitted"); getFlavorToNative().remove(flav); for (String aNative : natives) { addUnencodedNativeForFlavor(flav, aNative); } disabledMappingGenerationKeys.add(flav); ! nativesForFlavorCache.remove(flav); } /** * Adds a mapping from a single <code>String</code> native to a single * <code>DataFlavor</code>. Unlike <code>getFlavorsForNative</code>, the
*** 1148,1171 **** * @see #addUnencodedNativeForFlavor * @since 1.4 */ public synchronized void addFlavorForUnencodedNative(String nat, DataFlavor flav) { ! if (nat == null || flav == null) { ! throw new NullPointerException("null arguments not permitted"); ! } ! List<DataFlavor> flavors = getNativeToFlavor().get(nat); if (flavors == null) { ! flavors = new ArrayList<>(1); getNativeToFlavor().put(nat, flavors); - } else if (flavors.contains(flav)) { - return; } flavors.add(flav); ! getFlavorsForNativeCache.remove(nat); ! getFlavorsForNativeCache.remove(null); } /** * Discards the current mappings for the specified <code>String</code> * native, and creates new mappings to the specified --- 1084,1103 ---- * @see #addUnencodedNativeForFlavor * @since 1.4 */ public synchronized void addFlavorForUnencodedNative(String nat, DataFlavor flav) { ! Objects.requireNonNull(nat, "Null native not permitted"); ! Objects.requireNonNull(flav, "Null flavor not permitted"); ! LinkedHashSet<DataFlavor> flavors = getNativeToFlavor().get(nat); if (flavors == null) { ! flavors = new LinkedHashSet<>(1); getNativeToFlavor().put(nat, flavors); } flavors.add(flav); ! flavorsForNativeCache.remove(nat); } /** * Discards the current mappings for the specified <code>String</code> * native, and creates new mappings to the specified
*** 1193,1214 **** * @see #setNativesForFlavor * @since 1.4 */ public synchronized void setFlavorsForNative(String nat, DataFlavor[] flavors) { ! if (nat == null || flavors == null) { ! throw new NullPointerException("null arguments not permitted"); ! } getNativeToFlavor().remove(nat); for (DataFlavor flavor : flavors) { addFlavorForUnencodedNative(nat, flavor); } disabledMappingGenerationKeys.add(nat); ! // Clear the cache to handle the case of empty flavors. ! getFlavorsForNativeCache.remove(nat); ! getFlavorsForNativeCache.remove(null); } /** * Encodes a MIME type for use as a <code>String</code> native. The format * of an encoded representation of a MIME type is implementation-dependent. --- 1125,1143 ---- * @see #setNativesForFlavor * @since 1.4 */ public synchronized void setFlavorsForNative(String nat, DataFlavor[] flavors) { ! Objects.requireNonNull(nat, "Null native not permitted"); ! Objects.requireNonNull(flavors, "Null flavors not permitted"); getNativeToFlavor().remove(nat); for (DataFlavor flavor : flavors) { addFlavorForUnencodedNative(nat, flavor); } disabledMappingGenerationKeys.add(nat); ! flavorsForNativeCache.remove(nat); } /** * Encodes a MIME type for use as a <code>String</code> native. The format * of an encoded representation of a MIME type is implementation-dependent.
*** 1305,1323 **** return (retval_str != null) ? new DataFlavor(retval_str) : null; } ! private List<String> getAllNativesForType(String type) { ! Set<String> retval = null; ! for (DataFlavor dataFlavor : convertMimeTypeToDataFlavors(type)) { ! List<String> natives = getFlavorToNative().get(dataFlavor); ! if (natives != null && !natives.isEmpty()) { ! if (retval == null) { ! retval = new LinkedHashSet<>(); } ! retval.addAll(natives); } } - return retval == null ? null : new ArrayList<>(retval); } } --- 1234,1264 ---- return (retval_str != null) ? new DataFlavor(retval_str) : null; } ! private static final class SoftCache<K, V> { ! Map<K, SoftReference<LinkedHashSet<V>>> cache; ! ! public void put(K key, LinkedHashSet<V> value) { ! if (cache == null) { ! cache = new HashMap<>(1); ! } ! cache.put(key, new SoftReference<>(value)); ! } ! ! public void remove(K key) { ! if (cache == null) return; ! cache.remove(null); ! cache.remove(key); } ! ! public LinkedHashSet<V> check(K key) { ! if (cache == null) return null; ! SoftReference<LinkedHashSet<V>> ref = cache.get(key); ! if (ref != null) { ! return ref.get(); } + return null; } } }