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);
}
}