Util.java revision 2981:d1e5707cd4eb
11592Srgrimes/*
21592Srgrimes * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
31592Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41592Srgrimes *
51592Srgrimes * This code is free software; you can redistribute it and/or modify it
61592Srgrimes * under the terms of the GNU General Public License version 2 only, as
71592Srgrimes * published by the Free Software Foundation.  Oracle designates this
81592Srgrimes * particular file as subject to the "Classpath" exception as provided
91592Srgrimes * by Oracle in the LICENSE file that accompanied this code.
101592Srgrimes *
111592Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT
121592Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131592Srgrimes * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
141592Srgrimes * version 2 for more details (a copy is included in the LICENSE file that
151592Srgrimes * accompanied this code).
161592Srgrimes *
171592Srgrimes * You should have received a copy of the GNU General Public License version
181592Srgrimes * 2 along with this work; if not, write to the Free Software Foundation,
191592Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
201592Srgrimes *
211592Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
221592Srgrimes * or visit www.oracle.com if you need additional information or have any
231592Srgrimes * questions.
241592Srgrimes */
251592Srgrimes
261592Srgrimespackage com.sun.tools.sjavac;
271592Srgrimes
281592Srgrimesimport java.io.File;
291592Srgrimesimport java.io.PrintWriter;
301592Srgrimesimport java.io.StringWriter;
311592Srgrimesimport java.nio.file.Path;
321592Srgrimesimport java.util.Arrays;
331592Srgrimesimport java.util.Collection;
341592Srgrimesimport java.util.HashSet;
351592Srgrimesimport java.util.Map;
361592Srgrimesimport java.util.Set;
371592Srgrimesimport java.util.StringTokenizer;
381592Srgrimesimport java.util.function.Function;
391592Srgrimesimport java.util.stream.Collectors;
401592Srgrimes
411592Srgrimes/**
421592Srgrimes * Utilities.
431592Srgrimes *
441592Srgrimes *  <p><b>This is NOT part of any supported API.
451592Srgrimes *  If you write code that depends on this, you do so at your own risk.
461592Srgrimes *  This code and its internal interfaces are subject to change or
471592Srgrimes *  deletion without notice.</b>
481592Srgrimes */
491592Srgrimespublic class Util {
501592Srgrimes
511592Srgrimes    public static String toFileSystemPath(String pkgId) {
521592Srgrimes        if (pkgId == null || pkgId.length()==0) return null;
531592Srgrimes        String pn;
541592Srgrimes        if (pkgId.charAt(0) == ':') {
551592Srgrimes            // When the module is the default empty module.
561592Srgrimes            // Do not prepend the module directory, because there is none.
571592Srgrimes            // Thus :java.foo.bar translates to java/foo/bar (or \)
581592Srgrimes            pn = pkgId.substring(1).replace('.',File.separatorChar);
591592Srgrimes        } else {
601592Srgrimes            // There is a module. Thus jdk.base:java.foo.bar translates
611592Srgrimes            // into jdk.base/java/foo/bar
621592Srgrimes            int cp = pkgId.indexOf(':');
631592Srgrimes            String mn = pkgId.substring(0,cp);
641592Srgrimes            pn = mn+File.separatorChar+pkgId.substring(cp+1).replace('.',File.separatorChar);
651592Srgrimes        }
661592Srgrimes        return pn;
671592Srgrimes    }
681592Srgrimes
691592Srgrimes    public static String justPackageName(String pkgName) {
701592Srgrimes        int c = pkgName.indexOf(":");
711592Srgrimes        if (c == -1)
721592Srgrimes            throw new IllegalArgumentException("Expected ':' in package name (" + pkgName + ")");
731592Srgrimes        return pkgName.substring(c+1);
741592Srgrimes    }
751592Srgrimes
761592Srgrimes    public static String extractStringOption(String opName, String s) {
771592Srgrimes        return extractStringOption(opName, s, null);
781592Srgrimes    }
791592Srgrimes
801592Srgrimes    public static String extractStringOption(String opName, String s, String deflt) {
811592Srgrimes        int p = s.indexOf(opName+"=");
821592Srgrimes        if (p == -1) return deflt;
831592Srgrimes        p+=opName.length()+1;
841592Srgrimes        int pe = s.indexOf(',', p);
851592Srgrimes        if (pe == -1) pe = s.length();
861592Srgrimes        return s.substring(p, pe);
871592Srgrimes    }
881592Srgrimes
891592Srgrimes    public static boolean extractBooleanOption(String opName, String s, boolean deflt) {
901592Srgrimes       String str = extractStringOption(opName, s);
911592Srgrimes        return "true".equals(str) ? true
921592Srgrimes             : "false".equals(str) ? false
931592Srgrimes             : deflt;
941592Srgrimes    }
951592Srgrimes
961592Srgrimes    public static int extractIntOption(String opName, String s) {
971592Srgrimes        return extractIntOption(opName, s, 0);
981592Srgrimes    }
991592Srgrimes
1001592Srgrimes    public static int extractIntOption(String opName, String s, int deflt) {
1011592Srgrimes        int p = s.indexOf(opName+"=");
1021592Srgrimes        if (p == -1) return deflt;
1031592Srgrimes        p+=opName.length()+1;
1041592Srgrimes        int pe = s.indexOf(',', p);
1051592Srgrimes        if (pe == -1) pe = s.length();
1061592Srgrimes        int v = 0;
1071592Srgrimes        try {
1081592Srgrimes            v = Integer.parseInt(s.substring(p, pe));
1091592Srgrimes        } catch (Exception e) {}
1101592Srgrimes        return v;
1111592Srgrimes    }
1121592Srgrimes
1131592Srgrimes    /**
1141592Srgrimes     * Extract the package name from a fully qualified class name.
1151592Srgrimes     *
1161592Srgrimes     * Example: Given "pkg.subpkg.A" this method returns ":pkg.subpkg".
1171592Srgrimes     * Given "C" this method returns ":".
1181592Srgrimes     *
1191592Srgrimes     * @returns package name of the given class name
1201592Srgrimes     */
1211592Srgrimes    public static String pkgNameOfClassName(String fqClassName) {
1221592Srgrimes        int i = fqClassName.lastIndexOf('.');
1231592Srgrimes        String pkg = i == -1 ? "" : fqClassName.substring(0, i);
1241592Srgrimes        return ":" + pkg;
1251592Srgrimes    }
1261592Srgrimes
1271592Srgrimes    /**
1281592Srgrimes     * Clean out unwanted sub options supplied inside a primary option.
1291592Srgrimes     * For example to only had portfile remaining from:
1301592Srgrimes     *    settings="--server:id=foo,portfile=bar"
1311592Srgrimes     * do settings = cleanOptions("--server:",Util.set("-portfile"),settings);
1321592Srgrimes     *    now settings equals "--server:portfile=bar"
1331592Srgrimes     *
1341592Srgrimes     * @param allowedSubOptions A set of the allowed sub options, id portfile etc.
1351592Srgrimes     * @param s The option settings string.
1361592Srgrimes     */
1371592Srgrimes    public static String cleanSubOptions(Set<String> allowedSubOptions, String s) {
1381592Srgrimes        StringBuilder sb = new StringBuilder();
1391592Srgrimes        StringTokenizer st = new StringTokenizer(s, ",");
1401592Srgrimes        while (st.hasMoreTokens()) {
1411592Srgrimes            String o = st.nextToken();
1421592Srgrimes            int p = o.indexOf('=');
1431592Srgrimes            if (p>0) {
1441592Srgrimes                String key = o.substring(0,p);
1451592Srgrimes                String val = o.substring(p+1);
1461592Srgrimes                if (allowedSubOptions.contains(key)) {
1471592Srgrimes                    if (sb.length() > 0) sb.append(',');
1481592Srgrimes                    sb.append(key+"="+val);
1491592Srgrimes                }
1501592Srgrimes            }
1511592Srgrimes        }
1521592Srgrimes        return sb.toString();
1531592Srgrimes    }
1541592Srgrimes
1551592Srgrimes    /**
1561592Srgrimes     * Convenience method to create a set with strings.
1571592Srgrimes     */
1581592Srgrimes    public static Set<String> set(String... ss) {
1591592Srgrimes        Set<String> set = new HashSet<>();
1601592Srgrimes        set.addAll(Arrays.asList(ss));
1611592Srgrimes        return set;
1621592Srgrimes    }
1631592Srgrimes
1641592Srgrimes    /**
1651592Srgrimes     * Normalize windows drive letter paths to upper case to enable string
1661592Srgrimes     * comparison.
1671592Srgrimes     *
1681592Srgrimes     * @param file File name to normalize
1691592Srgrimes     * @return The normalized string if file has a drive letter at the beginning,
1701592Srgrimes     *         otherwise the original string.
1711592Srgrimes     */
1721592Srgrimes    public static String normalizeDriveLetter(String file) {
1731592Srgrimes        if (file.length() > 2 && file.charAt(1) == ':') {
1741592Srgrimes            return Character.toUpperCase(file.charAt(0)) + file.substring(1);
1751592Srgrimes        } else if (file.length() > 3 && file.charAt(0) == '*'
1761592Srgrimes                   && file.charAt(2) == ':') {
1771592Srgrimes            // Handle a wildcard * at the beginning of the string.
1781592Srgrimes            return file.substring(0, 1) + Character.toUpperCase(file.charAt(1))
1791592Srgrimes                   + file.substring(2);
1801592Srgrimes        }
1811592Srgrimes        return file;
1821592Srgrimes    }
1831592Srgrimes
1841592Srgrimes    /**
1851592Srgrimes     * Locate the setting for the server properties.
1861592Srgrimes     */
1871592Srgrimes    public static String findServerSettings(String[] args) {
1881592Srgrimes        for (String s : args) {
1891592Srgrimes            if (s.startsWith("--server:")) {
1901592Srgrimes                return s;
1911592Srgrimes            }
1921592Srgrimes        }
1931592Srgrimes        return null;
1941592Srgrimes    }
1951592Srgrimes
1961592Srgrimes    public static <E> Set<E> union(Set<? extends E> s1,
1971592Srgrimes                                   Set<? extends E> s2) {
1981592Srgrimes        Set<E> union = new HashSet<>();
1991592Srgrimes        union.addAll(s1);
2001592Srgrimes        union.addAll(s2);
2011592Srgrimes        return union;
2021592Srgrimes    }
2031592Srgrimes
2041592Srgrimes    public static <E> Set<E> subtract(Set<? extends E> orig,
2051592Srgrimes                                      Set<? extends E> toSubtract) {
2061592Srgrimes        Set<E> difference = new HashSet<>(orig);
2071592Srgrimes        difference.removeAll(toSubtract);
2081592Srgrimes        return difference;
2091592Srgrimes    }
2101592Srgrimes
2111592Srgrimes    public static String getStackTrace(Throwable t) {
2121592Srgrimes        StringWriter sw = new StringWriter();
2131592Srgrimes        t.printStackTrace(new PrintWriter(sw));
2141592Srgrimes        return sw.toString();
2151592Srgrimes    }
2161592Srgrimes
2171592Srgrimes    // TODO: Remove when refactoring from java.io.File to java.nio.file.Path.
2181592Srgrimes    public static File pathToFile(Path path) {
2191592Srgrimes        return path == null ? null : path.toFile();
2201592Srgrimes    }
2211592Srgrimes
2221592Srgrimes    public static <E> Set<E> intersection(Collection<? extends E> c1,
2231592Srgrimes                                          Collection<? extends E> c2) {
2241592Srgrimes        Set<E> intersection = new HashSet<E>(c1);
2251592Srgrimes        intersection.retainAll(c2);
2261592Srgrimes        return intersection;
2271592Srgrimes    }
2281592Srgrimes
2291592Srgrimes    public static <I, T> Map<I, T> indexBy(Collection<? extends T> c,
2301592Srgrimes                                           Function<? super T, ? extends I> indexFunction) {
2311592Srgrimes        return c.stream().collect(Collectors.<T, I, T>toMap(indexFunction, o -> o));
2321592Srgrimes    }
2331592Srgrimes}
2341592Srgrimes