package com.redhat.ceylon.model.cmr; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * Hide JDK impl details here. * * @author Stéphane Épardaud <stef@epardaud.fr> * @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a> */ public class JDKUtils { public enum JDK { JDK7("package-list.jdk7", "package-list.oracle.jdk7", "7"), JDK8("package-list.jdk8", "package-list.oracle.jdk8", "8"); public final String packageList; public final String packageListOracle; public final String version; private JDK(String packageList, String packageListOracle, String version) { this.packageList = packageList; this.packageListOracle = packageListOracle; this.version = version; } public boolean providesVersion(String version){ if(this.version.equals(version)) return true; // also provides every smaller version EnumSet<JDK> smaller = EnumSet.range(JDK7, this); // we want strictly smaller smaller.remove(this); for(JDK smallerJDK : smaller){ if(smallerJDK.version.equals(version)) return true; } return false; } public boolean isLowerVersion(String version) { EnumSet<JDK> smaller = EnumSet.range(JDK7, this); // we want strictly smaller smaller.remove(this); for(JDK smallerJDK : smaller){ if(smallerJDK.version.equals(version)) return true; } return false; } } public final static JDK jdk; static { String version = System.getProperty("java.version"); if(version != null && version.startsWith("1.8")){ jdk = JDK.JDK8; }else{ jdk = JDK.JDK7; } } private static Map<String, Tuple> jdkModules; private static Map<String, Tuple> jdkOracleModules; private static HashMap<String, String> jdkPackageToModule; private static class Tuple { private Set<String> packages; private Set<String> paths; private Tuple() { packages = new HashSet<String>(); paths = new HashSet<String>(); } boolean isEmpty() { return packages.isEmpty(); } Tuple finish() { packages = Collections.unmodifiableSet(packages); paths = Collections.unmodifiableSet(paths); return this; } } private static synchronized void loadPackageList() { if (jdkModules != null) return; jdkModules = loadModularPackageList(jdk.packageList); jdkOracleModules = loadModularPackageList(jdk.packageListOracle); jdkPackageToModule = new HashMap<String,String>(); for(Entry<String, Tuple> entry : jdkModules.entrySet()){ for(String pkg : entry.getValue().packages) jdkPackageToModule.put(pkg, entry.getKey()); } for(Entry<String, Tuple> entry : jdkOracleModules.entrySet()){ for(String pkg : entry.getValue().packages) jdkPackageToModule.put(pkg, entry.getKey()); } } private static Map<String, Tuple> loadModularPackageList(String file) { try { // not thread-safe, but that's OK because the caller is thread-safe Map<String, Tuple> jdkPackages = new HashMap<String, Tuple>(); InputStream inputStream = JDKUtils.class.getResourceAsStream(file); if (inputStream == null) { throw new RuntimeException("Failed to read JDK package list file from " + file + ": your Ceylon installation is broken."); } BufferedReader bis = new BufferedReader(new InputStreamReader(inputStream, "ASCII")); Tuple tuple = null; String moduleName = null; String pkg; while ((pkg = bis.readLine()) != null) { // strip comments int commentStart = pkg.indexOf('#'); if (commentStart > -1) pkg = pkg.substring(0, commentStart); // strip whitespace pkg = pkg.trim(); // ignore empty lines if (pkg.isEmpty()) continue; // see if we start a new module if (pkg.startsWith("=")) { String name = pkg.substring(1).trim(); if (name.isEmpty()) throw new RuntimeException("Failed to read JDK module list file from " + file + ": module has empty name"); // close previous module if (tuple != null) { if (tuple.isEmpty()) throw new RuntimeException("Failed to read JDK module list file from " + file + ": module " + moduleName + " is empty"); // save previous module jdkPackages.put(moduleName, tuple.finish()); } // start the new module moduleName = name; tuple = new Tuple(); continue; } // add a package to the current module if (tuple == null) throw new RuntimeException("Failed to read JDK module list file from " + file + ": adding package to undefined module"); tuple.packages.add(pkg); tuple.paths.add(pkg.replace('.', '/')); } bis.close(); // close previous module if (tuple != null) { if (tuple.isEmpty()) throw new RuntimeException("Failed to read JDK module list file from " + file + ": module " + moduleName + " is empty"); // save previous module jdkPackages.put(moduleName, tuple.finish()); } // sanity check if (jdkPackages.size() == 0) throw new RuntimeException("Failed to read JDK package list file from " + file + "(empty package set): your Ceylon installation is broken."); return Collections.unmodifiableMap(jdkPackages); } catch (IOException x) { throw new RuntimeException("Failed to read JDK package list file from " + file + ": your Ceylon installation is broken.", x); } } public static boolean isJDKModule(String mod) { loadPackageList(); return jdkModules.containsKey(mod); } public static boolean isJDKPackage(String mod, String pkg) { loadPackageList(); Tuple tuple = jdkModules.get(mod); return tuple != null && tuple.packages.contains(pkg); } public static boolean isJDKAnyPackage(String pkg) { loadPackageList(); for (Tuple tuple : jdkModules.values()) { if (tuple.packages.contains(pkg)) return true; } return false; } public static Set<String> getJDKModuleNames() { loadPackageList(); return jdkModules.keySet(); } public static Set<String> getJDKPackagesByModule(String module) { loadPackageList(); Tuple tuple = jdkModules.get(module); return tuple != null ? tuple.packages : null; } public static Set<String> getJDKPathsByModule(String module) { loadPackageList(); Tuple tuple = jdkModules.get(module); return tuple != null ? tuple.paths : null; } public static boolean isOracleJDKModule(String pkg) { loadPackageList(); return jdkOracleModules.containsKey(pkg); } public static boolean isOracleJDKPackage(String mod, String pkg) { loadPackageList(); Tuple tuple = jdkOracleModules.get(mod); return tuple != null && tuple.packages.contains(pkg); } public static boolean isOracleJDKAnyPackage(String pkg) { loadPackageList(); for (Tuple tuple : jdkOracleModules.values()) { if (tuple.packages.contains(pkg)) return true; } return false; } public static Set<String> getOracleJDKModuleNames() { loadPackageList(); return jdkOracleModules.keySet(); } public static Set<String> getOracleJDKPackagesByModule(String module) { loadPackageList(); Tuple tuple = jdkOracleModules.get(module); return tuple != null ? tuple.packages : null; } public static Set<String> getOracleJDKPathsByModule(String module) { loadPackageList(); Tuple tuple = jdkOracleModules.get(module); return tuple != null ? tuple.paths : null; } public static String getJDKModuleNameForPackage(String pkgName) { loadPackageList(); return jdkPackageToModule.get(pkgName); } }