1 /*
   2  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package com.sun.classanalyzer;
  24 
  25 import java.io.BufferedReader;
  26 import java.io.File;
  27 import java.io.FileNotFoundException;
  28 import java.io.FileReader;
  29 import java.io.IOException;
  30 
  31 import java.util.Collection;
  32 import java.util.Deque;
  33 import java.util.LinkedList;
  34 import java.util.Properties;
  35 import java.util.Set;
  36 import java.util.TreeSet;
  37 import static com.sun.classanalyzer.Module.*;
  38 
  39 /**
  40  * Platform module.
  41  *
  42  * The name of the platform modules starts with either "jdk." or "sun.".
  43  * All sun.* and jdk.boot are local modules.  Any requesting module
  44  * of a local module has to be explicitly permitted.
  45  *
  46  * The input module config files can define "sun.*" and "jdk.*"
  47  * modules.  For any sun.* module, it will have a corresponding
  48  * non-local platform module that is defined for application modules
  49  * to require.
  50  *
  51  * The tool will create the following platform modules:
  52  * 1) jdk.<name> for each sun.<name> module
  53  * 2) jdk module - represents the entire JDK
  54  * 3) jdk.jre module - represents the entire JRE
  55  *
  56  */
  57 public class Platform {
  58 
  59     static final String DEFAULT_BOOT_MODULE = "jdk.boot";
  60     static final String JDK_BASE_MODULE = "jdk.base";
  61     // platform modules created but not defined in the input module configs.
  62     static final String JDK_MODULE = "jdk";
  63     static final String JRE_MODULE = "jdk.jre";
  64     static final String LEGACY_MODULE = "jdk.legacy";
  65     // the following modules are expected to be defined in
  66     // the input module config files.
  67     static final String JDK_TOOLS = "jdk.tools";
  68     static final String JRE_TOOLS = "jdk.tools.jre";
  69     static final String JDK_BASE_TOOLS = "jdk.tools.base";
  70     static final String JDK_LANGTOOLS = "jdk.langtools";
  71 
  72     static boolean isBootModule(String name) {
  73         return name.equals(DEFAULT_BOOT_MODULE);
  74     }
  75     private static BootModule bootModule;
  76 
  77     static Module createBootModule(ModuleConfig config) {
  78         bootModule = new BootModule(config);
  79         return bootModule;
  80     }
  81 
  82     static Module bootModule() {
  83         return bootModule;
  84     }
  85     private static Module jdkBaseModule;
  86 
  87     static Module jdkBaseModule() {
  88         if (jdkBaseModule == null) {
  89             jdkBaseModule = findModule(JDK_BASE_MODULE);
  90         }
  91         return jdkBaseModule;
  92     }
  93     private static Module jdkBaseToolModule;
  94 
  95     static Module jdkBaseToolModule() {
  96         if (jdkBaseToolModule == null) {
  97             jdkBaseToolModule = findModule(JDK_BASE_TOOLS);
  98         }
  99         return jdkBaseToolModule;
 100     }
 101     private static Module jdkModule;
 102     private static Module jreModule;
 103     private static Module legacyModule;
 104 
 105     static Module jdkModule() {
 106         return jdkModule;
 107     }
 108 
 109     static Module jreModule() {
 110         return jreModule;
 111     }
 112 
 113     static Module legacyModule() {
 114         return legacyModule;
 115     }
 116 
 117     private static Module addPlatformModule(String name, String mainClass) {
 118         ModuleConfig config = null;
 119         try {
 120             config = new ModuleConfig(name, mainClass);
 121             return Module.addModule(config);
 122         } catch (IOException ex) {
 123             throw new RuntimeException(ex);
 124         }
 125     }
 126 
 127     static boolean isAggregator(String name) {
 128         return name.equals(JDK_MODULE) ||
 129                 name.equals(JRE_MODULE) ||
 130                 name.equals(JDK_TOOLS) ||
 131                 name.equals(JRE_TOOLS) ||
 132                 name.equals(JDK_BASE_TOOLS) ||
 133                 name.equals(LEGACY_MODULE) ||
 134                 name.startsWith(JDK_LANGTOOLS);
 135     }
 136 
 137     // returns the module that is used by the requires statement
 138     // in other module's module-info
 139     static Module toRequiresModule(Module m) {
 140         Module moduleForRequires = m;
 141         if (m == bootModule()) {
 142             moduleForRequires = jdkBaseModule();
 143         } else if (m.name().startsWith("sun.")) {
 144             // create an aggregate module for each sun.* module
 145             String mn = m.name().replaceFirst("sun", "jdk");
 146             String mainClassName = m.mainClass() == null ? null : m.mainClass().getClassName();
 147 
 148             Module rm = findModule(mn);
 149             if (rm != null) {
 150                 if (rm.mainClass() != m.mainClass()) {
 151                     throw new RuntimeException(mn +
 152                             " module already exists but mainClass not matched");
 153                 }
 154                 return rm;
 155             }
 156 
 157             if (m.hasPlatformAPIs()) {
 158                 ModuleConfig config = null;
 159                 try {
 160                     config = new ModuleConfig(mn, mainClassName);
 161                 } catch (IOException ex) {
 162                     throw new RuntimeException(ex);
 163                 }
 164                 moduleForRequires = Module.addModule(config);
 165                 moduleForRequires.addRequiresModule(m);
 166             }
 167         }
 168         return moduleForRequires;
 169     }
 170 
 171     static void fixupPlatformModules() {
 172         // Create the full jdk and jre modules
 173         jdkModule = addPlatformModule(JDK_MODULE, null /* no main class */);
 174         jreModule = addPlatformModule(JRE_MODULE, null /* no main class */);
 175 
 176         Module jreTools = findModule(JRE_TOOLS);
 177         Module jdkTools = findModule(JDK_TOOLS);
 178         Module jdkBaseTools = findModule(JDK_BASE_TOOLS);
 179 
 180         for (Module m : getTopLevelModules()) {
 181             String mn = m.name();
 182 
 183             // initialize module-info
 184             m.fixupModuleInfo();
 185 
 186             // set up the jdk, jdk.jre and jdk.legacy modules
 187             if (mn.startsWith("jdk.") || mn.startsWith("sun.")) {
 188                 Module req = m.toRequiredModule();
 189 
 190                 if (!m.isAggregator() && !mn.equals(JDK_MODULE) && !mn.equals(JRE_MODULE)) {
 191                     // all platform modules are required jdk module
 192                     jdkModule.addRequiresModule(req);
 193                     if (m.isBootConnected() || mn.equals(JRE_TOOLS)) {
 194                         // add all modules that are strongly connected to jdk.boot to JRE
 195                         jreModule.addRequiresModule(req);
 196                     }
 197                 }
 198             } else {
 199                 Trace.trace("Non-platform module: %s%n", m.name());
 200             }
 201         }
 202         // fixup the base module to include optional dependences from boot
 203         // ## It adds jndi, logging, and xml optional dependences
 204         // bootModule.fixupBase();
 205     }
 206     private static String[] corePkgs = new String[]{
 207         "java", "javax",
 208         "org.omg", "org.w3c.dom",
 209         "org.xml.sax", "org.ietf.jgss"
 210     };
 211     private static Set<String> nonCorePkgs = new TreeSet<String>();
 212 
 213     static void addNonCorePkgs(String file) throws FileNotFoundException, IOException {
 214         File f = new File(file);
 215         Properties props = new Properties();
 216         BufferedReader reader = null;
 217 
 218         try {
 219             reader = new BufferedReader(new FileReader(f));
 220             props.load(reader);
 221             String s = props.getProperty("NON_CORE_PKGS");
 222             String[] ss = s.split("\\s+");
 223             Deque<String> values = new LinkedList<String>();
 224 
 225             for (String v : ss) {
 226                 values.add(v.trim());
 227             }
 228 
 229             String pval;
 230             while ((pval = values.poll()) != null) {
 231                 if (pval.startsWith("$(") && pval.endsWith(")")) {
 232                     String key = pval.substring(2, pval.length() - 1);
 233                     String value = props.getProperty(key);
 234                     if (value == null) {
 235                         throw new RuntimeException("key " + key + " not found");
 236                     }
 237                     ss = value.split("\\s+");
 238                     for (String v : ss) {
 239                         values.add(v.trim());
 240                     }
 241                     continue;
 242                 }
 243                 if (pval.startsWith("java.") || pval.startsWith("javax") ||
 244                         pval.startsWith("com.") || pval.startsWith("org.")) {
 245                     nonCorePkgs.add(pval);
 246                 } else {
 247                     throw new RuntimeException("Invalid non core package: " + pval);
 248                 }
 249             }
 250         } finally {
 251             if (reader != null) {
 252                 reader.close();
 253             }
 254         }
 255     }
 256 
 257     static boolean isPlatformAPI(String classname) {
 258         for (String pkg : corePkgs) {
 259             if (classname.startsWith(pkg + ".")) {
 260                 return true;
 261             }
 262         }
 263         return false;
 264     }
 265 
 266     static boolean isNonCoreAPI(String pkgName) {
 267         for (String pkg : nonCorePkgs) {
 268             if (pkgName.startsWith(pkg)) {
 269                 return true;
 270             }
 271         }
 272         return false;
 273     }
 274 
 275     static class BootModule extends Module {
 276 
 277         BootModule(ModuleConfig config) {
 278             super(config);
 279         }
 280 
 281         Collection<Dependency> dependences() {
 282             Set<Dependency> result = new TreeSet<Dependency>();
 283             for (Dependency d : dependents()) {
 284                 // filter out optional dependences from jdk.boot module
 285                 if (!d.optional) {
 286                     result.add(d);
 287                 }
 288             }
 289             return result;
 290         }
 291 
 292         Module toRequiresModule() {
 293             return jdkBaseModule();
 294         }
 295 
 296         boolean isBootConnected() {
 297             return true;
 298         }
 299 
 300         boolean requirePermits() {
 301             return true;
 302         }
 303 
 304         void fixupBase() {
 305             // fixup jdk.boot optional dependences
 306             for (Dependency d : dependents()) {
 307                 if (d.optional) {
 308                     Module m = d.module().toRequiredModule();
 309                     jdkBaseModule().addRequiresModule(m);
 310                     Trace.trace("add requires %s to %s%n", m, jdkBaseModule().name());
 311                     if (m != d.module()) {
 312                         m.permits().remove(this);
 313                     }
 314 
 315                 }
 316             }
 317 
 318         }
 319     }
 320 }