1 /* 2 * Copyright (c) 2016, 2018, 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 * @requires vm.cds & !vm.graal.enabled 27 * @summary Testing -Xbootclasspath/a support for CDS 28 * @requires vm.cds 29 * @library /test/lib 30 * @modules java.base/jdk.internal.misc 31 * java.management 32 * jdk.internal.jvmstat/sun.jvmstat.monitor 33 * @compile javax/sound/sampled/MyClass.jasm 34 * @compile javax/annotation/processing/FilerException.jasm 35 * @compile nonjdk/myPackage/MyClass.java 36 * @build LoadClass 37 * @run main/othervm BootAppendTests 38 */ 39 40 import java.io.File; 41 import java.io.FileOutputStream; 42 import java.io.IOException; 43 import java.io.PrintStream; 44 45 import java.nio.file.Path; 46 import java.nio.file.Paths; 47 48 import jdk.test.lib.cds.CDSOptions; 49 import jdk.test.lib.cds.CDSTestUtils; 50 import jdk.test.lib.process.ProcessTools; 51 import jdk.test.lib.process.OutputAnalyzer; 52 53 public class BootAppendTests { 54 private static final String APP_CLASS = "LoadClass"; 55 private static final String BOOT_APPEND_MODULE_CLASS = "javax/sound/sampled/MyClass"; 56 private static final String BOOT_APPEND_DUPLICATE_MODULE_CLASS = 57 "javax/annotation/processing/FilerException"; 58 private static final String BOOT_APPEND_CLASS = "nonjdk/myPackage/MyClass"; 59 private static final String BOOT_APPEND_MODULE_CLASS_NAME = 60 BOOT_APPEND_MODULE_CLASS.replace('/', '.'); 61 private static final String BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME = 62 BOOT_APPEND_DUPLICATE_MODULE_CLASS.replace('/', '.'); 63 private static final String BOOT_APPEND_CLASS_NAME = 64 BOOT_APPEND_CLASS.replace('/', '.'); 65 private static final String[] ARCHIVE_CLASSES = 66 {BOOT_APPEND_MODULE_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS, BOOT_APPEND_CLASS}; 67 68 private static final String modes[] = {"on", "off"}; 69 70 private static String appJar; 71 private static String bootAppendJar; 72 73 public static void main(String... args) throws Exception { 74 dumpArchive(); 75 76 logTestCase("1"); 77 testBootAppendModuleClass(); 78 79 logTestCase("2"); 80 testBootAppendDuplicateModuleClass(); 81 82 logTestCase("3"); 83 testBootAppendExcludedModuleClass(); 84 85 logTestCase("4"); 86 testBootAppendDuplicateExcludedModuleClass(); 87 88 logTestCase("5"); 89 testBootAppendClass(); 90 91 logTestCase("6"); 92 testBootAppendExtraDir(); 93 } 94 95 private static void logTestCase(String msg) { 96 System.out.println(); 97 System.out.printf("TESTCASE: %s", msg); 98 System.out.println(); 99 } 100 101 static void dumpArchive() throws Exception { 102 // create the classlist 103 File classlist = CDSTestUtils.makeClassList(ARCHIVE_CLASSES); 104 105 // build jar files 106 appJar = ClassFileInstaller.writeJar("app.jar", APP_CLASS); 107 bootAppendJar = ClassFileInstaller.writeJar("bootAppend.jar", 108 BOOT_APPEND_MODULE_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS, BOOT_APPEND_CLASS); 109 110 111 OutputAnalyzer out = CDSTestUtils.createArchiveAndCheck( 112 "-Xbootclasspath/a:" + bootAppendJar, 113 "-XX:SharedClassListFile=" + classlist.getPath()); 114 // Make sure all the classes were successfully archived. 115 for (String archiveClass : ARCHIVE_CLASSES) { 116 out.shouldNotContain("Preload Warning: Cannot find " + archiveClass); 117 } 118 } 119 120 // Test #1: If a class on -Xbootclasspath/a is from a package defined in 121 // bootmodules, the class is not loaded at runtime. 122 // Verify the behavior is the same when the class is archived 123 // with CDS enabled at runtime. 124 // 125 // The javax.sound.sampled package is defined in the java.desktop module. 126 // The archived javax.sound.sampled.MyClass from the -Xbootclasspath/a 127 // should not be loaded at runtime. 128 public static void testBootAppendModuleClass() throws Exception { 129 for (String mode : modes) { 130 CDSOptions opts = (new CDSOptions()) 131 .setXShareMode(mode).setUseVersion(false) 132 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar, "-showversion") 133 .addSuffix(APP_CLASS, BOOT_APPEND_MODULE_CLASS_NAME); 134 135 OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); 136 CDSTestUtils.checkExec(out, opts, "java.lang.ClassNotFoundException: javax.sound.sampled.MyClass"); 137 } 138 } 139 140 // Test #2: If a class on -Xbootclasspath/a has the same fully qualified 141 // name as a class defined in boot modules, the class is not loaded 142 // from -Xbootclasspath/a. Verify the behavior is the same at runtime 143 // when CDS is enabled. 144 // 145 // The javax/annotation/processing/FilerException is a platform module 146 // class. The class on the -Xbootclasspath/a path that has the same 147 // fully-qualified name should not be loaded at runtime when CDS is enabled. 148 // The one from the platform modules should be loaded instead. 149 public static void testBootAppendDuplicateModuleClass() throws Exception { 150 for (String mode : modes) { 151 CDSOptions opts = (new CDSOptions()) 152 .setXShareMode(mode).setUseVersion(false) 153 .addPrefix("-showversion", 154 "-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar) 155 .addSuffix("-Xlog:class+load=info", 156 APP_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); 157 158 OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); 159 CDSTestUtils.checkExec(out, opts, "[class,load] javax.annotation.processing.FilerException source: jrt:/java.compiler"); 160 } 161 } 162 163 // Test #3: If a class on -Xbootclasspath/a is from a package defined in boot modules, 164 // the class can be loaded from -Xbootclasspath/a when the module is excluded 165 // using --limit-modules. Verify the behavior is the same at runtime when CDS 166 // is enabled. 167 // 168 // The java.desktop module is excluded using --limit-modules at runtime 169 // CDS will be disabled with the --limit-modules option during runtime. 170 // javax.sound.sampled.MyClass will be loaded from the jar at runtime. 171 public static void testBootAppendExcludedModuleClass() throws Exception { 172 for (String mode : modes) { 173 CDSOptions opts = (new CDSOptions()) 174 .setXShareMode(mode).setUseVersion(false) 175 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-showversion", 176 "--limit-modules=java.base", "-cp", appJar) 177 .addSuffix("-Xlog:class+load=info", 178 APP_CLASS, BOOT_APPEND_MODULE_CLASS_NAME); 179 CDSTestUtils.Result res = CDSTestUtils.run(opts); 180 String MATCH_PATTERN = 181 ".class.load. javax.sound.sampled.MyClass source:.*bootAppend.jar*"; 182 if (mode.equals("on")) { 183 res.assertSilentlyDisabledCDS(out -> { 184 out.shouldHaveExitValue(0) 185 .shouldMatch(MATCH_PATTERN); 186 }); 187 } else { 188 res.assertNormalExit(out -> { 189 out.shouldMatch(MATCH_PATTERN); 190 }); 191 } 192 } 193 } 194 195 // Test #4: If a class on -Xbootclasspath/a has the same fully qualified 196 // name as a class defined in boot modules, the class is loaded 197 // from -Xbootclasspath/a when the boot module is excluded using 198 // --limit-modules. Verify the behavior is the same at runtime 199 // when CDS is enabled. 200 // 201 // The javax.annotation.processing.FilerException is a platform module class. 202 // The class on -Xbootclasspath/a that has the same fully-qualified name 203 // as javax.annotation.processing.FilerException can be loaded at runtime when 204 // java.compiler is excluded. 205 // CDS is disabled during runtime if the --limit-modules option is 206 // specified. 207 public static void testBootAppendDuplicateExcludedModuleClass() throws Exception { 208 for (String mode : modes) { 209 CDSOptions opts = (new CDSOptions()) 210 .setXShareMode(mode).setUseVersion(false) 211 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-showversion", 212 "--limit-modules=java.base", "-cp", appJar) 213 .addSuffix("-Xlog:class+load=info", 214 APP_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); 215 216 CDSTestUtils.Result res = CDSTestUtils.run(opts); 217 String MATCH_PATTERN = 218 ".class.load. javax.annotation.processing.FilerException source:.*bootAppend.jar*"; 219 if (mode.equals("on")) { 220 res.assertSilentlyDisabledCDS(out -> { 221 out.shouldHaveExitValue(0) 222 .shouldMatch(MATCH_PATTERN); 223 }); 224 } else { 225 res.assertNormalExit(out -> { 226 out.shouldMatch(MATCH_PATTERN); 227 }); 228 } 229 } 230 } 231 232 // Test #5: If a class on -Xbootclasspath/a is not from named modules, 233 // the class can be loaded at runtime. Verify the behavior is 234 // the same at runtime when CDS is enabled. 235 // 236 // The nonjdk.myPackage is not defined in named modules. The 237 // nonjdk.myPackage.MyClass will be loaded from the jar in 238 // -Xbootclasspath/a since CDS will be disabled with the 239 // --limit-modules option. 240 public static void testBootAppendClass() throws Exception { 241 for (String mode : modes) { 242 CDSOptions opts = (new CDSOptions()) 243 .setXShareMode(mode).setUseVersion(false) 244 .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-showversion", 245 "--limit-modules=java.base", "-cp", appJar) 246 .addSuffix("-Xlog:class+load=info", 247 APP_CLASS, BOOT_APPEND_CLASS_NAME); 248 249 CDSTestUtils.Result res = CDSTestUtils.run(opts); 250 String MATCH_PATTERN = 251 ".class.load. nonjdk.myPackage.MyClass source:.*bootAppend.jar*"; 252 if (mode.equals("on")) { 253 res.assertSilentlyDisabledCDS(out -> { 254 out.shouldHaveExitValue(0) 255 .shouldMatch(MATCH_PATTERN); 256 }); 257 } else { 258 res.assertNormalExit(out -> { 259 out.shouldMatch(MATCH_PATTERN); 260 }); 261 } 262 } 263 } 264 265 // Test #6: This is similar to Test #5. During runtime, an extra dir 266 // is appended to the bootclasspath. It should not invalidate 267 // the shared archive. However, CDS will be disabled with the 268 // --limit-modules in the command line. 269 public static void testBootAppendExtraDir() throws Exception { 270 for (String mode : modes) { 271 CDSOptions opts = (new CDSOptions()) 272 .setXShareMode(mode).setUseVersion(false) 273 .addPrefix("-Xbootclasspath/a:" + bootAppendJar + File.pathSeparator + appJar, 274 "-showversion", "--limit-modules=java.base", "-cp", appJar) 275 .addSuffix("-Xlog:class+load=info", 276 APP_CLASS, BOOT_APPEND_CLASS_NAME); 277 278 CDSTestUtils.Result res = CDSTestUtils.run(opts); 279 String MATCH_PATTERN = 280 ".class.load. nonjdk.myPackage.MyClass source:.*bootAppend.jar*"; 281 if (mode.equals("on")) { 282 res.assertSilentlyDisabledCDS(out -> { 283 out.shouldHaveExitValue(0) 284 .shouldMatch(MATCH_PATTERN); 285 }); 286 } else { 287 res.assertNormalExit(out -> { 288 out.shouldMatch(MATCH_PATTERN); 289 }); 290 } 291 } 292 } 293 }