src/share/classes/java/awt/datatransfer/SystemFlavorMap.java
Print this page
*** 36,52 ****
import java.net.URL;
import java.net.MalformedURLException;
import java.util.ArrayList;
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;
/**
--- 36,53 ----
import java.net.URL;
import java.net.MalformedURLException;
import java.util.ArrayList;
+ import java.util.Collections;
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;
}
--- 101,124 ----
* 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
*/
--- 126,198 ----
/**
* 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 Map<String, LinkedHashSet<String>> textTypeToNative = new HashMap<>();
+
+ /**
* Shows if the object has been initialized.
*/
private boolean isMapInitialized = false;
/**
+ * 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();
+ // From this point the map should not be modified
+ textTypeToNative = Collections.unmodifiableMap(textTypeToNative);
+ }
+ return textTypeToNative;
+ }
+
+ /**
* 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());
--- 418,440 ----
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);
}
--- 519,532 ----
* 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);
--- 536,555 ----
* 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);
--- 571,618 ----
"\"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
--- 623,651 ----
}
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);
}
/**
--- 669,735 ----
* 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) {
--- 761,802 ----
* 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))
{
--- 808,817 ----
*** 941,952 ****
}
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) {
--- 888,899 ----
}
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);
--- 926,943 ----
* <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
--- 972,997 ----
* <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
--- 1013,1032 ----
* @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
--- 1055,1073 ----
* @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
--- 1086,1105 ----
* @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.
--- 1127,1145 ----
* @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);
}
}
--- 1236,1266 ----
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;
}
}
}