make/tools/classanalyzer/src/com/sun/classanalyzer/PlatformModuleBuilder.java
Print this page
@@ -20,199 +20,359 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.classanalyzer;
+import com.sun.classanalyzer.ModuleInfo.Dependence;
+import static com.sun.classanalyzer.PlatformModuleBuilder.PlatformModuleNames.*;
+
import java.io.BufferedReader;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
+import java.util.*;
-import java.util.Collection;
-import java.util.Deque;
-import java.util.LinkedList;
-import java.util.Properties;
-import java.util.Set;
-import java.util.TreeSet;
-import static com.sun.classanalyzer.Module.*;
-
/**
- * Platform module.
+ * A platform module builder for JDK. JDK's boot module, base module,
+ * and JRE tools module must be defined in the modules.config files.
+ * The platform module builder will create the following platform
+ * modules in addition to the ones specified in the configuration files:
+ * - JDK and JRE aggregator modules
+ * - one jdk.<m> aggregator module for each sun.<m> module to
+ * reexport its public APIs
*
- * The name of the platform modules starts with either "jdk." or "sun.".
- * All sun.* and jdk.boot are local modules. Any requesting module
- * of a local module has to be explicitly permitted.
- *
- * The input module config files can define "sun.*" and "jdk.*"
- * modules. For any sun.* module, it will have a corresponding
- * non-local platform module that is defined for application modules
- * to require.
- *
- * The tool will create the following platform modules:
- * 1) jdk.<name> for each sun.<name> module
- * 2) jdk module - represents the entire JDK
- * 3) jdk.jre module - represents the entire JRE
- *
+ * @author Mandy Chung
*/
-public class Platform {
+public class PlatformModuleBuilder extends ModuleBuilder {
+ /**
+ * Platform modules that must be defined in the modules.properties
+ */
+ static class PlatformModuleNames {
+ static final String BOOT_MODULE =
+ getValue("platform.boot.module");
+ static final String BASE_MODULE =
+ getValue("platform.base.module");
+ static final String JDK_MODULE =
+ getValue("platform.jdk.module");
+ static final String JRE_MODULE =
+ getValue("platform.jre.module");
+ static final String JRE_TOOLS_MODULE =
+ getValue("platform.jre.tools.module");
- static final String DEFAULT_BOOT_MODULE = "jdk.boot";
- static final String JDK_BASE_MODULE = "jdk.base";
- // platform modules created but not defined in the input module configs.
- static final String JDK_MODULE = "jdk";
- static final String JRE_MODULE = "jdk.jre";
- static final String LEGACY_MODULE = "jdk.legacy";
- // the following modules are expected to be defined in
- // the input module config files.
- static final String JDK_TOOLS = "jdk.tools";
- static final String JRE_TOOLS = "jdk.tools.jre";
- static final String JDK_BASE_TOOLS = "jdk.tools.base";
- static final String JDK_LANGTOOLS = "jdk.langtools";
-
- static boolean isBootModule(String name) {
- return name.equals(DEFAULT_BOOT_MODULE);
+ private static String getValue(String key) {
+ String value = Module.getModuleProperty(key);
+ if (value == null || value.isEmpty()) {
+ throw new RuntimeException("Null or empty module property: " + key);
}
- private static BootModule bootModule;
-
- static Module createBootModule(ModuleConfig config) {
- bootModule = new BootModule(config);
- return bootModule;
+ return value;
}
+ }
- static Module bootModule() {
- return bootModule;
+ private BootModule bootModule;
+ private final PlatformModule jdkModule;
+ private final PlatformModule jreModule;
+
+ public PlatformModuleBuilder(List<String> configs, String version)
+ throws IOException {
+ this(configs, null, true, version);
}
- private static Module jdkBaseModule;
- static Module jdkBaseModule() {
- if (jdkBaseModule == null) {
- jdkBaseModule = findModule(JDK_BASE_MODULE);
+ public PlatformModuleBuilder(List<String> configs,
+ List<String> depconfigs,
+ boolean merge,
+ String version)
+ throws IOException {
+ super(null, depconfigs, merge, version);
+
+ Module.setBaseModule(BASE_MODULE);
+
+ // create modules based on the input config files
+ for (String file : configs) {
+ for (ModuleConfig mconfig : ModuleConfig.readConfigurationFile(file)) {
+ newModule(mconfig);
}
- return jdkBaseModule;
}
- private static Module jdkBaseToolModule;
- static Module jdkBaseToolModule() {
- if (jdkBaseToolModule == null) {
- jdkBaseToolModule = findModule(JDK_BASE_TOOLS);
+ // Create the full jdk and jre modules
+ jdkModule = (PlatformModule) newModule(JDK_MODULE);
+ jreModule = (PlatformModule) newModule(JRE_MODULE);
}
- return jdkBaseToolModule;
- }
- private static Module jdkModule;
- private static Module jreModule;
- private static Module legacyModule;
- static Module jdkModule() {
- return jdkModule;
+ @Override
+ public Module newModule(ModuleConfig mconfig) {
+ return addPlatformModule(mconfig);
}
- static Module jreModule() {
- return jreModule;
+ @Override
+ public void run() throws IOException {
+ // assign classes and resource files to the modules
+ // group fine-grained modules per configuration files
+ buildModules();
+
+ // build public jdk modules to reexport sun.* modules
+ buildJDKModules();
+
+ // generate package information
+ buildPackageInfos();
+
+ // analyze cross-module dependencies and generate ModuleInfo
+ buildModuleInfos();
+
+ // ## Hack: add local to all requires
+ for (Module m : Module.getAllModules()) {
+ if (m.isTopLevel()) {
+ PlatformModule pm = (PlatformModule) m;
+ if (pm.isBootConnected()) {
+ for (Dependence d : pm.getModuleInfo().requires()) {
+ d.addModifier(Dependence.Modifier.LOCAL);
}
+ }
+ }
+ }
+ }
- static Module legacyModule() {
- return legacyModule;
+ private void buildJDKModules() {
+ Set<PlatformModule> modules = new LinkedHashSet<PlatformModule>();
+ PlatformModule jreToolModule = (PlatformModule)
+ Module.findModule(JRE_TOOLS_MODULE);
+
+ for (Module m : Module.getAllModules()) {
+ if (m.isTopLevel()) {
+ PlatformModule pm = (PlatformModule) m;
+ modules.add(pm);
}
+ }
- private static Module addPlatformModule(String name, String mainClass) {
+ // set exporter
+ for (PlatformModule pm : modules) {
+ PlatformModule exporter = pm;
+ String name = pm.name();
+ if (name.startsWith("sun.")) {
+ // create an aggregate module for each sun.* module
+ String mn = name.replaceFirst("sun", "jdk");
+ String mainClassName =
+ pm.mainClass() == null ? null : pm.mainClass().getClassName();
+
+ PlatformModule rm = (PlatformModule) Module.findModule(mn);
+ if (rm != null) {
+ if (pm.mainClass() != rm.mainClass()) {
+ // propagate the main class to its aggregator module
+ rm.setMainClass(mainClassName);
+ }
+ exporter = rm;
+ } else if (pm.hasPlatformAPIs()) {
ModuleConfig config = null;
try {
- config = new ModuleConfig(name, mainClass);
- return Module.addModule(config);
+ config = new ModuleConfig(mn, mainClassName);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
+ exporter = addPlatformModule(config);
}
- static boolean isAggregator(String name) {
- return name.equals(JDK_MODULE) ||
- name.equals(JRE_MODULE) ||
- name.equals(JDK_TOOLS) ||
- name.equals(JRE_TOOLS) ||
- name.equals(JDK_BASE_TOOLS) ||
- name.equals(LEGACY_MODULE) ||
- name.startsWith(JDK_LANGTOOLS);
+ if (pm != exporter) {
+ pm.reexportBy(exporter);
}
+ }
+ }
- // returns the module that is used by the requires statement
- // in other module's module-info
- static Module toRequiresModule(Module m) {
- Module moduleForRequires = m;
- if (m == bootModule()) {
- moduleForRequires = jdkBaseModule();
- } else if (m.name().startsWith("sun.")) {
- // create an aggregate module for each sun.* module
- String mn = m.name().replaceFirst("sun", "jdk");
- String mainClassName = m.mainClass() == null ? null : m.mainClass().getClassName();
+ // base module to reexport boot module
+ bootModule.reexportBy((PlatformModule) Module.findModule(BASE_MODULE));
- Module rm = findModule(mn);
- if (rm != null) {
- if (rm.mainClass() != m.mainClass()) {
- throw new RuntimeException(mn +
- " module already exists but mainClass not matched");
+ // set up the jdk, jdk.jre and jdk.legacy modules
+ for (Module m : Module.getAllModules()) {
+ if (m.isTopLevel()) {
+ PlatformModule pm = (PlatformModule) m;
+ String name = pm.name();
+ if (name.startsWith("jdk.") || name.startsWith("sun.")) {
+ if (pm != jdkModule && pm != jreModule) {
+ Module exp = pm.exporter(jdkModule);
+ // the "jdk" module requires all platform modules (public ones)
+ jdkModule.config().export(exp);
+ if (pm.isBootConnected() || pm == jreToolModule) {
+ // add all modules that are strongly connected to jdk.boot to JRE
+ jreModule.config().export(exp);
}
- return rm;
}
+ }
+ }
+ }
- if (m.hasPlatformAPIs()) {
- ModuleConfig config = null;
- try {
- config = new ModuleConfig(mn, mainClassName);
- } catch (IOException ex) {
- throw new RuntimeException(ex);
}
- moduleForRequires = Module.addModule(config);
- moduleForRequires.addRequiresModule(m);
+
+ /*
+ * Returns an ordered list of platform modules according to
+ * their dependencies with jdk.boot always be the first.
+ */
+ @Override
+ public Set<Module> getModules() {
+ Set<Module> modules = new LinkedHashSet<Module>();
+ // put the boot module first
+ modules.add(bootModule);
+ Module base = Module.findModule(BASE_MODULE);
+ modules.addAll(base.getModuleInfo().dependences(
+ new Dependence.Filter() {
+ @Override
+ public boolean accept(Dependence d) {
+ return !d.isOptional();
}
+ }));
+ modules.addAll(jdkModule.getModuleInfo().dependences(null));
+ for (Module m : Module.getAllModules()) {
+ if (m.isTopLevel() && !modules.contains(m)) {
+ modules.addAll(m.getModuleInfo().dependences(null));
}
- return moduleForRequires;
}
+ return modules;
+ }
- static void fixupPlatformModules() {
- // Create the full jdk and jre modules
- jdkModule = addPlatformModule(JDK_MODULE, null /* no main class */);
- jreModule = addPlatformModule(JRE_MODULE, null /* no main class */);
+ void readNonCorePackagesFrom(String nonCorePkgsFile) throws IOException {
+ PlatformPackage.addNonCorePkgs(nonCorePkgsFile);
+ }
- Module jreTools = findModule(JRE_TOOLS);
- Module jdkTools = findModule(JDK_TOOLS);
- Module jdkBaseTools = findModule(JDK_BASE_TOOLS);
+ private PlatformModule addPlatformModule(ModuleConfig config) {
+ PlatformModule m;
+ if (config.module.equals(BOOT_MODULE)) {
+ bootModule = new BootModule(config);
+ m = bootModule;
+ } else {
+ m = new PlatformModule(config);
+ }
+ Module.addModule(m);
+ return m;
+ }
- for (Module m : getTopLevelModules()) {
- String mn = m.name();
+ public class PlatformModule extends Module {
+ private Module exporter; // module that reexports this platform module
+ private String mainClass;
+ public PlatformModule(ModuleConfig config) {
+ super(config);
+ this.exporter = this;
+ this.mainClass = config.mainClass();
+ }
- // initialize module-info
- m.fixupModuleInfo();
+ // support for incremental build
+ // an aggregate module "jdk.*" is not defined in modules.config
+ // files but created by the platform module builder
+ // Set to the main class of sun.* module
+ void setMainClass(String classname) {
+ String mn = name();
+ if (!mn.startsWith("jdk") || !isEmpty()) {
+ throw new RuntimeException("module " + name() +
+ " not an aggregator");
+ }
- // set up the jdk, jdk.jre and jdk.legacy modules
- if (mn.startsWith("jdk.") || mn.startsWith("sun.")) {
- Module req = m.toRequiredModule();
+ if (classname == null)
+ throw new RuntimeException("Null main class for module " + name());
- if (!m.isAggregator() && !mn.equals(JDK_MODULE) && !mn.equals(JRE_MODULE)) {
- // all platform modules are required jdk module
- jdkModule.addRequiresModule(req);
- if (m.isBootConnected() || mn.equals(JRE_TOOLS)) {
- // add all modules that are strongly connected to jdk.boot to JRE
- jreModule.addRequiresModule(req);
+ mainClass = classname;
}
+
+ @Override
+ Klass mainClass() {
+ if (mainClass != null)
+ return Klass.findKlass(mainClass);
+ else
+ return null;
}
+
+ @Override
+ boolean allowEmpty() {
+ return this == jdkModule || this == jreModule || super.allowEmpty();
+ }
+
+ // requires local for JRE modules that are strongly
+ // connected with the boot module
+ boolean isBootConnected() {
+ // ## should it check for local?
+ return config().requires.containsKey(BOOT_MODULE);
+ }
+
+ private int platformAPIs;
+ boolean hasPlatformAPIs() {
+ platformAPIs = 0;
+ Visitor<Void, PlatformModule> v = new Visitor<Void, PlatformModule>() {
+ public Void visitClass(Klass k, PlatformModule pm) {
+ if (PlatformPackage.isOfficialClass(k.getClassName())) {
+ pm.platformAPIs++;
+ }
+ return null;
+ }
+
+ public Void visitResource(ResourceFile r, PlatformModule pm) {
+ return null;
+ }
+ };
+
+ this.visit(v, this);
+ return platformAPIs > 0;
+ }
+
+ // returns the module that is used by the requires statement
+ // in other module's module-info
+ @Override
+ public Module exporter(Module from) {
+ PlatformModule pm = (PlatformModule) from;
+ if (pm.isBootConnected()) {
+ // If it's a local module requiring jdk.boot, retain
+ // the original requires; otherwise, use its external
+ // module
+ return this;
} else {
- Trace.trace("Non-platform module: %s%n", m.name());
+ return exporter;
}
}
- // fixup the base module to include optional dependences from boot
- // ## It adds jndi, logging, and xml optional dependences
- // bootModule.fixupBase();
+
+ void reexportBy(PlatformModule pm) {
+ exporter = pm;
+ // sun.<m> permits jdk.<m>
+ this.config().addPermit(pm);
+ // jdk.<m> requires public sun.<m>;
+ pm.config().export(this);
}
+ }
+
+ public class BootModule extends PlatformModule {
+ BootModule(ModuleConfig config) {
+ super(config);
+ }
+
+ @Override
+ boolean isBootConnected() {
+ return true;
+ }
+ }
+
+ static class PlatformPackage {
+
private static String[] corePkgs = new String[]{
"java", "javax",
"org.omg", "org.w3c.dom",
"org.xml.sax", "org.ietf.jgss"
};
private static Set<String> nonCorePkgs = new TreeSet<String>();
- static void addNonCorePkgs(String file) throws FileNotFoundException, IOException {
+ static boolean isOfficialClass(String classname) {
+ for (String pkg : corePkgs) {
+ if (classname.startsWith(pkg + ".")) {
+ return true;
+ }
+ }
+
+ // TODO: include later
+ /*
+ for (String pkg : nonCorePkgs) {
+ if (classname.startsWith(pkg + ".")) {
+ return true;
+ }
+ }
+ */
+ return false;
+ }
+
+ // process a properties file listing the non core packages
+ static void addNonCorePkgs(String file) throws IOException {
File f = new File(file);
Properties props = new Properties();
BufferedReader reader = null;
try {
@@ -238,12 +398,12 @@
for (String v : ss) {
values.add(v.trim());
}
continue;
}
- if (pval.startsWith("java.") || pval.startsWith("javax") ||
- pval.startsWith("com.") || pval.startsWith("org.")) {
+ if (pval.startsWith("java.") || pval.startsWith("javax")
+ || pval.startsWith("com.") || pval.startsWith("org.")) {
nonCorePkgs.add(pval);
} else {
throw new RuntimeException("Invalid non core package: " + pval);
}
}
@@ -251,70 +411,7 @@
if (reader != null) {
reader.close();
}
}
}
-
- static boolean isPlatformAPI(String classname) {
- for (String pkg : corePkgs) {
- if (classname.startsWith(pkg + ".")) {
- return true;
}
- }
- return false;
- }
-
- static boolean isNonCoreAPI(String pkgName) {
- for (String pkg : nonCorePkgs) {
- if (pkgName.startsWith(pkg)) {
- return true;
- }
- }
- return false;
- }
-
- static class BootModule extends Module {
-
- BootModule(ModuleConfig config) {
- super(config);
- }
-
- Collection<Dependency> dependences() {
- Set<Dependency> result = new TreeSet<Dependency>();
- for (Dependency d : dependents()) {
- // filter out optional dependences from jdk.boot module
- if (!d.optional) {
- result.add(d);
- }
- }
- return result;
- }
-
- Module toRequiresModule() {
- return jdkBaseModule();
- }
-
- boolean isBootConnected() {
- return true;
- }
-
- boolean requirePermits() {
- return true;
- }
-
- void fixupBase() {
- // fixup jdk.boot optional dependences
- for (Dependency d : dependents()) {
- if (d.optional) {
- Module m = d.module().toRequiredModule();
- jdkBaseModule().addRequiresModule(m);
- Trace.trace("add requires %s to %s%n", m, jdkBaseModule().name());
- if (m != d.module()) {
- m.permits().remove(this);
- }
-
- }
- }
-
- }
- }
}