1 /*
  2  * Copyright (c) 2014, 2020, 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 /*
 26  * @test
 27  * @summary Class-Path: attribute in MANIFEST file
 28  * @requires vm.cds
 29  * @library /test/lib
 30  * @run driver/timeout=240 ClassPathAttr
 31  */
 32 
 33 import jdk.test.lib.cds.CDSTestUtils;
 34 import jdk.test.lib.process.OutputAnalyzer;
 35 import java.io.File;
 36 import java.nio.file.Files;
 37 import java.nio.file.FileAlreadyExistsException;
 38 import java.nio.file.StandardCopyOption;
 39 import java.nio.file.Paths;
 40 
 41 
 42 public class ClassPathAttr {
 43 
 44   public static void main(String[] args) throws Exception {
 45     testNormalOps();
 46     testNonExistentJars();
 47   }
 48 
 49   static void testNormalOps() throws Exception {
 50     buildCpAttr("cpattr1", "cpattr1.mf", "CpAttr1", "CpAttr1");
 51     buildCpAttr("cpattr1_long", "cpattr1_long.mf", "CpAttr1", "CpAttr1");
 52     buildCpAttr("cpattr2", "cpattr2.mf", "CpAttr2", "CpAttr2");
 53     buildCpAttr("cpattr3", "cpattr3.mf", "CpAttr3", "CpAttr2", "CpAttr3");
 54     buildCpAttr("cpattr4", "cpattr4.mf", "CpAttr4",
 55         "CpAttr2", "CpAttr3", "CpAttr4", "CpAttr5");
 56     buildCpAttr("cpattr5_123456789_223456789_323456789_423456789_523456789_623456789", "cpattr5_extra_long.mf", "CpAttr5", "CpAttr5");
 57 
 58     String[] classlist = { "CpAttr1", "CpAttr2", "CpAttr3", "CpAttr4", "CpAttr5"};
 59     String jar4 = TestCommon.getTestJar("cpattr4.jar");
 60     for (int i=1; i<=2; i++) {
 61       String jar1 = TestCommon.getTestJar("cpattr1.jar");
 62       if (i == 2) {
 63         // Test case #2 -- same as #1, except we use cpattr1_long.jar, which has a super-long
 64         // Class-Path: attribute.
 65         jar1 = TestCommon.getTestJar("cpattr1_long.jar");
 66       }
 67       String cp = jar1 + File.pathSeparator + jar4;
 68 
 69       TestCommon.testDump(cp, classlist);
 70 
 71       TestCommon.run(
 72           "-cp", cp,
 73           "CpAttr1")
 74         .assertNormalExit();
 75 
 76       // Logging test for class+path.
 77       TestCommon.run(
 78           "-Xlog:class+path",
 79           "-cp", cp,
 80           "CpAttr1")
 81         .assertNormalExit(output -> {
 82             output.shouldMatch("checking shared classpath entry: .*cpattr2.jar");
 83             output.shouldMatch("checking shared classpath entry: .*cpattr3.jar");
 84           });
 85     }
 86 
 87     // test duplicate jars in the "Class-path" attribute in the jar manifest
 88     buildCpAttr("cpattr_dup", "cpattr_dup.mf", "CpAttr1", "CpAttr1");
 89     String cp = TestCommon.getTestJar("cpattr_dup.jar") + File.pathSeparator + jar4;
 90     TestCommon.testDump(cp, classlist);
 91 
 92     TestCommon.run(
 93         "-cp", cp,
 94         "CpAttr1")
 95       .assertNormalExit();
 96   }
 97 
 98   static void testNonExistentJars() throws Exception {
 99     buildCpAttr("cpattr6", "cpattr6.mf", "CpAttr6", "CpAttr6");
100 
101     String cp = TestCommon.getTestJar("cpattr6.jar");
102     String nonExistPath = CDSTestUtils.getOutputDir() + File.separator + "cpattrX.jar";
103     (new File(nonExistPath)).delete();
104 
105     TestCommon.testDump(cp, TestCommon.list("CpAttr6"),
106         "-Xlog:class+path");
107 
108     TestCommon.run(
109         "-Xlog:class+path",
110         "-cp", cp,
111         "CpAttr6")
112       .assertNormalExit(output -> {
113           output.shouldMatch("should be non-existent: .*cpattrX.jar");
114         });
115 
116     // Now make nonExistPath exist. CDS still loads, but archived non-system classes will not be used.
117     Files.copy(Paths.get(cp), Paths.get(nonExistPath),
118                StandardCopyOption.REPLACE_EXISTING);
119 
120     TestCommon.run(
121         "-Xlog:class+path",
122         "-cp", cp,
123         "CpAttr6")
124       .assertNormalExit(output -> {
125           output.shouldMatch("Archived non-system classes are disabled because the file .*cpattrX.jar exists");
126         });
127   }
128 
129   private static void buildCpAttr(String jarName, String manifest, String enclosingClassName, String ...testClassNames) throws Exception {
130     String jarClassesDir = CDSTestUtils.getOutputDir() + File.separator + jarName + "_classes";
131     try { Files.createDirectory(Paths.get(jarClassesDir)); } catch (FileAlreadyExistsException e) { }
132 
133     JarBuilder.compile(jarClassesDir, System.getProperty("test.src") + File.separator +
134         "test-classes" + File.separator + enclosingClassName + ".java");
135     JarBuilder.buildWithManifest(jarName, manifest, jarClassesDir, testClassNames);
136   }
137 }