--- old/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java 2014-04-18 16:31:38.000000000 +0400 +++ new/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java 2014-04-18 16:31:38.000000000 +0400 @@ -43,8 +43,8 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; -import java.util.WeakHashMap; import sun.awt.AppContext; import sun.awt.datatransfer.DataTransferer; @@ -102,19 +102,11 @@ 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> nativeToFlavor = new HashMap<>(); + private final Map> nativeToFlavor = new HashMap<>(); /** * Accessor to nativeToFlavor map. Since we use lazy initialization we must @@ -123,7 +115,7 @@ * * @return nativeToFlavor */ - private Map> getNativeToFlavor() { + private Map> getNativeToFlavor() { if (!isMapInitialized) { initSystemFlavorMap(); } @@ -135,7 +127,7 @@ * native Strings. * Do not use the field directly, use getFlavorToNative() instead. */ - private final Map> flavorToNative = new HashMap<>(); + private final Map> flavorToNative = new HashMap<>(); /** * Accessor to flavorToNative map. Since we use lazy initialization we must @@ -144,7 +136,7 @@ * * @return flavorToNative */ - private synchronized Map> getFlavorToNative() { + private synchronized Map> getFlavorToNative() { if (!isMapInitialized) { initSystemFlavorMap(); } @@ -152,21 +144,42 @@ } /** + * 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> 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> 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 Lists of String natives. + * SoftReferences which reference LinkedHashSet of String natives. */ - private Map>> getNativesForFlavorCache = new HashMap<>(); + private final SoftCache nativesForFlavorCache = new SoftCache<>(); /** * Caches the result getFlavorsForNative(). Maps String natives to - * SoftReferences which reference Lists of DataFlavors. + * SoftReferences which reference LinkedHashSet of DataFlavors. */ - private Map>> getFlavorsForNativeCache = new HashMap<>(); + private final SoftCache flavorsForNativeCache = new SoftCache<>(); /** * Dynamic mapping generation used for text mappings should not be applied @@ -174,7 +187,7 @@ * explicitly specified with setFlavorsForNative() or * setNativesForFlavor(). This keeps all such keys. */ - private Set disabledMappingGenerationKeys = new HashSet(); + private Set disabledMappingGenerationKeys = new HashSet<>(); /** * Returns the default FlavorMap for this thread's ClassLoader. @@ -404,7 +417,7 @@ flavor = new DataFlavor(value); } catch (Exception e) { try { - flavor = new DataFlavor(value, (String)null); + flavor = new DataFlavor(value, null); } catch (Exception ee) { ee.printStackTrace(); continue; @@ -412,11 +425,11 @@ } final LinkedHashSet 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) { @@ -505,10 +518,10 @@ * the appropriate Map location, but rather will be appended to a List * stored in that location. */ - private void store(H hashed, L listed, Map> map) { - List list = map.get(hashed); + private void store(H hashed, L listed, Map> map) { + LinkedHashSet list = map.get(hashed); if (list == null) { - list = new ArrayList<>(1); + list = new LinkedHashSet<>(1); map.put(hashed, list); } if (!list.contains(listed)) { @@ -522,17 +535,16 @@ * 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 nativeToFlavorLookup(String nat) { - List flavors = getNativeToFlavor().get(nat); + private LinkedHashSet nativeToFlavorLookup(String nat) { + LinkedHashSet flavors = getNativeToFlavor().get(nat); if (nat != null && !disabledMappingGenerationKeys.contains(nat)) { DataTransferer transferer = DataTransferer.getInstance(); if (transferer != null) { - List platformFlavors = + LinkedHashSet 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 @@ -558,24 +570,22 @@ } if (flavor != null) { - flavors = new ArrayList<>(1); + flavors = new LinkedHashSet<>(1); getNativeToFlavor().put(nat, flavors); flavors.add(flavor); - getFlavorsForNativeCache.remove(nat); - getFlavorsForNativeCache.remove(null); + flavorsForNativeCache.remove(nat); - List natives = getFlavorToNative().get(flavor); + LinkedHashSet natives = getFlavorToNative().get(flavor); if (natives == null) { - natives = new ArrayList<>(1); + natives = new LinkedHashSet<>(1); getFlavorToNative().put(flavor, natives); } natives.add(nat); - getNativesForFlavorCache.remove(flavor); - getNativesForFlavorCache.remove(null); + nativesForFlavorCache.remove(flavor); } } - return (flavors != null) ? flavors : new ArrayList<>(0); + return (flavors != null) ? flavors : new LinkedHashSet<>(0); } /** @@ -586,18 +596,18 @@ * encoding the DataFlavor's MIME type. Otherwise an empty List is returned * and 'flavorToNative' remains unaffected. */ - private List flavorToNativeLookup(final DataFlavor flav, - final boolean synthesize) { - List natives = getFlavorToNative().get(flav); + private LinkedHashSet flavorToNativeLookup(final DataFlavor flav, + final boolean synthesize) { + + LinkedHashSet natives = getFlavorToNative().get(flav); if (flav != null && !disabledMappingGenerationKeys.contains(flav)) { DataTransferer transferer = DataTransferer.getInstance(); if (transferer != null) { - List platformNatives = + LinkedHashSet 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 @@ -612,26 +622,25 @@ if (natives == null) { if (synthesize) { String encoded = encodeDataFlavor(flav); - natives = new ArrayList<>(1); + natives = new LinkedHashSet<>(1); getFlavorToNative().put(flav, natives); natives.add(encoded); - getNativesForFlavorCache.remove(flav); - getNativesForFlavorCache.remove(null); - List flavors = getNativeToFlavor().get(encoded); + LinkedHashSet flavors = getNativeToFlavor().get(encoded); if (flavors == null) { - flavors = new ArrayList<>(1); + flavors = new LinkedHashSet<>(1); getNativeToFlavor().put(encoded, flavors); } flavors.add(flav); - getFlavorsForNativeCache.remove(encoded); - getFlavorsForNativeCache.remove(null); + + nativesForFlavorCache.remove(flav); + flavorsForNativeCache.remove(encoded); } else { - natives = new ArrayList<>(0); + natives = new LinkedHashSet<>(0); } } - return natives; + return new LinkedHashSet<>(natives); } /** @@ -659,103 +668,63 @@ * @see #encodeDataFlavor * @since 1.4 */ + @Override public synchronized List getNativesForFlavor(DataFlavor flav) { - List retval = null; - - // Check cache, even for null flav - SoftReference> 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); - } + LinkedHashSet retval = nativesForFlavorCache.check(flav); + if (retval != null) { + return new ArrayList<>(retval); } if (flav == null) { - retval = new ArrayList<>(getNativeToFlavor().keySet()); + 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, !SYNTHESIZE_IF_NOT_FOUND); + 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())) { - retval = getAllNativesForType(flav.mimeType.getBaseType()); - if (retval != null) { - // To prevent the List stored in the map from modification. - retval = new ArrayList(retval); + LinkedHashSet textTypeNatives = + getTextTypeToNative().get(flav.mimeType.getBaseType()); + if (textTypeNatives != null) { + retval.addAll(textTypeNatives); } } // Also include text/plain natives, but don't duplicate Strings - List 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; - } + LinkedHashSet textTypeNatives = + getTextTypeToNative().get(TEXT_PLAIN_BASE_TYPE); + if (textTypeNatives != null) { + retval.addAll(textTypeNatives); } - if (retval == null || retval.isEmpty()) { - retval = flavorToNativeLookup(flav, SYNTHESIZE_IF_NOT_FOUND); + 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. - List 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); - } + retval.addAll(flavorToNativeLookup(flav, false)); } } else if (DataTransferer.isFlavorNoncharsetTextType(flav)) { - retval = getAllNativesForType(flav.mimeType.getBaseType()); + retval = getTextTypeToNative().get(flav.mimeType.getBaseType()); if (retval == null || retval.isEmpty()) { - retval = flavorToNativeLookup(flav, SYNTHESIZE_IF_NOT_FOUND); + 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. - List 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); - } + retval.addAll(flavorToNativeLookup(flav, false)); } } 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. return new ArrayList<>(retval); } @@ -791,62 +760,38 @@ * @see #encodeJavaMIMEType * @since 1.4 */ + @Override public synchronized List getFlavorsForNative(String nat) { - - // Check cache, even for null nat - SoftReference> ref = getFlavorsForNativeCache.get(nat); - if (ref != null) { - List retval = ref.get(); - if (retval != null) { - return new ArrayList<>(retval); - } + LinkedHashSet returnValue = flavorsForNativeCache.check(nat); + if (returnValue != null) { + return new ArrayList<>(returnValue); + } else { + returnValue = new LinkedHashSet<>(); } - final LinkedHashSet returnValue = - new LinkedHashSet<>(); - if (nat == null) { - final List natives = getNativesForFlavor(null); - - for (String n : natives) - { - final List flavors = getFlavorsForNative(n); - - for (DataFlavor df : flavors) - { - returnValue.add(df); - } + for (String n : getNativesForFlavor(null)) { + returnValue.addAll(getFlavorsForNative(n)); } } else { - - final List flavors = nativeToFlavorLookup(nat); - + final LinkedHashSet flavors = nativeToFlavorLookup(nat); if (disabledMappingGenerationKeys.contains(nat)) { - return flavors; + return new ArrayList<>(flavors); } - final List flavorsAndBaseTypes = - nativeToFlavorLookup(nat); + final LinkedHashSet flavorsWithSynthesized = + nativeToFlavorLookup(nat); - for (DataFlavor df : flavorsAndBaseTypes) { + for (DataFlavor df : flavorsWithSynthesized) { returnValue.add(df); if ("text".equals(df.getPrimaryType())) { - try { - returnValue.addAll( - convertMimeTypeToDataFlavors( - new MimeType(df.getMimeType() - ).getBaseType())); - } catch (MimeTypeParseException e) { - e.printStackTrace(); - } + String baseType = df.mimeType.getBaseType(); + returnValue.addAll(convertMimeTypeToDataFlavors(baseType)); } } - } - - final List arrayList = new ArrayList<>(returnValue); - getFlavorsForNativeCache.put(nat, new SoftReference<>(arrayList)); - return new ArrayList<>(arrayList); + flavorsForNativeCache.put(nat, returnValue); + return new ArrayList<>(returnValue); } private static Set convertMimeTypeToDataFlavors( @@ -862,7 +807,6 @@ } catch (MimeTypeParseException mtpe) { // Cannot happen, since we checked all mappings // on load from flavormap.properties. - assert(false); } if (DataTransferer.doesSubtypeSupportCharset(subType, null)) { @@ -940,11 +884,12 @@ return returnValue; } - private static final String [] htmlDocumntTypes = - new String [] {"all", "selection", "fragment"}; + private static final String [] htmlDocumntTypes = new String [] {"all", + "selection", + "fragment"}; - private static LinkedHashSet handleHtmlMimeTypes( - String baseType, String mimeType) { + private static LinkedHashSet handleHtmlMimeTypes(String baseType, + String mimeType) { LinkedHashSet returnValues = new LinkedHashSet<>(); @@ -981,14 +926,14 @@ * @see #getNativesForFlavor * @see #encodeDataFlavor */ - public synchronized Map - getNativesForFlavors(DataFlavor[] flavors) + @Override + public synchronized Map getNativesForFlavors(DataFlavor[] flavors) { // Use getNativesForFlavor to generate extra natives for text flavors // and stringFlavor if (flavors == null) { - List flavor_list = getFlavorsForNative(null); + List flavor_list = getFlavorsForNative(null); flavors = new DataFlavor[flavor_list.size()]; flavor_list.toArray(flavors); } @@ -1027,15 +972,14 @@ * @see #getFlavorsForNative * @see #encodeJavaMIMEType */ - public synchronized Map - getFlavorsForNatives(String[] natives) + @Override + public synchronized Map 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); + List nativesList = getNativesForFlavor(null); + natives = new String[nativesList.size()]; + nativesList.toArray(natives); } Map retval = new HashMap<>(natives.length, 1.0f); @@ -1044,7 +988,6 @@ DataFlavor flav = (flavors.isEmpty())? null : flavors.get(0); retval.put(aNative, flav); } - return retval; } @@ -1070,20 +1013,16 @@ */ public synchronized void addUnencodedNativeForFlavor(DataFlavor flav, String nat) { - if (flav == null || nat == null) { - throw new NullPointerException("null arguments not permitted"); - } + Objects.requireNonNull(nat, "Null native not permitted"); + Objects.requireNonNull(flav, "Null flavor not permitted"); - List natives = getFlavorToNative().get(flav); + LinkedHashSet natives = getFlavorToNative().get(flav); if (natives == null) { - natives = new ArrayList<>(1); + natives = new LinkedHashSet<>(1); getFlavorToNative().put(flav, natives); - } else if (natives.contains(nat)) { - return; } natives.add(nat); - getNativesForFlavorCache.remove(flav); - getNativesForFlavorCache.remove(null); + nativesForFlavorCache.remove(flav); } /** @@ -1116,18 +1055,15 @@ */ public synchronized void setNativesForFlavor(DataFlavor flav, String[] natives) { - if (flav == null || natives == null) { - throw new NullPointerException("null arguments not permitted"); - } + 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); - // Clear the cache to handle the case of empty natives. - getNativesForFlavorCache.remove(flav); - getNativesForFlavorCache.remove(null); + nativesForFlavorCache.remove(flav); } /** @@ -1150,20 +1086,16 @@ */ public synchronized void addFlavorForUnencodedNative(String nat, DataFlavor flav) { - if (nat == null || flav == null) { - throw new NullPointerException("null arguments not permitted"); - } + Objects.requireNonNull(nat, "Null native not permitted"); + Objects.requireNonNull(flav, "Null flavor not permitted"); - List flavors = getNativeToFlavor().get(nat); + LinkedHashSet flavors = getNativeToFlavor().get(nat); if (flavors == null) { - flavors = new ArrayList<>(1); + flavors = new LinkedHashSet<>(1); getNativeToFlavor().put(nat, flavors); - } else if (flavors.contains(flav)) { - return; } flavors.add(flav); - getFlavorsForNativeCache.remove(nat); - getFlavorsForNativeCache.remove(null); + flavorsForNativeCache.remove(nat); } /** @@ -1195,18 +1127,15 @@ */ public synchronized void setFlavorsForNative(String nat, DataFlavor[] flavors) { - if (nat == null || flavors == null) { - throw new NullPointerException("null arguments not permitted"); - } + 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); - // Clear the cache to handle the case of empty flavors. - getFlavorsForNativeCache.remove(nat); - getFlavorsForNativeCache.remove(null); + flavorsForNativeCache.remove(nat); } /** @@ -1307,17 +1236,29 @@ : null; } - private List getAllNativesForType(String type) { - Set retval = null; - for (DataFlavor dataFlavor : convertMimeTypeToDataFlavors(type)) { - List natives = getFlavorToNative().get(dataFlavor); - if (natives != null && !natives.isEmpty()) { - if (retval == null) { - retval = new LinkedHashSet<>(); - } - retval.addAll(natives); + private static final class SoftCache { + Map>> cache; + + public void put(K key, LinkedHashSet 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 check(K key) { + if (cache == null) return null; + SoftReference> ref = cache.get(key); + if (ref != null) { + return ref.get(); } + return null; } - return retval == null ? null : new ArrayList<>(retval); } } --- old/src/share/classes/sun/awt/datatransfer/DataTransferer.java 2014-04-18 16:31:40.000000000 +0400 +++ new/src/share/classes/sun/awt/datatransfer/DataTransferer.java 2014-04-18 16:31:39.000000000 +0400 @@ -70,22 +70,7 @@ import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.SortedMap; -import java.util.SortedSet; -import java.util.Set; -import java.util.Stack; -import java.util.TreeMap; -import java.util.TreeSet; +import java.util.*; import sun.util.logging.PlatformLogger; @@ -2267,8 +2252,8 @@ * If there are no platform-specific mappings for this native, the method * returns an empty List. */ - public List getPlatformMappingsForNative(String nat) { - return new ArrayList<>(); + public LinkedHashSet getPlatformMappingsForNative(String nat) { + return new LinkedHashSet<>(); } /** @@ -2276,8 +2261,8 @@ * If there are no platform-specific mappings for this flavor, the method * returns an empty List. */ - public List getPlatformMappingsForFlavor(DataFlavor df) { - return new ArrayList<>(); + public LinkedHashSet getPlatformMappingsForFlavor(DataFlavor df) { + return new LinkedHashSet<>(); } /** --- old/src/solaris/classes/sun/awt/X11/XDataTransferer.java 2014-04-18 16:31:41.000000000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XDataTransferer.java 2014-04-18 16:31:41.000000000 +0400 @@ -45,6 +45,7 @@ import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import javax.imageio.ImageIO; @@ -330,8 +331,8 @@ * type can be translated by the Data Transfer subsystem. */ @Override - public List getPlatformMappingsForNative(String nat) { - List flavors = new ArrayList<>(); + public LinkedHashSet getPlatformMappingsForNative(String nat) { + LinkedHashSet flavors = new LinkedHashSet<>(); if (nat == null) { return flavors; @@ -392,8 +393,8 @@ * Transfer subsystem. */ @Override - public List getPlatformMappingsForFlavor(DataFlavor df) { - List natives = new ArrayList<>(1); + public LinkedHashSet getPlatformMappingsForFlavor(DataFlavor df) { + LinkedHashSet natives = new LinkedHashSet<>(1); if (df == null) { return natives; --- /dev/null 2014-04-18 16:31:42.000000000 +0400 +++ new/test/java/awt/datatransfer/MappingGenerationTest/MappingGenerationTest.java 2014-04-18 16:31:42.000000000 +0400 @@ -0,0 +1,183 @@ +/* + * 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 natives = fm.getNativesForFlavor(df); + fm.addUnencodedNativeForFlavor(df, nat); + 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 flavors = fm.getFlavorsForNative(nat); + fm.addFlavorForUnencodedNative(nat, df); + 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 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 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 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 natives = fm.getNativesForFlavor(df2); + fm.addUnencodedNativeForFlavor(df1, nat); + List 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 natives = fm.getNativesForFlavor(df); + if (!natives.contains(nat)) { + fm.addUnencodedNativeForFlavor(df, nat); + List 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 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 flavors = fm.getFlavorsForNative(nat); + + if (!flavors.isEmpty()) { + System.err.println("flavors=" + flavors); + throw new RuntimeException("Test failed"); + } + } +} \ No newline at end of file