1 /* 2 * Copyright (c) 2016, 2017, 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 24 /** 25 * @test 26 * @summary Testing -Xbootclasspath/a support for CDS 27 * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true) 28 * @library /test/lib 29 * @modules java.base/jdk.internal.misc 30 * java.management 31 * jdk.internal.jvmstat/sun.jvmstat.monitor 32 * @compile javax/sound/sampled/MyClass.jasm 33 * @compile org/omg/CORBA/Context.jasm 34 * @compile nonjdk/myPackage/MyClass.java 35 * @build LoadClass 36 * @run main/othervm BootAppendTests 37 */ 38 39 import java.io.File; 40 import java.io.FileOutputStream; 41 import java.io.IOException; 42 import java.io.PrintStream; 43 44 import java.nio.file.Path; 45 import java.nio.file.Paths; 46 47 import jdk.test.lib.cds.CDSOptions; 48 import jdk.test.lib.cds.CDSTestUtils; 49 import jdk.test.lib.process.ProcessTools; 50 import jdk.test.lib.process.OutputAnalyzer; 51 52 public class BootAppendTests { 53 private static final String APP_CLASS = "LoadClass"; 54 private static final String BOOT_APPEND_MODULE_CLASS = "javax/sound/sampled/MyClass"; 55 private static final String BOOT_APPEND_DUPLICATE_MODULE_CLASS = "org/omg/CORBA/Context"; 56 private static final String BOOT_APPEND_CLASS = "nonjdk/myPackage/MyClass"; 57 private static final String BOOT_APPEND_MODULE_CLASS_NAME = 58 BOOT_APPEND_MODULE_CLASS.replace('/', '.'); 59 private static final String BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME = 60 BOOT_APPEND_DUPLICATE_MODULE_CLASS.replace('/', '.'); 61 private static final String BOOT_APPEND_CLASS_NAME = 62 BOOT_APPEND_CLASS.replace('/', '.'); 63 private static final String[] ARCHIVE_CLASSES = 64 {BOOT_APPEND_MODULE_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS, BOOT_APPEND_CLASS}; 65 66 private static final String modes[] = {"on", "off"}; 67 68 private static String appJar; 69 private static String bootAppendJar; 70 71 public static void main(String... args) throws Exception { 72 dumpArchive(); 73 74 logTestCase("1"); 75 testBootAppendModuleClass(); 76 77 logTestCase("2"); 78 testBootAppendDuplicateModuleClass(); 79 80 logTestCase("3"); 81 testBootAppendExcludedModuleClass(); 82 83 logTestCase("4"); 84 testBootAppendDuplicateExcludedModuleClass(); 85 86 logTestCase("5"); 87 testBootAppendClass(); 88 } 89 90 private static void logTestCase(String msg) { 91 System.out.println(); 92 System.out.printf("TESTCASE: %s", msg); 93 System.out.println(); 94 } 95 96 static void dumpArchive() throws Exception { 97 // create the classlist 98 File classlist = CDSTestUtils.makeClassList(ARCHIVE_CLASSES); 99 100 // build jar files 101 appJar = ClassFileInstaller.writeJar("app.jar", APP_CLASS); 102 bootAppendJar = ClassFileInstaller.writeJar("bootAppend.jar", 103 BOOT_APPEND_MODULE_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS, BOOT_APPEND_CLASS); 104 105 106 OutputAnalyzer out = CDSTestUtils.createArchiveAndCheck( 107 "-Xbootclasspath/a:" + bootAppendJar, 108 "-XX:SharedClassListFile=" + classlist.getPath()); 109 // Make sure all the classes were successfully archived. 110 for (String archiveClass : ARCHIVE_CLASSES) { 111 out.shouldNotContain("Preload Warning: Cannot find " + archiveClass); 112 } 113 } 114 115 // Test #1: If a class on -Xbootclasspath/a is from a package defined in 116 // bootmodules, the class is not loaded at runtime. 117 // Verify the behavior is the same when the class is archived 118 // with CDS enabled at runtime. 119 // 120 // The javax.sound.sampled package is defined in the java.desktop module. 121 // The archived javax.sound.sampled.MyClass from the -Xbootclasspath/a 122 // should not be loaded at runtime. 123 public static void testBootAppendModuleClass() throws Exception { 124 for (String mode : modes) { 125 CDSOptions opts = (new CDSOptions()) 126 .setXShareMode(mode).setUseVersion(false) 127 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar, "-showversion") 128 .addSuffix(APP_CLASS, BOOT_APPEND_MODULE_CLASS_NAME); 129 130 OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); 131 CDSTestUtils.checkExec(out, opts, "java.lang.ClassNotFoundException: javax.sound.sampled.MyClass"); 132 } 133 } 134 135 // Test #2: If a class on -Xbootclasspath/a has the same fully qualified 136 // name as a class defined in boot modules, the class is not loaded 137 // from -Xbootclasspath/a. Verify the behavior is the same at runtime 138 // when CDS is enabled. 139 // 140 // The org.omg.CORBA.Context is a boot module class. The class on 141 // the -Xbootclasspath/a path that has the same fully-qualified name 142 // should not be loaded at runtime when CDS is enabled. 143 // The one from the boot modules should be loaded instead. 144 public static void testBootAppendDuplicateModuleClass() throws Exception { 145 for (String mode : modes) { 146 CDSOptions opts = (new CDSOptions()) 147 .setXShareMode(mode).setUseVersion(false) 148 .addPrefix("--add-modules", "java.corba", "-showversion", 149 "-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar) 150 .addSuffix("-Xlog:class+load=info", 151 APP_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); 152 153 OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); 154 CDSTestUtils.checkExec(out, opts, "[class,load] org.omg.CORBA.Context source: jrt:/java.corba"); 155 } 156 } 157 158 // Test #3: If a class on -Xbootclasspath/a is from a package defined in boot modules, 159 // the class can be loaded from -Xbootclasspath/a when the module is excluded 160 // using --limit-modules. Verify the behavior is the same at runtime when CDS 161 // is enabled. 162 // 163 // The java.desktop module is excluded using --limit-modules at runtime, 164 // javax.sound.sampled.MyClass is archived from -Xbootclasspath/a. It can be 165 // loaded from the archive at runtime. 166 public static void testBootAppendExcludedModuleClass() throws Exception { 167 for (String mode : modes) { 168 CDSOptions opts = (new CDSOptions()) 169 .setXShareMode(mode).setUseVersion(false) 170 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-showversion", 171 "--limit-modules=java.base", "-cp", appJar) 172 .addSuffix("-Xlog:class+load=info", 173 APP_CLASS, BOOT_APPEND_MODULE_CLASS_NAME); 174 175 OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); 176 CDSTestUtils.checkExec(out, opts, "[class,load] javax.sound.sampled.MyClass"); 177 178 // When CDS is enabled, the shared class should be loaded from the archive. 179 if (mode.equals("on")) { 180 CDSTestUtils.checkExec(out, opts, "[class,load] javax.sound.sampled.MyClass source: shared objects file"); 181 } 182 } 183 } 184 185 // Test #4: If a class on -Xbootclasspath/a has the same fully qualified 186 // name as a class defined in boot modules, the class is loaded 187 // from -Xbootclasspath/a when the boot module is excluded using 188 // --limit-modules. Verify the behavior is the same at runtime 189 // when CDS is enabled. 190 // 191 // The org.omg.CORBA.Context is a boot module class. The class 192 // on -Xbootclasspath/a that has the same fully-qualified name 193 // as org.omg.CORBA.Context can be loaded at runtime when 194 // java.corba is excluded. 195 public static void testBootAppendDuplicateExcludedModuleClass() throws Exception { 196 for (String mode : modes) { 197 CDSOptions opts = (new CDSOptions()) 198 .setXShareMode(mode).setUseVersion(false) 199 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-showversion", 200 "--limit-modules=java.base", "-cp", appJar) 201 .addSuffix("-Xlog:class+load=info", 202 APP_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); 203 204 OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); 205 CDSTestUtils.checkExec(out, opts, "[class,load] org.omg.CORBA.Context"); 206 if (!CDSTestUtils.isUnableToMap(out)) { 207 out.shouldMatch(".*\\[class,load\\] org.omg.CORBA.Context source:.*bootAppend.jar"); 208 } 209 } 210 } 211 212 // Test #5: If a class on -Xbootclasspath/a is not from named modules, 213 // the class can be loaded at runtime. Verify the behavior is 214 // the same at runtime when CDS is enabled. 215 // 216 // The nonjdk.myPackage is not defined in named modules. The 217 // archived nonjdk.myPackage.MyClass from -Xbootclasspath/a 218 // can be loaded at runtime when CDS is enabled. 219 public static void testBootAppendClass() throws Exception { 220 for (String mode : modes) { 221 CDSOptions opts = (new CDSOptions()) 222 .setXShareMode(mode).setUseVersion(false) 223 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-showversion", 224 "--limit-modules=java.base", "-cp", appJar) 225 .addSuffix("-Xlog:class+load=info", 226 APP_CLASS, BOOT_APPEND_CLASS_NAME); 227 228 OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); 229 CDSTestUtils.checkExec(out, opts, "[class,load] nonjdk.myPackage.MyClass"); 230 231 // If CDS is enabled, the nonjdk.myPackage.MyClass should be loaded 232 // from the shared archive. 233 if (mode.equals("on")) { 234 CDSTestUtils.checkExec(out, opts, 235 "[class,load] nonjdk.myPackage.MyClass source: shared objects file"); 236 } 237 } 238 } 239 }