提交 0071d180 编写于 作者: P pchelko

8027148: SystemFlavorMap.getNativesForFlavor returns list of native formats in incorrect order

Reviewed-by: anthony, serb
上级 1b2caa0f
...@@ -38,11 +38,13 @@ import java.net.URL; ...@@ -38,11 +38,13 @@ import java.net.URL;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import sun.awt.AppContext; import sun.awt.AppContext;
...@@ -101,20 +103,12 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -101,20 +103,12 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
*/ */
private static final String HTML_TEXT_BASE_TYPE = "text/html"; 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 * Maps native Strings to Lists of DataFlavors (or base type Strings for
* text DataFlavors). * text DataFlavors).
* Do not use the field directly, use getNativeToFlavor() instead. * Do not use the field directly, use getNativeToFlavor() instead.
*/ */
private final Map<String, List<DataFlavor>> nativeToFlavor = new HashMap<>(); private final Map<String, LinkedHashSet<DataFlavor>> nativeToFlavor = new HashMap<>();
/** /**
* Accessor to nativeToFlavor map. Since we use lazy initialization we must * Accessor to nativeToFlavor map. Since we use lazy initialization we must
...@@ -123,7 +117,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -123,7 +117,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* *
* @return nativeToFlavor * @return nativeToFlavor
*/ */
private Map<String, List<DataFlavor>> getNativeToFlavor() { private Map<String, LinkedHashSet<DataFlavor>> getNativeToFlavor() {
if (!isMapInitialized) { if (!isMapInitialized) {
initSystemFlavorMap(); initSystemFlavorMap();
} }
...@@ -135,7 +129,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -135,7 +129,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* native Strings. * native Strings.
* Do not use the field directly, use getFlavorToNative() instead. * Do not use the field directly, use getFlavorToNative() instead.
*/ */
private final Map<DataFlavor, List<String>> flavorToNative = new HashMap<>(); private final Map<DataFlavor, LinkedHashSet<String>> flavorToNative = new HashMap<>();
/** /**
* Accessor to flavorToNative map. Since we use lazy initialization we must * Accessor to flavorToNative map. Since we use lazy initialization we must
...@@ -144,29 +138,52 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -144,29 +138,52 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* *
* @return flavorToNative * @return flavorToNative
*/ */
private synchronized Map<DataFlavor, List<String>> getFlavorToNative() { private synchronized Map<DataFlavor, LinkedHashSet<String>> getFlavorToNative() {
if (!isMapInitialized) { if (!isMapInitialized) {
initSystemFlavorMap(); initSystemFlavorMap();
} }
return flavorToNative; 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. * Shows if the object has been initialized.
*/ */
private boolean isMapInitialized = false; 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 * Caches the result of getNativesForFlavor(). Maps DataFlavors to
* SoftReferences which reference Lists of String natives. * SoftReferences which reference LinkedHashSet of String natives.
*/ */
private Map<DataFlavor, SoftReference<List<String>>> getNativesForFlavorCache = new HashMap<>(); private final SoftCache<DataFlavor, String> nativesForFlavorCache = new SoftCache<>();
/** /**
* Caches the result getFlavorsForNative(). Maps String natives to * Caches the result getFlavorsForNative(). Maps String natives to
* SoftReferences which reference Lists of DataFlavors. * SoftReferences which reference LinkedHashSet of DataFlavors.
*/ */
private Map<String, SoftReference<List<DataFlavor>>> getFlavorsForNativeCache = new HashMap<>(); private final SoftCache<String, DataFlavor> flavorsForNativeCache = new SoftCache<>();
/** /**
* Dynamic mapping generation used for text mappings should not be applied * Dynamic mapping generation used for text mappings should not be applied
...@@ -174,7 +191,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -174,7 +191,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* explicitly specified with setFlavorsForNative() or * explicitly specified with setFlavorsForNative() or
* setNativesForFlavor(). This keeps all such keys. * setNativesForFlavor(). This keeps all such keys.
*/ */
private Set disabledMappingGenerationKeys = new HashSet(); private Set<Object> disabledMappingGenerationKeys = new HashSet<>();
/** /**
* Returns the default FlavorMap for this thread's ClassLoader. * Returns the default FlavorMap for this thread's ClassLoader.
...@@ -403,7 +420,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -403,7 +420,7 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
flavor = new DataFlavor(value); flavor = new DataFlavor(value);
} catch (Exception e) { } catch (Exception e) {
try { try {
flavor = new DataFlavor(value, (String)null); flavor = new DataFlavor(value, null);
} catch (Exception ee) { } catch (Exception ee) {
ee.printStackTrace(); ee.printStackTrace();
continue; continue;
...@@ -411,11 +428,11 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -411,11 +428,11 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
} }
final LinkedHashSet<DataFlavor> dfs = new LinkedHashSet<>(); final LinkedHashSet<DataFlavor> dfs = new LinkedHashSet<>();
dfs.add(flavor); dfs.add(flavor);
if ("text".equals(flavor.getPrimaryType())) { if ("text".equals(flavor.getPrimaryType())) {
dfs.addAll(convertMimeTypeToDataFlavors(value)); dfs.addAll(convertMimeTypeToDataFlavors(value));
store(flavor.mimeType.getBaseType(), key, getTextTypeToNative());
} }
for (DataFlavor df : dfs) { for (DataFlavor df : dfs) {
...@@ -504,10 +521,10 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -504,10 +521,10 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* the appropriate Map location, but rather will be appended to a List * the appropriate Map location, but rather will be appended to a List
* stored in that location. * stored in that location.
*/ */
private <H, L> void store(H hashed, L listed, Map<H, List<L>> map) { private <H, L> void store(H hashed, L listed, Map<H, LinkedHashSet<L>> map) {
List<L> list = map.get(hashed); LinkedHashSet<L> list = map.get(hashed);
if (list == null) { if (list == null) {
list = new ArrayList<>(1); list = new LinkedHashSet<>(1);
map.put(hashed, list); map.put(hashed, list);
} }
if (!list.contains(listed)) { if (!list.contains(listed)) {
...@@ -521,17 +538,17 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -521,17 +538,17 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* case, a new DataFlavor is synthesized, stored, and returned, if and * case, a new DataFlavor is synthesized, stored, and returned, if and
* only if the specified native is encoded as a Java MIME type. * only if the specified native is encoded as a Java MIME type.
*/ */
private List<DataFlavor> nativeToFlavorLookup(String nat) { private LinkedHashSet<DataFlavor> nativeToFlavorLookup(String nat) {
List<DataFlavor> flavors = getNativeToFlavor().get(nat); LinkedHashSet<DataFlavor> flavors = getNativeToFlavor().get(nat);
if (nat != null && !disabledMappingGenerationKeys.contains(nat)) { if (nat != null && !disabledMappingGenerationKeys.contains(nat)) {
DataTransferer transferer = DataTransferer.getInstance(); DataTransferer transferer = DataTransferer.getInstance();
if (transferer != null) { if (transferer != null) {
List<DataFlavor> platformFlavors = LinkedHashSet<DataFlavor> platformFlavors =
transferer.getPlatformMappingsForNative(nat); transferer.getPlatformMappingsForNative(nat);
if (!platformFlavors.isEmpty()) { if (!platformFlavors.isEmpty()) {
if (flavors != null) { if (flavors != null) {
platformFlavors.removeAll(new HashSet<>(flavors));
// Prepending the platform-specific mappings ensures // Prepending the platform-specific mappings ensures
// that the flavors added with // that the flavors added with
// addFlavorForUnencodedNative() are at the end of // addFlavorForUnencodedNative() are at the end of
...@@ -557,24 +574,22 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -557,24 +574,22 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
} }
if (flavor != null) { if (flavor != null) {
flavors = new ArrayList<>(1); flavors = new LinkedHashSet<>(1);
getNativeToFlavor().put(nat, flavors); getNativeToFlavor().put(nat, flavors);
flavors.add(flavor); flavors.add(flavor);
getFlavorsForNativeCache.remove(nat); flavorsForNativeCache.remove(nat);
getFlavorsForNativeCache.remove(null);
List<String> natives = getFlavorToNative().get(flavor); LinkedHashSet<String> natives = getFlavorToNative().get(flavor);
if (natives == null) { if (natives == null) {
natives = new ArrayList<>(1); natives = new LinkedHashSet<>(1);
getFlavorToNative().put(flavor, natives); getFlavorToNative().put(flavor, natives);
} }
natives.add(nat); natives.add(nat);
getNativesForFlavorCache.remove(flavor); nativesForFlavorCache.remove(flavor);
getNativesForFlavorCache.remove(null);
} }
} }
return (flavors != null) ? flavors : new ArrayList<>(0); return (flavors != null) ? flavors : new LinkedHashSet<>(0);
} }
/** /**
...@@ -585,18 +600,18 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -585,18 +600,18 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* encoding the DataFlavor's MIME type. Otherwise an empty List is returned * encoding the DataFlavor's MIME type. Otherwise an empty List is returned
* and 'flavorToNative' remains unaffected. * and 'flavorToNative' remains unaffected.
*/ */
private List<String> flavorToNativeLookup(final DataFlavor flav, private LinkedHashSet<String> flavorToNativeLookup(final DataFlavor flav,
final boolean synthesize) { final boolean synthesize) {
List<String> natives = getFlavorToNative().get(flav);
LinkedHashSet<String> natives = getFlavorToNative().get(flav);
if (flav != null && !disabledMappingGenerationKeys.contains(flav)) { if (flav != null && !disabledMappingGenerationKeys.contains(flav)) {
DataTransferer transferer = DataTransferer.getInstance(); DataTransferer transferer = DataTransferer.getInstance();
if (transferer != null) { if (transferer != null) {
List<String> platformNatives = LinkedHashSet<String> platformNatives =
transferer.getPlatformMappingsForFlavor(flav); transferer.getPlatformMappingsForFlavor(flav);
if (!platformNatives.isEmpty()) { if (!platformNatives.isEmpty()) {
if (natives != null) { if (natives != null) {
platformNatives.removeAll(new HashSet<>(natives));
// Prepend the platform-specific mappings to ensure // Prepend the platform-specific mappings to ensure
// that the natives added with // that the natives added with
// addUnencodedNativeForFlavor() are at the end of // addUnencodedNativeForFlavor() are at the end of
...@@ -611,26 +626,25 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -611,26 +626,25 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
if (natives == null) { if (natives == null) {
if (synthesize) { if (synthesize) {
String encoded = encodeDataFlavor(flav); String encoded = encodeDataFlavor(flav);
natives = new ArrayList<>(1); natives = new LinkedHashSet<>(1);
getFlavorToNative().put(flav, natives); getFlavorToNative().put(flav, natives);
natives.add(encoded); natives.add(encoded);
getNativesForFlavorCache.remove(flav);
getNativesForFlavorCache.remove(null);
List<DataFlavor> flavors = getNativeToFlavor().get(encoded); LinkedHashSet<DataFlavor> flavors = getNativeToFlavor().get(encoded);
if (flavors == null) { if (flavors == null) {
flavors = new ArrayList<>(1); flavors = new LinkedHashSet<>(1);
getNativeToFlavor().put(encoded, flavors); getNativeToFlavor().put(encoded, flavors);
} }
flavors.add(flav); flavors.add(flav);
getFlavorsForNativeCache.remove(encoded);
getFlavorsForNativeCache.remove(null); nativesForFlavorCache.remove(flav);
flavorsForNativeCache.remove(encoded);
} else { } else {
natives = new ArrayList<>(0); natives = new LinkedHashSet<>(0);
} }
} }
return natives; return new LinkedHashSet<>(natives);
} }
/** /**
...@@ -658,103 +672,63 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -658,103 +672,63 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* @see #encodeDataFlavor * @see #encodeDataFlavor
* @since 1.4 * @since 1.4
*/ */
@Override
public synchronized List<String> getNativesForFlavor(DataFlavor flav) { public synchronized List<String> getNativesForFlavor(DataFlavor flav) {
List<String> retval = null; LinkedHashSet<String> retval = nativesForFlavorCache.check(flav);
if (retval != null) {
// Check cache, even for null flav return new ArrayList<>(retval);
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) { if (flav == null) {
retval = new ArrayList<>(getNativeToFlavor().keySet()); retval = new LinkedHashSet<>(getNativeToFlavor().keySet());
} else if (disabledMappingGenerationKeys.contains(flav)) { } else if (disabledMappingGenerationKeys.contains(flav)) {
// In this case we shouldn't synthesize a native for this flavor, // In this case we shouldn't synthesize a native for this flavor,
// since its mappings were explicitly specified. // since its mappings were explicitly specified.
retval = flavorToNativeLookup(flav, !SYNTHESIZE_IF_NOT_FOUND); retval = flavorToNativeLookup(flav, false);
} else if (DataTransferer.isFlavorCharsetTextType(flav)) { } else if (DataTransferer.isFlavorCharsetTextType(flav)) {
retval = new LinkedHashSet<>(0);
// For text/* flavors, flavor-to-native mappings specified in // For text/* flavors, flavor-to-native mappings specified in
// flavormap.properties are stored per flavor's base type. // flavormap.properties are stored per flavor's base type.
if ("text".equals(flav.getPrimaryType())) { if ("text".equals(flav.getPrimaryType())) {
retval = getAllNativesForType(flav.mimeType.getBaseType()); LinkedHashSet<String> textTypeNatives =
if (retval != null) { getTextTypeToNative().get(flav.mimeType.getBaseType());
// To prevent the List stored in the map from modification. if (textTypeNatives != null) {
retval = new ArrayList(retval); retval.addAll(textTypeNatives);
} }
} }
// Also include text/plain natives, but don't duplicate Strings // Also include text/plain natives, but don't duplicate Strings
List<String> textPlainList = getAllNativesForType(TEXT_PLAIN_BASE_TYPE); LinkedHashSet<String> textTypeNatives =
getTextTypeToNative().get(TEXT_PLAIN_BASE_TYPE);
if (textPlainList != null && !textPlainList.isEmpty()) { if (textTypeNatives != null) {
// To prevent the List stored in the map from modification. retval.addAll(textTypeNatives);
// 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()) { if (retval.isEmpty()) {
retval = flavorToNativeLookup(flav, SYNTHESIZE_IF_NOT_FOUND); retval = flavorToNativeLookup(flav, true);
} else { } else {
// In this branch it is guaranteed that natives explicitly // In this branch it is guaranteed that natives explicitly
// listed for flav's MIME type were added with // listed for flav's MIME type were added with
// addUnencodedNativeForFlavor(), so they have lower priority. // addUnencodedNativeForFlavor(), so they have lower priority.
List<String> explicitList = retval.addAll(flavorToNativeLookup(flav, false));
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)) { } else if (DataTransferer.isFlavorNoncharsetTextType(flav)) {
retval = getAllNativesForType(flav.mimeType.getBaseType()); retval = getTextTypeToNative().get(flav.mimeType.getBaseType());
if (retval == null || retval.isEmpty()) { if (retval == null || retval.isEmpty()) {
retval = flavorToNativeLookup(flav, SYNTHESIZE_IF_NOT_FOUND); retval = flavorToNativeLookup(flav, true);
} else { } else {
// In this branch it is guaranteed that natives explicitly // In this branch it is guaranteed that natives explicitly
// listed for flav's MIME type were added with // listed for flav's MIME type were added with
// addUnencodedNativeForFlavor(), so they have lower priority. // addUnencodedNativeForFlavor(), so they have lower priority.
List<String> explicitList = retval.addAll(flavorToNativeLookup(flav, false));
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 { } else {
retval = flavorToNativeLookup(flav, SYNTHESIZE_IF_NOT_FOUND); retval = flavorToNativeLookup(flav, true);
} }
getNativesForFlavorCache.put(flav, new SoftReference<>(retval)); nativesForFlavorCache.put(flav, retval);
// Create a copy, because client code can modify the returned list. // Create a copy, because client code can modify the returned list.
return new ArrayList<>(retval); return new ArrayList<>(retval);
} }
...@@ -790,62 +764,38 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -790,62 +764,38 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* @see #encodeJavaMIMEType * @see #encodeJavaMIMEType
* @since 1.4 * @since 1.4
*/ */
@Override
public synchronized List<DataFlavor> getFlavorsForNative(String nat) { public synchronized List<DataFlavor> getFlavorsForNative(String nat) {
LinkedHashSet<DataFlavor> returnValue = flavorsForNativeCache.check(nat);
// Check cache, even for null nat if (returnValue != null) {
SoftReference<List<DataFlavor>> ref = getFlavorsForNativeCache.get(nat); return new ArrayList<>(returnValue);
if (ref != null) { } else {
List<DataFlavor> retval = ref.get(); returnValue = new LinkedHashSet<>();
if (retval != null) {
return new ArrayList<>(retval);
}
} }
final LinkedHashSet <DataFlavor> returnValue =
new LinkedHashSet<>();
if (nat == null) { if (nat == null) {
final List<String> natives = getNativesForFlavor(null); for (String n : getNativesForFlavor(null)) {
returnValue.addAll(getFlavorsForNative(n));
for (String n : natives)
{
final List<DataFlavor> flavors = getFlavorsForNative(n);
for (DataFlavor df : flavors)
{
returnValue.add(df);
}
} }
} else { } else {
final LinkedHashSet<DataFlavor> flavors = nativeToFlavorLookup(nat);
final List<DataFlavor> flavors = nativeToFlavorLookup(nat);
if (disabledMappingGenerationKeys.contains(nat)) { if (disabledMappingGenerationKeys.contains(nat)) {
return flavors; return new ArrayList<>(flavors);
} }
final List<DataFlavor> flavorsAndBaseTypes = final LinkedHashSet<DataFlavor> flavorsWithSynthesized =
nativeToFlavorLookup(nat); nativeToFlavorLookup(nat);
for (DataFlavor df : flavorsAndBaseTypes) { for (DataFlavor df : flavorsWithSynthesized) {
returnValue.add(df); returnValue.add(df);
if ("text".equals(df.getPrimaryType())) { if ("text".equals(df.getPrimaryType())) {
try { String baseType = df.mimeType.getBaseType();
returnValue.addAll( returnValue.addAll(convertMimeTypeToDataFlavors(baseType));
convertMimeTypeToDataFlavors(
new MimeType(df.getMimeType()
).getBaseType()));
} catch (MimeTypeParseException e) {
e.printStackTrace();
}
} }
} }
} }
flavorsForNativeCache.put(nat, returnValue);
final List<DataFlavor> arrayList = new ArrayList<>(returnValue); return new ArrayList<>(returnValue);
getFlavorsForNativeCache.put(nat, new SoftReference<>(arrayList));
return new ArrayList<>(arrayList);
} }
private static Set<DataFlavor> convertMimeTypeToDataFlavors( private static Set<DataFlavor> convertMimeTypeToDataFlavors(
...@@ -861,7 +811,6 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -861,7 +811,6 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
} catch (MimeTypeParseException mtpe) { } catch (MimeTypeParseException mtpe) {
// Cannot happen, since we checked all mappings // Cannot happen, since we checked all mappings
// on load from flavormap.properties. // on load from flavormap.properties.
assert(false);
} }
if (DataTransferer.doesSubtypeSupportCharset(subType, null)) { if (DataTransferer.doesSubtypeSupportCharset(subType, null)) {
...@@ -940,10 +889,10 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -940,10 +889,10 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
} }
private static final String [] htmlDocumntTypes = private static final String [] htmlDocumntTypes =
new String [] {"all", "selection", "fragment"}; new String [] {"all", "selection", "fragment"};
private static LinkedHashSet<String> handleHtmlMimeTypes( private static LinkedHashSet<String> handleHtmlMimeTypes(String baseType,
String baseType, String mimeType) { String mimeType) {
LinkedHashSet<String> returnValues = new LinkedHashSet<>(); LinkedHashSet<String> returnValues = new LinkedHashSet<>();
...@@ -980,14 +929,14 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -980,14 +929,14 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* @see #getNativesForFlavor * @see #getNativesForFlavor
* @see #encodeDataFlavor * @see #encodeDataFlavor
*/ */
public synchronized Map<DataFlavor,String> @Override
getNativesForFlavors(DataFlavor[] flavors) public synchronized Map<DataFlavor,String> getNativesForFlavors(DataFlavor[] flavors)
{ {
// Use getNativesForFlavor to generate extra natives for text flavors // Use getNativesForFlavor to generate extra natives for text flavors
// and stringFlavor // and stringFlavor
if (flavors == null) { if (flavors == null) {
List flavor_list = getFlavorsForNative(null); List<DataFlavor> flavor_list = getFlavorsForNative(null);
flavors = new DataFlavor[flavor_list.size()]; flavors = new DataFlavor[flavor_list.size()];
flavor_list.toArray(flavors); flavor_list.toArray(flavors);
} }
...@@ -1026,15 +975,14 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -1026,15 +975,14 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
* @see #getFlavorsForNative * @see #getFlavorsForNative
* @see #encodeJavaMIMEType * @see #encodeJavaMIMEType
*/ */
public synchronized Map<String,DataFlavor> @Override
getFlavorsForNatives(String[] natives) public synchronized Map<String,DataFlavor> getFlavorsForNatives(String[] natives)
{ {
// Use getFlavorsForNative to generate extra flavors for text natives // Use getFlavorsForNative to generate extra flavors for text natives
if (natives == null) { if (natives == null) {
List native_list = getNativesForFlavor(null); List<String> nativesList = getNativesForFlavor(null);
natives = new String[native_list.size()]; natives = new String[nativesList.size()];
native_list.toArray(natives); nativesList.toArray(natives);
} }
Map<String, DataFlavor> retval = new HashMap<>(natives.length, 1.0f); Map<String, DataFlavor> retval = new HashMap<>(natives.length, 1.0f);
...@@ -1043,7 +991,6 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -1043,7 +991,6 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
DataFlavor flav = (flavors.isEmpty())? null : flavors.get(0); DataFlavor flav = (flavors.isEmpty())? null : flavors.get(0);
retval.put(aNative, flav); retval.put(aNative, flav);
} }
return retval; return retval;
} }
...@@ -1069,20 +1016,16 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -1069,20 +1016,16 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
*/ */
public synchronized void addUnencodedNativeForFlavor(DataFlavor flav, public synchronized void addUnencodedNativeForFlavor(DataFlavor flav,
String nat) { String nat) {
if (flav == null || nat == null) { Objects.requireNonNull(nat, "Null native not permitted");
throw new NullPointerException("null arguments not permitted"); Objects.requireNonNull(flav, "Null flavor not permitted");
}
List<String> natives = getFlavorToNative().get(flav); LinkedHashSet<String> natives = getFlavorToNative().get(flav);
if (natives == null) { if (natives == null) {
natives = new ArrayList<>(1); natives = new LinkedHashSet<>(1);
getFlavorToNative().put(flav, natives); getFlavorToNative().put(flav, natives);
} else if (natives.contains(nat)) {
return;
} }
natives.add(nat); natives.add(nat);
getNativesForFlavorCache.remove(flav); nativesForFlavorCache.remove(flav);
getNativesForFlavorCache.remove(null);
} }
/** /**
...@@ -1115,18 +1058,15 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -1115,18 +1058,15 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
*/ */
public synchronized void setNativesForFlavor(DataFlavor flav, public synchronized void setNativesForFlavor(DataFlavor flav,
String[] natives) { String[] natives) {
if (flav == null || natives == null) { Objects.requireNonNull(natives, "Null natives not permitted");
throw new NullPointerException("null arguments not permitted"); Objects.requireNonNull(flav, "Null flavors not permitted");
}
getFlavorToNative().remove(flav); getFlavorToNative().remove(flav);
for (String aNative : natives) { for (String aNative : natives) {
addUnencodedNativeForFlavor(flav, aNative); addUnencodedNativeForFlavor(flav, aNative);
} }
disabledMappingGenerationKeys.add(flav); disabledMappingGenerationKeys.add(flav);
// Clear the cache to handle the case of empty natives. nativesForFlavorCache.remove(flav);
getNativesForFlavorCache.remove(flav);
getNativesForFlavorCache.remove(null);
} }
/** /**
...@@ -1149,20 +1089,16 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -1149,20 +1089,16 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
*/ */
public synchronized void addFlavorForUnencodedNative(String nat, public synchronized void addFlavorForUnencodedNative(String nat,
DataFlavor flav) { DataFlavor flav) {
if (nat == null || flav == null) { Objects.requireNonNull(nat, "Null native not permitted");
throw new NullPointerException("null arguments not permitted"); Objects.requireNonNull(flav, "Null flavor not permitted");
}
List<DataFlavor> flavors = getNativeToFlavor().get(nat); LinkedHashSet<DataFlavor> flavors = getNativeToFlavor().get(nat);
if (flavors == null) { if (flavors == null) {
flavors = new ArrayList<>(1); flavors = new LinkedHashSet<>(1);
getNativeToFlavor().put(nat, flavors); getNativeToFlavor().put(nat, flavors);
} else if (flavors.contains(flav)) {
return;
} }
flavors.add(flav); flavors.add(flav);
getFlavorsForNativeCache.remove(nat); flavorsForNativeCache.remove(nat);
getFlavorsForNativeCache.remove(null);
} }
/** /**
...@@ -1194,18 +1130,15 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -1194,18 +1130,15 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
*/ */
public synchronized void setFlavorsForNative(String nat, public synchronized void setFlavorsForNative(String nat,
DataFlavor[] flavors) { DataFlavor[] flavors) {
if (nat == null || flavors == null) { Objects.requireNonNull(nat, "Null native not permitted");
throw new NullPointerException("null arguments not permitted"); Objects.requireNonNull(flavors, "Null flavors not permitted");
}
getNativeToFlavor().remove(nat); getNativeToFlavor().remove(nat);
for (DataFlavor flavor : flavors) { for (DataFlavor flavor : flavors) {
addFlavorForUnencodedNative(nat, flavor); addFlavorForUnencodedNative(nat, flavor);
} }
disabledMappingGenerationKeys.add(nat); disabledMappingGenerationKeys.add(nat);
// Clear the cache to handle the case of empty flavors. flavorsForNativeCache.remove(nat);
getFlavorsForNativeCache.remove(nat);
getFlavorsForNativeCache.remove(null);
} }
/** /**
...@@ -1304,17 +1237,29 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { ...@@ -1304,17 +1237,29 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable {
: null; : null;
} }
private List<String> getAllNativesForType(String type) { private static final class SoftCache<K, V> {
Set<String> retval = null; Map<K, SoftReference<LinkedHashSet<V>>> cache;
for (DataFlavor dataFlavor : convertMimeTypeToDataFlavors(type)) {
List<String> natives = getFlavorToNative().get(dataFlavor); public void put(K key, LinkedHashSet<V> value) {
if (natives != null && !natives.isEmpty()) { if (cache == null) {
if (retval == null) { cache = new HashMap<>(1);
retval = new LinkedHashSet<>(); }
} cache.put(key, new SoftReference<>(value));
retval.addAll(natives); }
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;
} }
return retval == null ? null : new ArrayList<>(retval);
} }
} }
...@@ -77,6 +77,7 @@ import java.util.Comparator; ...@@ -77,6 +77,7 @@ import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.SortedMap; import java.util.SortedMap;
...@@ -273,7 +274,7 @@ public abstract class DataTransferer { ...@@ -273,7 +274,7 @@ public abstract class DataTransferer {
* instead, null will be returned. * instead, null will be returned.
*/ */
public static synchronized DataTransferer getInstance() { public static synchronized DataTransferer getInstance() {
return ((ComponentFactory) Toolkit.getDefaultToolkit()).getDataTransferer(); return ((SunToolkit) Toolkit.getDefaultToolkit()).getDataTransferer();
} }
/** /**
...@@ -2424,8 +2425,8 @@ search: ...@@ -2424,8 +2425,8 @@ search:
* If there are no platform-specific mappings for this native, the method * If there are no platform-specific mappings for this native, the method
* returns an empty <code>List</code>. * returns an empty <code>List</code>.
*/ */
public List getPlatformMappingsForNative(String nat) { public LinkedHashSet<DataFlavor> getPlatformMappingsForNative(String nat) {
return new ArrayList(); return new LinkedHashSet<>();
} }
/** /**
...@@ -2433,8 +2434,8 @@ search: ...@@ -2433,8 +2434,8 @@ search:
* If there are no platform-specific mappings for this flavor, the method * If there are no platform-specific mappings for this flavor, the method
* returns an empty <code>List</code>. * returns an empty <code>List</code>.
*/ */
public List getPlatformMappingsForFlavor(DataFlavor df) { public LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df) {
return new ArrayList(); return new LinkedHashSet<>();
} }
/** /**
......
...@@ -45,6 +45,7 @@ import java.net.URISyntaxException; ...@@ -45,6 +45,7 @@ import java.net.URISyntaxException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
...@@ -328,8 +329,9 @@ public class XDataTransferer extends DataTransferer { ...@@ -328,8 +329,9 @@ public class XDataTransferer extends DataTransferer {
* a valid MIME and return a list of flavors to which the data in this MIME * a valid MIME and return a list of flavors to which the data in this MIME
* type can be translated by the Data Transfer subsystem. * type can be translated by the Data Transfer subsystem.
*/ */
public List <DataFlavor> getPlatformMappingsForNative(String nat) { public LinkedHashSet<DataFlavor> getPlatformMappingsForNative(String nat) {
List <DataFlavor> flavors = new ArrayList(); LinkedHashSet<DataFlavor> flavors = new LinkedHashSet<>();
if (nat == null) { if (nat == null) {
return flavors; return flavors;
...@@ -389,8 +391,8 @@ public class XDataTransferer extends DataTransferer { ...@@ -389,8 +391,8 @@ public class XDataTransferer extends DataTransferer {
* MIME types to which the data in this flavor can be translated by the Data * MIME types to which the data in this flavor can be translated by the Data
* Transfer subsystem. * Transfer subsystem.
*/ */
public List getPlatformMappingsForFlavor(DataFlavor df) { public LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df) {
List natives = new ArrayList(1); LinkedHashSet<String> natives = new LinkedHashSet<>(1);
if (df == null) { if (df == null) {
return natives; return natives;
......
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.SystemFlavorMap;
import java.util.List;
/*
@test
@bug 4512530 8027148
@summary tests that mappings for text flavors are generated properly
@author das@sparc.spb.su area=datatransfer
*/
public class MappingGenerationTest {
private static final SystemFlavorMap fm =
(SystemFlavorMap)SystemFlavorMap.getDefaultFlavorMap();
public static void main(String[] args) {
test1();
test2();
test3();
test4();
test5();
test6();
}
/**
* Verifies that Lists returned from getNativesForFlavor() and
* getFlavorsForNative() are not modified with a subsequent call
* to addUnencodedNativeForFlavor() and addFlavorForUnencodedNative()
* respectively.
*/
public static void test1() {
DataFlavor df = new DataFlavor("text/plain-test1", null);
String nat = "native1";
List<String> natives = fm.getNativesForFlavor(df);
fm.addUnencodedNativeForFlavor(df, nat);
List<String> nativesNew = fm.getNativesForFlavor(df);
if (natives.equals(nativesNew)) {
System.err.println("orig=" + natives);
System.err.println("new=" + nativesNew);
throw new RuntimeException("Test failed");
}
List<DataFlavor> flavors = fm.getFlavorsForNative(nat);
fm.addFlavorForUnencodedNative(nat, df);
List<DataFlavor> flavorsNew = fm.getFlavorsForNative(nat);
if (flavors.equals(flavorsNew)) {
System.err.println("orig=" + flavors);
System.err.println("new=" + flavorsNew);
throw new RuntimeException("Test failed");
}
}
/**
* Verifies that SystemFlavorMap is not affected by modification of
* the Lists returned from getNativesForFlavor() and
* getFlavorsForNative().
*/
public static void test2() {
DataFlavor df = new DataFlavor("text/plain-test2", null);
String nat = "native2";
DataFlavor extraDf = new DataFlavor("text/test", null);
List<String> natives = fm.getNativesForFlavor(df);
natives.add("Should not be here");
java.util.List nativesNew = fm.getNativesForFlavor(df);
if (natives.equals(nativesNew)) {
System.err.println("orig=" + natives);
System.err.println("new=" + nativesNew);
throw new RuntimeException("Test failed");
}
List<DataFlavor> flavors = fm.getFlavorsForNative(nat);
flavors.add(extraDf);
java.util.List flavorsNew = fm.getFlavorsForNative(nat);
if (flavors.equals(flavorsNew)) {
System.err.println("orig=" + flavors);
System.err.println("new=" + flavorsNew);
throw new RuntimeException("Test failed");
}
}
/**
* Verifies that addUnencodedNativeForFlavor() for a particular text flavor
* doesn't affect mappings for other flavors.
*/
public static void test3() {
DataFlavor df1 = new DataFlavor("text/plain-test3", null);
DataFlavor df2 = new DataFlavor("text/plain-test3; charset=Unicode; class=java.io.Reader", null);
String nat = "native3";
List<String> natives = fm.getNativesForFlavor(df2);
fm.addUnencodedNativeForFlavor(df1, nat);
List<String> nativesNew = fm.getNativesForFlavor(df2);
if (!natives.equals(nativesNew)) {
System.err.println("orig=" + natives);
System.err.println("new=" + nativesNew);
throw new RuntimeException("Test failed");
}
}
/**
* Verifies that addUnencodedNativeForFlavor() really adds the specified
* flavor-to-native mapping to the existing mappings.
*/
public static void test4() {
DataFlavor df = new DataFlavor("text/plain-test4; charset=Unicode; class=java.io.Reader", null);
String nat = "native4";
List<String> natives = fm.getNativesForFlavor(df);
if (!natives.contains(nat)) {
fm.addUnencodedNativeForFlavor(df, nat);
List<String> nativesNew = fm.getNativesForFlavor(df);
natives.add(nat);
if (!natives.equals(nativesNew)) {
System.err.println("orig=" + natives);
System.err.println("new=" + nativesNew);
throw new RuntimeException("Test failed");
}
}
}
/**
* Verifies that a flavor doesn't have any flavor-to-native mappings after
* a call to setNativesForFlavor() with this flavor and an empty native
* array as arguments.
*/
public static void test5() {
final DataFlavor flavor =
new DataFlavor("text/plain-TEST5; charset=Unicode", null);
fm.getNativesForFlavor(flavor);
fm.setNativesForFlavor(flavor, new String[0]);
List<String> natives = fm.getNativesForFlavor(flavor);
if (!natives.isEmpty()) {
System.err.println("natives=" + natives);
throw new RuntimeException("Test failed");
}
}
/**
* Verifies that a native doesn't have any native-to-flavor mappings after
* a call to setFlavorsForNative() with this native and an empty flavor
* array as arguments.
*/
public static void test6() {
final String nat = "STRING";
fm.getFlavorsForNative(nat);
fm.setFlavorsForNative(nat, new DataFlavor[0]);
List<DataFlavor> flavors = fm.getFlavorsForNative(nat);
if (!flavors.isEmpty()) {
System.err.println("flavors=" + flavors);
throw new RuntimeException("Test failed");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册