1 /* 2 * Copyright (c) 2012, 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 8003255 27 * @compile -XDignore.symbol.file Basic.java Main.java Logging.java 28 * @run main Basic 29 * @summary Test the launcher checks the Profile attribute of executable JAR 30 * files. Also checks that libraries that specify the Profile attribute 31 * are not loaded if the runtime does not support the required profile. 32 */ 33 34 import java.io.*; 35 import java.util.jar.*; 36 import static java.util.jar.JarFile.MANIFEST_NAME; 37 import java.util.zip.*; 38 import java.nio.file.*; 39 import java.nio.file.attribute.BasicFileAttributes; 40 41 public class Basic { 42 43 static final String MANIFEST_DIR = "META-INF/"; 44 45 static final String JAVA_HOME = System.getProperty("java.home"); 46 static final String OS_NAME = System.getProperty("os.name"); 47 static final String OS_ARCH = System.getProperty("os.arch"); 48 49 static final String JAVA_CMD = 50 OS_NAME.startsWith("Windows") ? "java.exe" : "java"; 51 52 static final boolean NEED_D64 = 53 OS_NAME.equals("SunOS") && 54 (OS_ARCH.equals("sparcv9") || OS_ARCH.equals("amd64")); 55 56 /** 57 * Creates a JAR file with the given attributes and the given entries. 58 * Class files are assumed to be in ${test.classes}. Note that this this 59 * method cannot use the "jar" tool as it may not be present in the image. 60 */ 61 static void createJarFile(String jarfile, 62 String mainAttributes, 63 String... entries) 64 throws IOException 65 { 66 // create Manifest 67 Manifest manifest = new Manifest(); 68 Attributes jarAttrs = manifest.getMainAttributes(); 69 jarAttrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); 70 if (mainAttributes.length() > 0) { 71 for (String attr: mainAttributes.split(",")) { 72 String[] s = attr.split("="); 73 jarAttrs.put(new Attributes.Name(s[0]), s[1]); 74 } 75 } 76 77 try (OutputStream out = Files.newOutputStream(Paths.get(jarfile)); 78 ZipOutputStream zos = new JarOutputStream(out)) 79 { 80 // add manifest directory and manifest file 81 ZipEntry e = new JarEntry(MANIFEST_DIR); 82 e.setTime(System.currentTimeMillis()); 83 e.setSize(0); 84 e.setCrc(0); 85 zos.putNextEntry(e); 86 e = new ZipEntry(MANIFEST_NAME); 87 e.setTime(System.currentTimeMillis()); 88 zos.putNextEntry(e); 89 manifest.write(zos); 90 zos.closeEntry(); 91 92 // entries in JAR file 93 for (String entry: entries) { 94 e = new JarEntry(entry); 95 Path path; 96 if (entry.endsWith(".class")) { 97 path = Paths.get(System.getProperty("test.classes"), entry); 98 } else { 99 path = Paths.get(entry); 100 } 101 BasicFileAttributes attrs = 102 Files.readAttributes(path, BasicFileAttributes.class); 103 e.setTime(attrs.lastModifiedTime().toMillis()); 104 if (attrs.size() == 0) { 105 e.setMethod(ZipEntry.STORED); 106 e.setSize(0); 107 e.setCrc(0); 108 } 109 zos.putNextEntry(e); 110 if (attrs.isRegularFile()) 111 Files.copy(path, zos); 112 zos.closeEntry(); 113 } 114 } 115 } 116 117 /** 118 * Execute the given executable JAR file with the given arguments. This 119 * method blocks until the launched VM terminates. Any output or error 120 * message from the launched VM are printed to System.out. Returns the 121 * exit value. 122 */ 123 static int exec(String jf, String... args) throws IOException { 124 StringBuilder sb = new StringBuilder(); 125 sb.append(Paths.get(JAVA_HOME, "bin", JAVA_CMD).toString()); 126 if (NEED_D64) 127 sb.append(" -d64"); 128 sb.append(" -jar "); 129 sb.append(Paths.get(jf).toAbsolutePath()); 130 for (String arg: args) { 131 sb.append(' '); 132 sb.append(arg); 133 } 134 String[] cmd = sb.toString().split(" "); 135 ProcessBuilder pb = new ProcessBuilder(cmd); 136 pb.redirectErrorStream(true); 137 Process p = pb.start(); 138 BufferedReader reader = 139 new BufferedReader(new InputStreamReader(p.getInputStream())); 140 String line; 141 while ((line = reader.readLine()) != null) { 142 System.out.println(line); 143 } 144 try { 145 return p.waitFor(); 146 } catch (InterruptedException e) { 147 throw new RuntimeException("Should not happen"); 148 } 149 } 150 151 static void checkRun(String jf, String... args) throws IOException { 152 if (exec(jf) != 0) 153 throw new RuntimeException(jf + " failed!!!"); 154 } 155 156 static void checkRunFail(String jf, String... args) throws IOException { 157 if (exec(jf) == 0) 158 throw new RuntimeException(jf + " did not fail!!!"); 159 System.out.println("Failed as expected"); 160 } 161 162 public static void main(String[] args) throws IOException { 163 // ## replace this if there is a standard way to determine the profile 164 String profile = sun.misc.Version.profileName(); 165 166 int thisProfile = 4; 167 if ("compact1".equals(profile)) thisProfile = 1; 168 if ("compact2".equals(profile)) thisProfile = 2; 169 if ("compact3".equals(profile)) thisProfile = 3; 170 171 // "library" JAR file used by the test 172 createJarFile("Logging.jar", "", "Logging.class"); 173 174 // Executable JAR file without the Profile attribute 175 if (thisProfile <= 3) { 176 createJarFile("Main.jar", 177 "Main-Class=Main,Class-Path=Logging.jar", 178 "Main.class"); 179 checkRunFail("Main.jar"); 180 } 181 182 // Executable JAR file with Profile attribute, Library JAR file without 183 for (int p=1; p<=3; p++) { 184 String attrs = "Main-Class=Main,Class-Path=Logging.jar" + 185 ",Profile=compact" + p; 186 createJarFile("Main.jar", attrs, "Main.class"); 187 if (p <= thisProfile) { 188 checkRun("Main.jar"); 189 } else { 190 checkRunFail("Main.jar"); 191 } 192 } 193 194 // Executable JAR file with Profile attribute and unrecognized profile 195 createJarFile("Main.jar", 196 "Main-Class=Main,Class-Path=Logging.jar,Profile=BadName", 197 "Main.class"); 198 checkRunFail("Main.jar"); 199 200 // Executable JAR file and Librrary JAR file with Profile attribute 201 createJarFile("Main.jar", 202 "Main-Class=Main,Class-Path=Logging.jar,Profile=compact1", 203 "Main.class"); 204 for (int p=1; p<=3; p++) { 205 String attrs = "Profile=compact" + p; 206 createJarFile("Logging.jar", attrs, "Logging.class"); 207 if (p <= thisProfile) { 208 checkRun("Main.jar"); 209 } else { 210 checkRunFail("Main.jar"); 211 } 212 } 213 214 // Executable JAR file and Library JAR with Profile attribute, value 215 // of Profile not recognized 216 createJarFile("Logging.jar", "Profile=BadName", "Logging.class"); 217 createJarFile("Main.jar", 218 "Main-Class=Main,Class-Path=Logging.jar,Profile=compact1", 219 "Main.class"); 220 checkRunFail("Main.jar"); 221 222 System.out.println("TEST PASSED."); 223 } 224 225 }