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