1 /*
  2  * Copyright (c) 2014, 2023, 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  * @bug 8060130
 27  * @requires vm.flagless
 28  * @library /test/lib
 29  * @build package2.Class2 GetSystemPackage
 30  * @summary Test if getSystemPackage() return consistent values for cases
 31  *          where a manifest is provided or not and ensure only jars on
 32  *          bootclasspath gets resolved via Package.getSystemPackage
 33  * @run main GetSystemPackage
 34  */
 35 
 36 import java.io.File;
 37 import java.io.FileInputStream;
 38 import java.io.FileNotFoundException;
 39 import java.io.FileOutputStream;
 40 import java.io.IOException;
 41 import java.util.jar.Attributes;
 42 import java.util.jar.JarEntry;
 43 import java.util.jar.JarOutputStream;
 44 import java.util.jar.Manifest;
 45 
 46 import jdk.test.lib.process.OutputAnalyzer;
 47 import jdk.test.lib.process.ProcessTools;
 48 
 49 public class GetSystemPackage {
 50 
 51     static final String testClassesDir = System.getProperty("test.classes", ".");
 52     static final File tmpFolder = new File(testClassesDir);
 53     static final String manifestTitle = "Special JAR";
 54 
 55     public static void main(String ... args) throws Exception {
 56         if (args.length == 0) {
 57             buildJarsAndInitiateSystemPackageTest();
 58             return;
 59         }
 60         switch (args[0]) {
 61             case "system-manifest":
 62                 verifyPackage(true, true);
 63                 break;
 64             case "system-no-manifest":
 65                 verifyPackage(false, true);
 66                 break;
 67             case "non-system-manifest":
 68                 verifyPackage(true, false);
 69                 break;
 70             case "non-system-no-manifest":
 71             default:
 72                 verifyPackage(false, false);
 73                 break;
 74         }
 75     }
 76 
 77     private static void buildJarsAndInitiateSystemPackageTest()
 78             throws Exception
 79     {
 80         Manifest m = new Manifest();
 81         // not setting MANIFEST_VERSION prevents META-INF/MANIFEST.MF from
 82         // getting written
 83         m.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
 84         m.getMainAttributes().put(Attributes.Name.SPECIFICATION_TITLE,
 85                                   manifestTitle);
 86 
 87         buildJar("manifest.jar", m);
 88         buildJar("no-manifest.jar", null);
 89 
 90         runSubProcess("System package with manifest improperly resolved.",
 91                 "-Xbootclasspath/a:" + testClassesDir + "/manifest.jar",
 92                 "GetSystemPackage", "system-manifest");
 93 
 94         runSubProcess("System package from directory improperly resolved.",
 95                 "-Xbootclasspath/a:" + testClassesDir, "GetSystemPackage",
 96                 "system-no-manifest");
 97 
 98         runSubProcess("System package with no manifest improperly resolved",
 99                 "-Xbootclasspath/a:" + testClassesDir + "/no-manifest.jar",
100                 "GetSystemPackage", "system-no-manifest");
101 
102         runSubProcess("Classpath package with manifest improperly resolved",
103                 "-cp", testClassesDir + "/manifest.jar", "GetSystemPackage",
104                 "non-system-manifest");
105 
106         runSubProcess("Classpath package with no manifest improperly resolved",
107                 "-cp", testClassesDir + "/no-manifest.jar", "GetSystemPackage",
108                 "non-system-no-manifest");
109 
110     }
111 
112     private static void buildJar(String name, Manifest man) throws Exception {
113         JarBuilder jar = new JarBuilder(tmpFolder, name, man);
114         jar.addClassFile("package2/Class2.class",
115                 testClassesDir + "/package2/Class2.class");
116         jar.addClassFile("GetSystemPackage.class",
117                 testClassesDir + "/GetSystemPackage.class");
118         jar.build();
119     }
120 
121     private static void runSubProcess(String messageOnError, String ... args)
122             throws Exception
123     {
124         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args)
125                                         .directory(tmpFolder);
126         int res = ProcessTools.executeProcess(pb).getExitValue();
127         if (res != 0) {
128             throw new RuntimeException(messageOnError);
129         }
130     }
131 
132     private static void verifyPackage(boolean hasManifest,
133                                       boolean isSystemPackage)
134             throws Exception
135     {
136         Class<?> c = Class.forName("package2.Class2");
137         Package pkg = c.getPackage();
138         if (pkg == null || pkg != Package.getPackage("package2") ||
139                 !"package2".equals(pkg.getName())) {
140             fail("package2 not found via Package.getPackage()");
141         }
142 
143         String specificationTitle = pkg.getSpecificationTitle();
144         if (!"package2".equals(pkg.getName())) {
145             fail("Invalid package for Class2");
146         }
147 
148         if (hasManifest && (specificationTitle == null
149                 || !manifestTitle.equals(specificationTitle))) {
150             fail("Invalid manifest for package " + pkg.getName());
151         }
152         if (!hasManifest && specificationTitle != null) {
153             fail("Invalid manifest for package " + pkg.getName() + ": was " +
154                     specificationTitle + " expected: null");
155         }
156 
157         ClassLoader ld = c.getClassLoader();
158         Package systemPkg = ld != null ? null : Package.getPackage("package2");
159 
160         if (findPackage("java.lang") == null) {
161             fail("java.lang not found via Package.getPackages()");
162         }
163         Package foundPackage = findPackage("package2");
164         if (isSystemPackage) {
165             if (systemPkg == null) {
166                 fail("System package could not be found via getSystemPackage");
167             }
168             if (foundPackage != systemPkg || systemPkg != pkg) {
169                 fail("Inconsistent package found via Package.getPackages()");
170             }
171         } else {
172             if (systemPkg != null) {
173                 fail("Non-system package could be found via getSystemPackage");
174             }
175             if (foundPackage == null) {
176                 fail("Non-system package not found via Package.getPackages()");
177             }
178         }
179     }
180 
181     private static Package findPackage(String name) {
182         Package[] packages = Package.getPackages();
183         for (Package p : packages) {
184             if (p.getName().equals(name)) {
185                 return p;
186             }
187         }
188         return null;
189     }
190 
191     private static void fail(String message) {
192         throw new RuntimeException(message);
193     }
194 }
195 
196 /*
197  * Helper class for building jar files
198  */
199 class JarBuilder {
200 
201     private JarOutputStream os;
202 
203     public JarBuilder(File tmpFolder, String jarName, Manifest manifest)
204             throws FileNotFoundException, IOException
205     {
206         File jarFile = new File(tmpFolder, jarName);
207         if (manifest != null) {
208             this.os = new JarOutputStream(new FileOutputStream(jarFile),
209                                           manifest);
210         } else {
211             this.os = new JarOutputStream(new FileOutputStream(jarFile));
212         }
213     }
214 
215     public void addClassFile(String pathFromRoot, String file)
216             throws IOException
217     {
218         byte[] buf = new byte[1024];
219         try (FileInputStream in = new FileInputStream(file)) {
220             JarEntry entry = new JarEntry(pathFromRoot);
221             os.putNextEntry(entry);
222             int len;
223             while ((len = in.read(buf)) > 0) {
224                 os.write(buf, 0, len);
225             }
226             os.closeEntry();
227         }
228     }
229 
230     public void build() throws IOException {
231         os.close();
232     }
233 }