Source Code Cross Referenced for SystemFlavorMap.java in  » 6.0-JDK-Core » AWT » java » awt » datatransfer » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » AWT » java.awt.datatransfer 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025
0026        package java.awt.datatransfer;
0027
0028        import java.awt.Toolkit;
0029
0030        import java.lang.ref.SoftReference;
0031
0032        import java.io.BufferedReader;
0033        import java.io.File;
0034        import java.io.InputStreamReader;
0035        import java.io.IOException;
0036
0037        import java.net.URL;
0038        import java.net.MalformedURLException;
0039
0040        import java.util.ArrayList;
0041        import java.util.HashMap;
0042        import java.util.HashSet;
0043        import java.util.Iterator;
0044        import java.util.LinkedList;
0045        import java.util.List;
0046        import java.util.Map;
0047        import java.util.Set;
0048        import java.util.WeakHashMap;
0049
0050        import sun.awt.datatransfer.DataTransferer;
0051
0052        /**
0053         * The SystemFlavorMap is a configurable map between "natives" (Strings), which
0054         * correspond to platform-specific data formats, and "flavors" (DataFlavors),
0055         * which correspond to platform-independent MIME types. This mapping is used
0056         * by the data transfer subsystem to transfer data between Java and native
0057         * applications, and between Java applications in separate VMs.
0058         * <p>
0059         * In the Sun reference implementation, the default SystemFlavorMap is
0060         * initialized by the file <code>jre/lib/flavormap.properties</code> and the
0061         * contents of the URL referenced by the AWT property
0062         * <code>AWT.DnD.flavorMapFileURL</code>. See <code>flavormap.properties</code>
0063         * for details.
0064         *
0065         * @version 1.44, 05/05/07
0066         * @since 1.2
0067         */
0068        public final class SystemFlavorMap implements  FlavorMap, FlavorTable {
0069
0070            /**
0071             * Constant prefix used to tag Java types converted to native platform
0072             * type.
0073             */
0074            private static String JavaMIME = "JAVA_DATAFLAVOR:";
0075
0076            /**
0077             * System singleton which maps a thread's ClassLoader to a SystemFlavorMap.
0078             */
0079            private static final WeakHashMap flavorMaps = new WeakHashMap();
0080
0081            /**
0082             * Copied from java.util.Properties.
0083             */
0084            private static final String keyValueSeparators = "=: \t\r\n\f";
0085            private static final String strictKeyValueSeparators = "=:";
0086            private static final String whiteSpaceChars = " \t\r\n\f";
0087
0088            /**
0089             * The list of valid, decoded text flavor representation classes, in order
0090             * from best to worst.
0091             */
0092            private static final String[] UNICODE_TEXT_CLASSES = {
0093                    "java.io.Reader", "java.lang.String",
0094                    "java.nio.CharBuffer", "\"[C\"" };
0095
0096            /**
0097             * The list of valid, encoded text flavor representation classes, in order
0098             * from best to worst.
0099             */
0100            private static final String[] ENCODED_TEXT_CLASSES = {
0101                    "java.io.InputStream", "java.nio.ByteBuffer", "\"[B\"" };
0102
0103            /**
0104             * A String representing text/plain MIME type.
0105             */
0106            private static final String TEXT_PLAIN_BASE_TYPE = "text/plain";
0107
0108            /**
0109             * This constant is passed to flavorToNativeLookup() to indicate that a
0110             * a native should be synthesized, stored, and returned by encoding the
0111             * DataFlavor's MIME type in case if the DataFlavor is not found in
0112             * 'flavorToNative' map.
0113             */
0114            private static final boolean SYNTHESIZE_IF_NOT_FOUND = true;
0115
0116            /**
0117             * Maps native Strings to Lists of DataFlavors (or base type Strings for
0118             * text DataFlavors).
0119             */
0120            private Map nativeToFlavor = new HashMap();
0121
0122            /**
0123             * Maps DataFlavors (or base type Strings for text DataFlavors) to Lists of
0124             * native Strings.
0125             */
0126            private Map flavorToNative = new HashMap();
0127
0128            /**
0129             * Caches the result of getNativesForFlavor(). Maps DataFlavors to
0130             * SoftReferences which reference Lists of String natives.
0131             */
0132            private Map getNativesForFlavorCache = new HashMap();
0133
0134            /**
0135             * Caches the result getFlavorsForNative(). Maps String natives to
0136             * SoftReferences which reference Lists of DataFlavors.
0137             */
0138            private Map getFlavorsForNativeCache = new HashMap();
0139
0140            /**
0141             * Dynamic mapping generation used for text mappings should not be applied
0142             * to the DataFlavors and String natives for which the mappings have been
0143             * explicitly specified with setFlavorsForNative() or
0144             * setNativesForFlavor(). This keeps all such keys.
0145             */
0146            private Set disabledMappingGenerationKeys = new HashSet();
0147
0148            /**
0149             * Returns the default FlavorMap for this thread's ClassLoader.
0150             */
0151            public static FlavorMap getDefaultFlavorMap() {
0152                ClassLoader contextClassLoader = Thread.currentThread()
0153                        .getContextClassLoader();
0154                if (contextClassLoader == null) {
0155                    contextClassLoader = ClassLoader.getSystemClassLoader();
0156                }
0157
0158                FlavorMap fm;
0159
0160                synchronized (flavorMaps) {
0161                    fm = (FlavorMap) flavorMaps.get(contextClassLoader);
0162                    if (fm == null) {
0163                        fm = new SystemFlavorMap();
0164                        flavorMaps.put(contextClassLoader, fm);
0165                    }
0166                }
0167
0168                return fm;
0169            }
0170
0171            /**
0172             * Constructs a SystemFlavorMap by reading flavormap.properties and
0173             * AWT.DnD.flavorMapFileURL.
0174             */
0175            private SystemFlavorMap() {
0176                BufferedReader flavormapDotProperties = (BufferedReader) java.security.AccessController
0177                        .doPrivileged(new java.security.PrivilegedAction() {
0178                            public Object run() {
0179                                String fileName = System
0180                                        .getProperty("java.home")
0181                                        + File.separator
0182                                        + "lib"
0183                                        + File.separator
0184                                        + "flavormap.properties";
0185                                try {
0186                                    return new BufferedReader(
0187                                            new InputStreamReader(new File(
0188                                                    fileName).toURI().toURL()
0189                                                    .openStream(), "ISO-8859-1"));
0190                                } catch (MalformedURLException e) {
0191                                    System.err
0192                                            .println("MalformedURLException:"
0193                                                    + e
0194                                                    + " while loading default flavormap.properties file:"
0195                                                    + fileName);
0196                                } catch (IOException e) {
0197                                    System.err
0198                                            .println("IOException:"
0199                                                    + e
0200                                                    + " while loading default flavormap.properties file:"
0201                                                    + fileName);
0202                                }
0203                                return null;
0204                            }
0205                        });
0206
0207                BufferedReader flavormapURL = (BufferedReader) java.security.AccessController
0208                        .doPrivileged(new java.security.PrivilegedAction() {
0209                            public Object run() {
0210                                String url = Toolkit.getDefaultToolkit()
0211                                        .getProperty(
0212                                                "AWT.DnD.flavorMapFileURL",
0213                                                null);
0214
0215                                if (url == null) {
0216                                    return null;
0217                                }
0218
0219                                try {
0220                                    return new BufferedReader(
0221                                            new InputStreamReader(new URL(url)
0222                                                    .openStream(), "ISO-8859-1"));
0223                                } catch (MalformedURLException e) {
0224                                    System.err
0225                                            .println("MalformedURLException:"
0226                                                    + e
0227                                                    + " while reading AWT.DnD.flavorMapFileURL:"
0228                                                    + url);
0229                                } catch (IOException e) {
0230                                    System.err
0231                                            .println("IOException:"
0232                                                    + e
0233                                                    + " while reading AWT.DnD.flavorMapFileURL:"
0234                                                    + url);
0235                                }
0236                                return null;
0237                            }
0238                        });
0239
0240                if (flavormapDotProperties != null) {
0241                    try {
0242                        parseAndStoreReader(flavormapDotProperties);
0243                    } catch (IOException e) {
0244                        System.err
0245                                .println("IOException:"
0246                                        + e
0247                                        + " while parsing default flavormap.properties file");
0248                    }
0249                }
0250
0251                if (flavormapURL != null) {
0252                    try {
0253                        parseAndStoreReader(flavormapURL);
0254                    } catch (IOException e) {
0255                        System.err.println("IOException:" + e
0256                                + " while parsing AWT.DnD.flavorMapFileURL");
0257                    }
0258                }
0259            }
0260
0261            /**
0262             * Copied code from java.util.Properties. Parsing the data ourselves is the
0263             * only way to handle duplicate keys and values.
0264             */
0265            private void parseAndStoreReader(BufferedReader in)
0266                    throws IOException {
0267                while (true) {
0268                    // Get next line
0269                    String line = in.readLine();
0270                    if (line == null) {
0271                        return;
0272                    }
0273
0274                    if (line.length() > 0) {
0275                        // Continue lines that end in slashes if they are not comments
0276                        char firstChar = line.charAt(0);
0277                        if (firstChar != '#' && firstChar != '!') {
0278                            while (continueLine(line)) {
0279                                String nextLine = in.readLine();
0280                                if (nextLine == null) {
0281                                    nextLine = new String("");
0282                                }
0283                                String loppedLine = line.substring(0, line
0284                                        .length() - 1);
0285                                // Advance beyond whitespace on new line
0286                                int startIndex = 0;
0287                                for (; startIndex < nextLine.length(); startIndex++) {
0288                                    if (whiteSpaceChars.indexOf(nextLine
0289                                            .charAt(startIndex)) == -1) {
0290                                        break;
0291                                    }
0292                                }
0293                                nextLine = nextLine.substring(startIndex,
0294                                        nextLine.length());
0295                                line = new String(loppedLine + nextLine);
0296                            }
0297
0298                            // Find start of key
0299                            int len = line.length();
0300                            int keyStart = 0;
0301                            for (; keyStart < len; keyStart++) {
0302                                if (whiteSpaceChars.indexOf(line
0303                                        .charAt(keyStart)) == -1) {
0304                                    break;
0305                                }
0306                            }
0307
0308                            // Blank lines are ignored
0309                            if (keyStart == len) {
0310                                continue;
0311                            }
0312
0313                            // Find separation between key and value
0314                            int separatorIndex = keyStart;
0315                            for (; separatorIndex < len; separatorIndex++) {
0316                                char currentChar = line.charAt(separatorIndex);
0317                                if (currentChar == '\\') {
0318                                    separatorIndex++;
0319                                } else if (keyValueSeparators
0320                                        .indexOf(currentChar) != -1) {
0321                                    break;
0322                                }
0323                            }
0324
0325                            // Skip over whitespace after key if any
0326                            int valueIndex = separatorIndex;
0327                            for (; valueIndex < len; valueIndex++) {
0328                                if (whiteSpaceChars.indexOf(line
0329                                        .charAt(valueIndex)) == -1) {
0330                                    break;
0331                                }
0332                            }
0333
0334                            // Skip over one non whitespace key value separators if any
0335                            if (valueIndex < len) {
0336                                if (strictKeyValueSeparators.indexOf(line
0337                                        .charAt(valueIndex)) != -1) {
0338                                    valueIndex++;
0339                                }
0340                            }
0341
0342                            // Skip over white space after other separators if any
0343                            while (valueIndex < len) {
0344                                if (whiteSpaceChars.indexOf(line
0345                                        .charAt(valueIndex)) == -1) {
0346                                    break;
0347                                }
0348                                valueIndex++;
0349                            }
0350
0351                            String key = line.substring(keyStart,
0352                                    separatorIndex);
0353                            String value = (separatorIndex < len) ? line
0354                                    .substring(valueIndex, len) : "";
0355
0356                            // Convert then store key and value
0357                            key = loadConvert(key);
0358                            value = loadConvert(value);
0359
0360                            try {
0361                                MimeType mime = new MimeType(value);
0362                                if ("text".equals(mime.getPrimaryType())) {
0363                                    String charset = mime
0364                                            .getParameter("charset");
0365                                    if (DataTransferer
0366                                            .doesSubtypeSupportCharset(mime
0367                                                    .getSubType(), charset)) {
0368                                        // We need to store the charset and eoln
0369                                        // parameters, if any, so that the
0370                                        // DataTransferer will have this information
0371                                        // for conversion into the native format.
0372                                        DataTransferer transferer = DataTransferer
0373                                                .getInstance();
0374                                        if (transferer != null) {
0375                                            transferer
0376                                                    .registerTextFlavorProperties(
0377                                                            key,
0378                                                            charset,
0379                                                            mime
0380                                                                    .getParameter("eoln"),
0381                                                            mime
0382                                                                    .getParameter("terminators"));
0383                                        }
0384                                    }
0385
0386                                    // But don't store any of these parameters in the
0387                                    // DataFlavor itself for any text natives (even
0388                                    // non-charset ones). The SystemFlavorMap will
0389                                    // synthesize the appropriate mappings later.
0390                                    mime.removeParameter("charset");
0391                                    mime.removeParameter("class");
0392                                    mime.removeParameter("eoln");
0393                                    mime.removeParameter("terminators");
0394                                    value = mime.toString();
0395                                }
0396                            } catch (MimeTypeParseException e) {
0397                                e.printStackTrace();
0398                                continue;
0399                            }
0400
0401                            DataFlavor flavor;
0402                            try {
0403                                flavor = new DataFlavor(value);
0404                            } catch (Exception e) {
0405                                try {
0406                                    flavor = new DataFlavor(value,
0407                                            (String) null);
0408                                } catch (Exception ee) {
0409                                    ee.printStackTrace();
0410                                    continue;
0411                                }
0412                            }
0413
0414                            // For text/* flavors, store mappings in separate maps to
0415                            // enable dynamic mapping generation at a run-time.
0416                            if ("text".equals(flavor.getPrimaryType())) {
0417                                store(value, key, flavorToNative);
0418                                store(key, value, nativeToFlavor);
0419                            } else {
0420                                store(flavor, key, flavorToNative);
0421                                store(key, flavor, nativeToFlavor);
0422                            }
0423                        }
0424                    }
0425                }
0426            }
0427
0428            /**
0429             * Copied from java.util.Properties.
0430             */
0431            private boolean continueLine(String line) {
0432                int slashCount = 0;
0433                int index = line.length() - 1;
0434                while ((index >= 0) && (line.charAt(index--) == '\\')) {
0435                    slashCount++;
0436                }
0437                return (slashCount % 2 == 1);
0438            }
0439
0440            /**
0441             * Copied from java.util.Properties.
0442             */
0443            private String loadConvert(String theString) {
0444                char aChar;
0445                int len = theString.length();
0446                StringBuilder outBuffer = new StringBuilder(len);
0447
0448                for (int x = 0; x < len;) {
0449                    aChar = theString.charAt(x++);
0450                    if (aChar == '\\') {
0451                        aChar = theString.charAt(x++);
0452                        if (aChar == 'u') {
0453                            // Read the xxxx
0454                            int value = 0;
0455                            for (int i = 0; i < 4; i++) {
0456                                aChar = theString.charAt(x++);
0457                                switch (aChar) {
0458                                case '0':
0459                                case '1':
0460                                case '2':
0461                                case '3':
0462                                case '4':
0463                                case '5':
0464                                case '6':
0465                                case '7':
0466                                case '8':
0467                                case '9': {
0468                                    value = (value << 4) + aChar - '0';
0469                                    break;
0470                                }
0471                                case 'a':
0472                                case 'b':
0473                                case 'c':
0474                                case 'd':
0475                                case 'e':
0476                                case 'f': {
0477                                    value = (value << 4) + 10 + aChar - 'a';
0478                                    break;
0479                                }
0480                                case 'A':
0481                                case 'B':
0482                                case 'C':
0483                                case 'D':
0484                                case 'E':
0485                                case 'F': {
0486                                    value = (value << 4) + 10 + aChar - 'A';
0487                                    break;
0488                                }
0489                                default: {
0490                                    throw new IllegalArgumentException(
0491                                            "Malformed \\uxxxx encoding.");
0492                                }
0493                                }
0494                            }
0495                            outBuffer.append((char) value);
0496                        } else {
0497                            if (aChar == 't') {
0498                                aChar = '\t';
0499                            } else if (aChar == 'r') {
0500                                aChar = '\r';
0501                            } else if (aChar == 'n') {
0502                                aChar = '\n';
0503                            } else if (aChar == 'f') {
0504                                aChar = '\f';
0505                            }
0506                            outBuffer.append(aChar);
0507                        }
0508                    } else {
0509                        outBuffer.append(aChar);
0510                    }
0511                }
0512                return outBuffer.toString();
0513            }
0514
0515            /**
0516             * Stores the listed object under the specified hash key in map. Unlike a
0517             * standard map, the listed object will not replace any object already at
0518             * the appropriate Map location, but rather will be appended to a List
0519             * stored in that location.
0520             */
0521            private void store(Object hashed, Object listed, Map map) {
0522                List list = (List) map.get(hashed);
0523                if (list == null) {
0524                    list = new ArrayList(1);
0525                    map.put(hashed, list);
0526                }
0527                if (!list.contains(listed)) {
0528                    list.add(listed);
0529                }
0530            }
0531
0532            /**
0533             * Semantically equivalent to 'nativeToFlavor.get(nat)'. This method
0534             * handles the case where 'nat' is not found in 'nativeToFlavor'. In that
0535             * case, a new DataFlavor is synthesized, stored, and returned, if and
0536             * only if the specified native is encoded as a Java MIME type.
0537             */
0538            private List nativeToFlavorLookup(String nat) {
0539                List flavors = (List) nativeToFlavor.get(nat);
0540
0541                if (nat != null && !disabledMappingGenerationKeys.contains(nat)) {
0542                    DataTransferer transferer = DataTransferer.getInstance();
0543                    if (transferer != null) {
0544                        List platformFlavors = transferer
0545                                .getPlatformMappingsForNative(nat);
0546                        if (!platformFlavors.isEmpty()) {
0547                            if (flavors != null) {
0548                                platformFlavors.removeAll(new HashSet(flavors));
0549                                // Prepending the platform-specific mappings ensures
0550                                // that the flavors added with
0551                                // addFlavorForUnencodedNative() are at the end of
0552                                // list.
0553                                platformFlavors.addAll(flavors);
0554                            }
0555                            flavors = platformFlavors;
0556                        }
0557                    }
0558                }
0559
0560                if (flavors == null && isJavaMIMEType(nat)) {
0561                    String decoded = decodeJavaMIMEType(nat);
0562                    DataFlavor flavor = null;
0563
0564                    try {
0565                        flavor = new DataFlavor(decoded);
0566                    } catch (Exception e) {
0567                        System.err.println("Exception \""
0568                                + e.getClass().getName() + ": "
0569                                + e.getMessage()
0570                                + "\"while constructing DataFlavor for: "
0571                                + decoded);
0572                    }
0573
0574                    if (flavor != null) {
0575                        flavors = new ArrayList(1);
0576                        nativeToFlavor.put(nat, flavors);
0577                        flavors.add(flavor);
0578                        getFlavorsForNativeCache.remove(nat);
0579                        getFlavorsForNativeCache.remove(null);
0580
0581                        List natives = (List) flavorToNative.get(flavor);
0582                        if (natives == null) {
0583                            natives = new ArrayList(1);
0584                            flavorToNative.put(flavor, natives);
0585                        }
0586                        natives.add(nat);
0587                        getNativesForFlavorCache.remove(flavor);
0588                        getNativesForFlavorCache.remove(null);
0589                    }
0590                }
0591
0592                return (flavors != null) ? flavors : new ArrayList(0);
0593            }
0594
0595            /**
0596             * Semantically equivalent to 'flavorToNative.get(flav)'. This method
0597             * handles the case where 'flav' is not found in 'flavorToNative' depending
0598             * on the value of passes 'synthesize' parameter. If 'synthesize' is
0599             * SYNTHESIZE_IF_NOT_FOUND a native is synthesized, stored, and returned by
0600             * encoding the DataFlavor's MIME type. Otherwise an empty List is returned
0601             * and 'flavorToNative' remains unaffected.
0602             */
0603            private List flavorToNativeLookup(final DataFlavor flav,
0604                    final boolean synthesize) {
0605                List natives = (List) flavorToNative.get(flav);
0606
0607                if (flav != null
0608                        && !disabledMappingGenerationKeys.contains(flav)) {
0609                    DataTransferer transferer = DataTransferer.getInstance();
0610                    if (transferer != null) {
0611                        List platformNatives = transferer
0612                                .getPlatformMappingsForFlavor(flav);
0613                        if (!platformNatives.isEmpty()) {
0614                            if (natives != null) {
0615                                platformNatives.removeAll(new HashSet(natives));
0616                                // Prepend the platform-specific mappings to ensure
0617                                // that the natives added with
0618                                // addUnencodedNativeForFlavor() are at the end of
0619                                // list. 
0620                                platformNatives.addAll(natives);
0621                            }
0622                            natives = platformNatives;
0623                        }
0624                    }
0625                }
0626
0627                if (natives == null) {
0628                    if (synthesize) {
0629                        String encoded = encodeDataFlavor(flav);
0630                        natives = new ArrayList(1);
0631                        flavorToNative.put(flav, natives);
0632                        natives.add(encoded);
0633                        getNativesForFlavorCache.remove(flav);
0634                        getNativesForFlavorCache.remove(null);
0635
0636                        List flavors = (List) nativeToFlavor.get(encoded);
0637                        if (flavors == null) {
0638                            flavors = new ArrayList(1);
0639                            nativeToFlavor.put(encoded, flavors);
0640                        }
0641                        flavors.add(flav);
0642                        getFlavorsForNativeCache.remove(encoded);
0643                        getFlavorsForNativeCache.remove(null);
0644                    } else {
0645                        natives = new ArrayList(0);
0646                    }
0647                }
0648
0649                return natives;
0650            }
0651
0652            /**
0653             * Returns a <code>List</code> of <code>String</code> natives to which the
0654             * specified <code>DataFlavor</code> can be translated by the data transfer
0655             * subsystem. The <code>List</code> will be sorted from best native to
0656             * worst. That is, the first native will best reflect data in the specified
0657             * flavor to the underlying native platform.
0658             * <p>
0659             * If the specified <code>DataFlavor</code> is previously unknown to the
0660             * data transfer subsystem and the data transfer subsystem is unable to
0661             * translate this <code>DataFlavor</code> to any existing native, then
0662             * invoking this method will establish a 
0663             * mapping in both directions between the specified <code>DataFlavor</code>
0664             * and an encoded version of its MIME type as its native.
0665             *
0666             * @param flav the <code>DataFlavor</code> whose corresponding natives
0667             *        should be returned. If <code>null</code> is specified, all
0668             *        natives currently known to the data transfer subsystem are
0669             *        returned in a non-deterministic order.
0670             * @return a <code>java.util.List</code> of <code>java.lang.String</code>
0671             *         objects which are platform-specific representations of platform-
0672             *         specific data formats
0673             *
0674             * @see #encodeDataFlavor
0675             * @since 1.4
0676             */
0677            public synchronized List<String> getNativesForFlavor(DataFlavor flav) {
0678                List retval = null;
0679
0680                // Check cache, even for null flav
0681                SoftReference ref = (SoftReference) getNativesForFlavorCache
0682                        .get(flav);
0683                if (ref != null) {
0684                    retval = (List) ref.get();
0685                    if (retval != null) {
0686                        // Create a copy, because client code can modify the returned
0687                        // list.
0688                        return new ArrayList(retval);
0689                    }
0690                }
0691
0692                if (flav == null) {
0693                    retval = new ArrayList(nativeToFlavor.keySet());
0694                } else if (disabledMappingGenerationKeys.contains(flav)) {
0695                    // In this case we shouldn't synthesize a native for this flavor,
0696                    // since its mappings were explicitly specified.
0697                    retval = flavorToNativeLookup(flav,
0698                            !SYNTHESIZE_IF_NOT_FOUND);
0699                } else if (DataTransferer.isFlavorCharsetTextType(flav)) {
0700
0701                    // For text/* flavors, flavor-to-native mappings specified in 
0702                    // flavormap.properties are stored per flavor's base type.
0703                    if ("text".equals(flav.getPrimaryType())) {
0704                        retval = (List) flavorToNative.get(flav.mimeType
0705                                .getBaseType());
0706                        if (retval != null) {
0707                            // To prevent the List stored in the map from modification.
0708                            retval = new ArrayList(retval);
0709                        }
0710                    }
0711
0712                    // Also include text/plain natives, but don't duplicate Strings
0713                    List textPlainList = (List) flavorToNative
0714                            .get(TEXT_PLAIN_BASE_TYPE);
0715
0716                    if (textPlainList != null && !textPlainList.isEmpty()) {
0717                        // To prevent the List stored in the map from modification.
0718                        // This also guarantees that removeAll() is supported.
0719                        textPlainList = new ArrayList(textPlainList);
0720                        if (retval != null && !retval.isEmpty()) {
0721                            // Use HashSet to get constant-time performance for search.
0722                            textPlainList.removeAll(new HashSet(retval));
0723                            retval.addAll(textPlainList);
0724                        } else {
0725                            retval = textPlainList;
0726                        }
0727                    }
0728
0729                    if (retval == null || retval.isEmpty()) {
0730                        retval = flavorToNativeLookup(flav,
0731                                SYNTHESIZE_IF_NOT_FOUND);
0732                    } else {
0733                        // In this branch it is guaranteed that natives explicitly
0734                        // listed for flav's MIME type were added with
0735                        // addUnencodedNativeForFlavor(), so they have lower priority.
0736                        List explicitList = flavorToNativeLookup(flav,
0737                                !SYNTHESIZE_IF_NOT_FOUND);
0738
0739                        // flavorToNativeLookup() never returns null.
0740                        // It can return an empty List, however.
0741                        if (!explicitList.isEmpty()) {
0742                            // To prevent the List stored in the map from modification.
0743                            // This also guarantees that removeAll() is supported.
0744                            explicitList = new ArrayList(explicitList);
0745                            // Use HashSet to get constant-time performance for search.
0746                            explicitList.removeAll(new HashSet(retval));
0747                            retval.addAll(explicitList);
0748                        }
0749                    }
0750                } else if (DataTransferer.isFlavorNoncharsetTextType(flav)) {
0751                    retval = (List) flavorToNative.get(flav.mimeType
0752                            .getBaseType());
0753
0754                    if (retval == null || retval.isEmpty()) {
0755                        retval = flavorToNativeLookup(flav,
0756                                SYNTHESIZE_IF_NOT_FOUND);
0757                    } else {
0758                        // In this branch it is guaranteed that natives explicitly
0759                        // listed for flav's MIME type were added with
0760                        // addUnencodedNativeForFlavor(), so they have lower priority.
0761                        List explicitList = flavorToNativeLookup(flav,
0762                                !SYNTHESIZE_IF_NOT_FOUND);
0763
0764                        // flavorToNativeLookup() never returns null.
0765                        // It can return an empty List, however.
0766                        if (!explicitList.isEmpty()) {
0767                            // To prevent the List stored in the map from modification.
0768                            // This also guarantees that add/removeAll() are supported.
0769                            retval = new ArrayList(retval);
0770                            explicitList = new ArrayList(explicitList);
0771                            // Use HashSet to get constant-time performance for search.
0772                            explicitList.removeAll(new HashSet(retval));
0773                            retval.addAll(explicitList);
0774                        }
0775                    }
0776                } else {
0777                    retval = flavorToNativeLookup(flav, SYNTHESIZE_IF_NOT_FOUND);
0778                }
0779
0780                getNativesForFlavorCache.put(flav, new SoftReference(retval));
0781                // Create a copy, because client code can modify the returned list.
0782                return new ArrayList(retval);
0783            }
0784
0785            /**
0786             * Returns a <code>List</code> of <code>DataFlavor</code>s to which the
0787             * specified <code>String</code> native can be translated by the data
0788             * transfer subsystem. The <code>List</code> will be sorted from best
0789             * <code>DataFlavor</code> to worst. That is, the first
0790             * <code>DataFlavor</code> will best reflect data in the specified
0791             * native to a Java application.
0792             * <p>
0793             * If the specified native is previously unknown to the data transfer
0794             * subsystem, and that native has been properly encoded, then invoking this
0795             * method will establish a mapping in both directions between the specified
0796             * native and a <code>DataFlavor</code> whose MIME type is a decoded
0797             * version of the native.
0798             * <p>
0799             * If the specified native is not a properly encoded native and the
0800             * mappings for this native have not been altered with
0801             * <code>setFlavorsForNative</code>, then the contents of the
0802             * <code>List</code> is platform dependent, but <code>null</code>
0803             * cannot be returned.
0804             *
0805             * @param nat the native whose corresponding <code>DataFlavor</code>s
0806             *        should be returned. If <code>null</code> is specified, all
0807             *        <code>DataFlavor</code>s currently known to the data transfer
0808             *        subsystem are returned in a non-deterministic order.
0809             * @return a <code>java.util.List</code> of <code>DataFlavor</code>
0810             *         objects into which platform-specific data in the specified,
0811             *         platform-specific native can be translated
0812             *
0813             * @see #encodeJavaMIMEType
0814             * @since 1.4
0815             */
0816            public synchronized List<DataFlavor> getFlavorsForNative(String nat) {
0817
0818                // Check cache, even for null nat
0819                SoftReference ref = (SoftReference) getFlavorsForNativeCache
0820                        .get(nat);
0821                if (ref != null) {
0822                    ArrayList retval = (ArrayList) ref.get();
0823                    if (retval != null) {
0824                        return (List) retval.clone();
0825                    }
0826                }
0827
0828                LinkedList retval = new LinkedList();
0829
0830                if (nat == null) {
0831                    List natives = getNativesForFlavor(null);
0832                    HashSet dups = new HashSet(natives.size());
0833
0834                    for (Iterator natives_iter = natives.iterator(); natives_iter
0835                            .hasNext();) {
0836                        List flavors = getFlavorsForNative((String) natives_iter
0837                                .next());
0838                        for (Iterator flavors_iter = flavors.iterator(); flavors_iter
0839                                .hasNext();) {
0840                            Object flavor = flavors_iter.next();
0841                            if (dups.add(flavor)) {
0842                                retval.add(flavor);
0843                            }
0844                        }
0845                    }
0846                } else {
0847                    List flavors = nativeToFlavorLookup(nat);
0848
0849                    if (disabledMappingGenerationKeys.contains(nat)) {
0850                        return flavors;
0851                    }
0852
0853                    HashSet dups = new HashSet(flavors.size());
0854
0855                    List flavorsAndbaseTypes = nativeToFlavorLookup(nat);
0856
0857                    for (Iterator flavorsAndbaseTypes_iter = flavorsAndbaseTypes
0858                            .iterator(); flavorsAndbaseTypes_iter.hasNext();) {
0859                        Object value = flavorsAndbaseTypes_iter.next();
0860                        if (value instanceof  String) {
0861                            String baseType = (String) value;
0862                            String subType = null;
0863                            try {
0864                                MimeType mimeType = new MimeType(baseType);
0865                                subType = mimeType.getSubType();
0866                            } catch (MimeTypeParseException mtpe) {
0867                                // Cannot happen, since we checked all mappings
0868                                // on load from flavormap.properties.
0869                                assert (false);
0870                            }
0871                            if (DataTransferer.doesSubtypeSupportCharset(
0872                                    subType, null)) {
0873                                if (TEXT_PLAIN_BASE_TYPE.equals(baseType)
0874                                        && dups.add(DataFlavor.stringFlavor)) {
0875                                    retval.add(DataFlavor.stringFlavor);
0876                                }
0877
0878                                for (int i = 0; i < UNICODE_TEXT_CLASSES.length; i++) {
0879                                    DataFlavor toAdd = null;
0880                                    try {
0881                                        toAdd = new DataFlavor(baseType
0882                                                + ";charset=Unicode;class="
0883                                                + UNICODE_TEXT_CLASSES[i]);
0884                                    } catch (ClassNotFoundException cannotHappen) {
0885                                    }
0886                                    if (dups.add(toAdd)) {
0887                                        retval.add(toAdd);
0888                                    }
0889                                }
0890
0891                                for (Iterator charset_iter = DataTransferer
0892                                        .standardEncodings(); charset_iter
0893                                        .hasNext();) {
0894                                    String charset = (String) charset_iter
0895                                            .next();
0896
0897                                    for (int i = 0; i < ENCODED_TEXT_CLASSES.length; i++) {
0898                                        DataFlavor toAdd = null;
0899                                        try {
0900                                            toAdd = new DataFlavor(baseType
0901                                                    + ";charset=" + charset
0902                                                    + ";class="
0903                                                    + ENCODED_TEXT_CLASSES[i]);
0904                                        } catch (ClassNotFoundException cannotHappen) {
0905                                        }
0906
0907                                        // Check for equality to plainTextFlavor so
0908                                        // that we can ensure that the exact charset of
0909                                        // plainTextFlavor, not the canonical charset
0910                                        // or another equivalent charset with a
0911                                        // different name, is used.
0912                                        if (toAdd
0913                                                .equals(DataFlavor.plainTextFlavor)) {
0914                                            toAdd = DataFlavor.plainTextFlavor;
0915                                        }
0916
0917                                        if (dups.add(toAdd)) {
0918                                            retval.add(toAdd);
0919                                        }
0920                                    }
0921                                }
0922
0923                                if (TEXT_PLAIN_BASE_TYPE.equals(baseType)
0924                                        && dups.add(DataFlavor.plainTextFlavor)) {
0925                                    retval.add(DataFlavor.plainTextFlavor);
0926                                }
0927                            } else {
0928                                // Non-charset text natives should be treated as
0929                                // opaque, 8-bit data in any of its various
0930                                // representations.
0931                                for (int i = 0; i < ENCODED_TEXT_CLASSES.length; i++) {
0932                                    DataFlavor toAdd = null;
0933                                    try {
0934                                        toAdd = new DataFlavor(baseType
0935                                                + ";class="
0936                                                + ENCODED_TEXT_CLASSES[i]);
0937                                    } catch (ClassNotFoundException cannotHappen) {
0938                                    }
0939
0940                                    if (dups.add(toAdd)) {
0941                                        retval.add(toAdd);
0942                                    }
0943                                }
0944                            }
0945                        } else {
0946                            DataFlavor flavor = (DataFlavor) value;
0947                            if (dups.add(flavor)) {
0948                                retval.add(flavor);
0949                            }
0950                        }
0951                    }
0952                }
0953
0954                ArrayList arrayList = new ArrayList(retval);
0955                getFlavorsForNativeCache.put(nat, new SoftReference(arrayList));
0956                return (List) arrayList.clone();
0957            }
0958
0959            /**
0960             * Returns a <code>Map</code> of the specified <code>DataFlavor</code>s to
0961             * their most preferred <code>String</code> native. Each native value will
0962             * be the same as the first native in the List returned by
0963             * <code>getNativesForFlavor</code> for the specified flavor.
0964             * <p>
0965             * If a specified <code>DataFlavor</code> is previously unknown to the
0966             * data transfer subsystem, then invoking this method will establish a
0967             * mapping in both directions between the specified <code>DataFlavor</code>
0968             * and an encoded version of its MIME type as its native.
0969             *
0970             * @param flavors an array of <code>DataFlavor</code>s which will be the
0971             *        key set of the returned <code>Map</code>. If <code>null</code> is
0972             *        specified, a mapping of all <code>DataFlavor</code>s known to the
0973             *        data transfer subsystem to their most preferred 
0974             *        <code>String</code> natives will be returned.
0975             * @return a <code>java.util.Map</code> of <code>DataFlavor</code>s to
0976             *         <code>String</code> natives
0977             *
0978             * @see #getNativesForFlavor
0979             * @see #encodeDataFlavor
0980             */
0981            public synchronized Map<DataFlavor, String> getNativesForFlavors(
0982                    DataFlavor[] flavors) {
0983                // Use getNativesForFlavor to generate extra natives for text flavors
0984                // and stringFlavor
0985
0986                if (flavors == null) {
0987                    List flavor_list = getFlavorsForNative(null);
0988                    flavors = new DataFlavor[flavor_list.size()];
0989                    flavor_list.toArray(flavors);
0990                }
0991
0992                HashMap retval = new HashMap(flavors.length, 1.0f);
0993                for (int i = 0; i < flavors.length; i++) {
0994                    List natives = getNativesForFlavor(flavors[i]);
0995                    String nat = (natives.isEmpty()) ? null : (String) natives
0996                            .get(0);
0997                    retval.put(flavors[i], nat);
0998                }
0999
1000                return retval;
1001            }
1002
1003            /**
1004             * Returns a <code>Map</code> of the specified <code>String</code> natives
1005             * to their most preferred <code>DataFlavor</code>. Each
1006             * <code>DataFlavor</code> value will be the same as the first
1007             * <code>DataFlavor</code> in the List returned by
1008             * <code>getFlavorsForNative</code> for the specified native.
1009             * <p>
1010             * If a specified native is previously unknown to the data transfer
1011             * subsystem, and that native has been properly encoded, then invoking this
1012             * method will establish a mapping in both directions between the specified
1013             * native and a <code>DataFlavor</code> whose MIME type is a decoded
1014             * version of the native.
1015             *
1016             * @param natives an array of <code>String</code>s which will be the
1017             *        key set of the returned <code>Map</code>. If <code>null</code> is
1018             *        specified, a mapping of all supported <code>String</code> natives
1019             *        to their most preferred <code>DataFlavor</code>s will be
1020             *        returned.
1021             * @return a <code>java.util.Map</code> of <code>String</code> natives to
1022             *         <code>DataFlavor</code>s
1023             *
1024             * @see #getFlavorsForNative
1025             * @see #encodeJavaMIMEType
1026             */
1027            public synchronized Map<String, DataFlavor> getFlavorsForNatives(
1028                    String[] natives) {
1029                // Use getFlavorsForNative to generate extra flavors for text natives
1030
1031                if (natives == null) {
1032                    List native_list = getNativesForFlavor(null);
1033                    natives = new String[native_list.size()];
1034                    native_list.toArray(natives);
1035                }
1036
1037                HashMap retval = new HashMap(natives.length, 1.0f);
1038                for (int i = 0; i < natives.length; i++) {
1039                    List flavors = getFlavorsForNative(natives[i]);
1040                    DataFlavor flav = (flavors.isEmpty()) ? null
1041                            : (DataFlavor) flavors.get(0);
1042                    retval.put(natives[i], flav);
1043                }
1044
1045                return retval;
1046            }
1047
1048            /**
1049             * Adds a mapping from the specified <code>DataFlavor</code> (and all
1050             * <code>DataFlavor</code>s equal to the specified <code>DataFlavor</code>)
1051             * to the specified <code>String</code> native.
1052             * Unlike <code>getNativesForFlavor</code>, the mapping will only be
1053             * established in one direction, and the native will not be encoded. To
1054             * establish a two-way mapping, call
1055             * <code>addFlavorForUnencodedNative</code> as well. The new mapping will 
1056             * be of lower priority than any existing mapping.
1057             * This method has no effect if a mapping from the specified or equal
1058             * <code>DataFlavor</code> to the specified <code>String</code> native
1059             * already exists.
1060             *
1061             * @param flav the <code>DataFlavor</code> key for the mapping
1062             * @param nat the <code>String</code> native value for the mapping
1063             * @throws NullPointerException if flav or nat is <code>null</code>
1064             *
1065             * @see #addFlavorForUnencodedNative
1066             * @since 1.4
1067             */
1068            public synchronized void addUnencodedNativeForFlavor(
1069                    DataFlavor flav, String nat) {
1070                if (flav == null || nat == null) {
1071                    throw new NullPointerException(
1072                            "null arguments not permitted");
1073                }
1074
1075                List natives = (List) flavorToNative.get(flav);
1076                if (natives == null) {
1077                    natives = new ArrayList(1);
1078                    flavorToNative.put(flav, natives);
1079                } else if (natives.contains(nat)) {
1080                    return;
1081                }
1082                natives.add(nat);
1083                getNativesForFlavorCache.remove(flav);
1084                getNativesForFlavorCache.remove(null);
1085            }
1086
1087            /**
1088             * Discards the current mappings for the specified <code>DataFlavor</code>
1089             * and all <code>DataFlavor</code>s equal to the specified
1090             * <code>DataFlavor</code>, and creates new mappings to the 
1091             * specified <code>String</code> natives.
1092             * Unlike <code>getNativesForFlavor</code>, the mappings will only be
1093             * established in one direction, and the natives will not be encoded. To
1094             * establish two-way mappings, call <code>setFlavorsForNative</code>
1095             * as well. The first native in the array will represent the highest
1096             * priority mapping. Subsequent natives will represent mappings of
1097             * decreasing priority.
1098             * <p>
1099             * If the array contains several elements that reference equal
1100             * <code>String</code> natives, this method will establish new mappings
1101             * for the first of those elements and ignore the rest of them.
1102             * <p> 
1103             * It is recommended that client code not reset mappings established by the
1104             * data transfer subsystem. This method should only be used for
1105             * application-level mappings.
1106             *
1107             * @param flav the <code>DataFlavor</code> key for the mappings
1108             * @param natives the <code>String</code> native values for the mappings
1109             * @throws NullPointerException if flav or natives is <code>null</code>
1110             *         or if natives contains <code>null</code> elements
1111             *
1112             * @see #setFlavorsForNative
1113             * @since 1.4
1114             */
1115            public synchronized void setNativesForFlavor(DataFlavor flav,
1116                    String[] natives) {
1117                if (flav == null || natives == null) {
1118                    throw new NullPointerException(
1119                            "null arguments not permitted");
1120                }
1121
1122                flavorToNative.remove(flav);
1123                for (int i = 0; i < natives.length; i++) {
1124                    addUnencodedNativeForFlavor(flav, natives[i]);
1125                }
1126                disabledMappingGenerationKeys.add(flav);
1127                // Clear the cache to handle the case of empty natives.
1128                getNativesForFlavorCache.remove(flav);
1129                getNativesForFlavorCache.remove(null);
1130            }
1131
1132            /**
1133             * Adds a mapping from a single <code>String</code> native to a single
1134             * <code>DataFlavor</code>. Unlike <code>getFlavorsForNative</code>, the
1135             * mapping will only be established in one direction, and the native will
1136             * not be encoded. To establish a two-way mapping, call
1137             * <code>addUnencodedNativeForFlavor</code> as well. The new mapping will
1138             * be of lower priority than any existing mapping.
1139             * This method has no effect if a mapping from the specified
1140             * <code>String</code> native to the specified or equal
1141             * <code>DataFlavor</code> already exists.
1142             *
1143             * @param nat the <code>String</code> native key for the mapping
1144             * @param flav the <code>DataFlavor</code> value for the mapping
1145             * @throws NullPointerException if nat or flav is <code>null</code>
1146             *
1147             * @see #addUnencodedNativeForFlavor
1148             * @since 1.4
1149             */
1150            public synchronized void addFlavorForUnencodedNative(String nat,
1151                    DataFlavor flav) {
1152                if (nat == null || flav == null) {
1153                    throw new NullPointerException(
1154                            "null arguments not permitted");
1155                }
1156
1157                List flavors = (List) nativeToFlavor.get(nat);
1158                if (flavors == null) {
1159                    flavors = new ArrayList(1);
1160                    nativeToFlavor.put(nat, flavors);
1161                } else if (flavors.contains(flav)) {
1162                    return;
1163                }
1164                flavors.add(flav);
1165                getFlavorsForNativeCache.remove(nat);
1166                getFlavorsForNativeCache.remove(null);
1167            }
1168
1169            /**
1170             * Discards the current mappings for the specified <code>String</code>
1171             * native, and creates new mappings to the specified
1172             * <code>DataFlavor</code>s. Unlike <code>getFlavorsForNative</code>, the
1173             * mappings will only be established in one direction, and the natives need
1174             * not be encoded. To establish two-way mappings, call
1175             * <code>setNativesForFlavor</code> as well. The first
1176             * <code>DataFlavor</code> in the array will represent the highest priority
1177             * mapping. Subsequent <code>DataFlavor</code>s will represent mappings of
1178             * decreasing priority.
1179             * <p>
1180             * If the array contains several elements that reference equal
1181             * <code>DataFlavor</code>s, this method will establish new mappings
1182             * for the first of those elements and ignore the rest of them.
1183             * <p>
1184             * It is recommended that client code not reset mappings established by the
1185             * data transfer subsystem. This method should only be used for
1186             * application-level mappings.
1187             *
1188             * @param nat the <code>String</code> native key for the mappings
1189             * @param flavors the <code>DataFlavor</code> values for the mappings
1190             * @throws NullPointerException if nat or flavors is <code>null</code>
1191             *         or if flavors contains <code>null</code> elements
1192             *
1193             * @see #setNativesForFlavor
1194             * @since 1.4
1195             */
1196            public synchronized void setFlavorsForNative(String nat,
1197                    DataFlavor[] flavors) {
1198                if (nat == null || flavors == null) {
1199                    throw new NullPointerException(
1200                            "null arguments not permitted");
1201                }
1202
1203                nativeToFlavor.remove(nat);
1204                for (int i = 0; i < flavors.length; i++) {
1205                    addFlavorForUnencodedNative(nat, flavors[i]);
1206                }
1207                disabledMappingGenerationKeys.add(nat);
1208                // Clear the cache to handle the case of empty flavors.
1209                getFlavorsForNativeCache.remove(nat);
1210                getFlavorsForNativeCache.remove(null);
1211            }
1212
1213            /**
1214             * Encodes a MIME type for use as a <code>String</code> native. The format
1215             * of an encoded representation of a MIME type is implementation-dependent.
1216             * The only restrictions are:
1217             * <ul>
1218             * <li>The encoded representation is <code>null</code> if and only if the
1219             * MIME type <code>String</code> is <code>null</code>.</li>
1220             * <li>The encoded representations for two non-<code>null</code> MIME type
1221             * <code>String</code>s are equal if and only if these <code>String</code>s
1222             * are equal according to <code>String.equals(Object)</code>.</li>
1223             * </ul>
1224             * <p>
1225             * Sun's reference implementation of this method returns the specified MIME
1226             * type <code>String</code> prefixed with <code>JAVA_DATAFLAVOR:</code>.
1227             *
1228             * @param mimeType the MIME type to encode
1229             * @return the encoded <code>String</code>, or <code>null</code> if
1230             *         mimeType is <code>null</code>
1231             */
1232            public static String encodeJavaMIMEType(String mimeType) {
1233                return (mimeType != null) ? JavaMIME + mimeType : null;
1234            }
1235
1236            /**
1237             * Encodes a <code>DataFlavor</code> for use as a <code>String</code>
1238             * native. The format of an encoded <code>DataFlavor</code> is 
1239             * implementation-dependent. The only restrictions are:
1240             * <ul>
1241             * <li>The encoded representation is <code>null</code> if and only if the
1242             * specified <code>DataFlavor</code> is <code>null</code> or its MIME type
1243             * <code>String</code> is <code>null</code>.</li>
1244             * <li>The encoded representations for two non-<code>null</code>
1245             * <code>DataFlavor</code>s with non-<code>null</code> MIME type
1246             * <code>String</code>s are equal if and only if the MIME type
1247             * <code>String</code>s of these <code>DataFlavor</code>s are equal
1248             * according to <code>String.equals(Object)</code>.</li>
1249             * </ul>
1250             * <p>
1251             * Sun's reference implementation of this method returns the MIME type
1252             * <code>String</code> of the specified <code>DataFlavor</code> prefixed
1253             * with <code>JAVA_DATAFLAVOR:</code>.
1254             *
1255             * @param flav the <code>DataFlavor</code> to encode
1256             * @return the encoded <code>String</code>, or <code>null</code> if
1257             *         flav is <code>null</code> or has a <code>null</code> MIME type
1258             */
1259            public static String encodeDataFlavor(DataFlavor flav) {
1260                return (flav != null) ? SystemFlavorMap.encodeJavaMIMEType(flav
1261                        .getMimeType()) : null;
1262            }
1263
1264            /**
1265             * Returns whether the specified <code>String</code> is an encoded Java
1266             * MIME type.
1267             *
1268             * @param str the <code>String</code> to test
1269             * @return <code>true</code> if the <code>String</code> is encoded;
1270             *         <code>false</code> otherwise
1271             */
1272            public static boolean isJavaMIMEType(String str) {
1273                return (str != null && str.startsWith(JavaMIME, 0));
1274            }
1275
1276            /**
1277             * Decodes a <code>String</code> native for use as a Java MIME type.
1278             *
1279             * @param nat the <code>String</code> to decode
1280             * @return the decoded Java MIME type, or <code>null</code> if nat is not
1281             *         an encoded <code>String</code> native
1282             */
1283            public static String decodeJavaMIMEType(String nat) {
1284                return (isJavaMIMEType(nat)) ? nat.substring(JavaMIME.length(),
1285                        nat.length()).trim() : null;
1286            }
1287
1288            /**
1289             * Decodes a <code>String</code> native for use as a
1290             * <code>DataFlavor</code>.
1291             *
1292             * @param nat the <code>String</code> to decode
1293             * @return the decoded <code>DataFlavor</code>, or <code>null</code> if
1294             *         nat is not an encoded <code>String</code> native
1295             */
1296            public static DataFlavor decodeDataFlavor(String nat)
1297                    throws ClassNotFoundException {
1298                String retval_str = SystemFlavorMap.decodeJavaMIMEType(nat);
1299                return (retval_str != null) ? new DataFlavor(retval_str) : null;
1300            }
1301        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.