1 /* 2 * Copyright (c) 2015, 2017, 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 import java.io.File; 25 import java.io.FileOutputStream; 26 import java.io.IOException; 27 import java.nio.file.Files; 28 import java.nio.file.Path; 29 import java.nio.file.Paths; 30 import java.security.KeyStore; 31 import java.security.PrivateKey; 32 import java.security.cert.CertPath; 33 import java.security.cert.CertificateFactory; 34 import java.util.Arrays; 35 import java.util.HashMap; 36 import java.util.Map; 37 import java.util.zip.ZipFile; 38 import jdk.security.jarsigner.JarSigner; 39 40 public class CreateMultiReleaseTestJars { 41 final private String main = 42 "package version;\n\n" 43 + "public class Main {\n" 44 + " public static void main(String[] args) {\n" 45 + " Version v = new Version();\n" 46 + " System.out.println(\"I am running on version \" + v.getVersion());\n" 47 + " }\n" 48 + "}\n"; 49 final private String java8 = 50 "package version;\n\n" 51 + "public class Version {\n" 52 + " public int getVersion() {\n" 53 + " return 8;\n" 54 + " }\n" 55 + "}\n"; 56 final private String java9 = 57 "package version;\n\n" 58 + "public class Version {\n" 59 + " public int getVersion() {\n" 60 + " int version = (new PackagePrivate()).getVersion();\n" 61 + " if (version == 9) return 9;\n" // strange I know, but easy to test 62 + " return version;\n" 63 + " }\n" 64 + "}\n"; 65 final private String ppjava9 = 66 "package version;\n\n" 67 + "class PackagePrivate {\n" 68 + " int getVersion() {\n" 69 + " return 9;\n" 70 + " }\n" 71 + "}\n"; 72 final int currentVersion = Runtime.version().major(); 73 final String currentVersionStr = Integer.toString(currentVersion); 74 final private String javaCurrent = java8.replace("8", currentVersionStr); 75 final String readme8 = "This is the root readme file"; 76 final String readme9 = "This is the version nine readme file"; 77 final String readmeCurrent = "This is the current version readme file"; 78 private Map<String,byte[]> rootClasses; 79 private Map<String,byte[]> version9Classes; 80 private Map<String,byte[]> versionCurrentClasses; 81 82 public void buildUnversionedJar() throws IOException { 83 JarBuilder jb = new JarBuilder("unversioned.jar"); 84 jb.addEntry("README", readme8.getBytes()); 85 jb.addEntry("version/Main.java", main.getBytes()); 86 jb.addEntry("version/Main.class", rootClasses.get("version.Main")); 87 jb.addEntry("version/Version.java", java8.getBytes()); 88 jb.addEntry("version/Version.class", rootClasses.get("version.Version")); 89 jb.build(); 90 } 91 92 public void buildMultiReleaseJar() throws IOException { 93 JarBuilder jb = customMultiReleaseJar("multi-release.jar", "true"); 94 addEntries(jb); 95 jb.addEntry("META-INF/versions/9/version/Version.class", version9Classes.get("version.Version")); 96 jb.build(); 97 } 98 99 public void buildShortMultiReleaseJar() throws IOException { 100 JarBuilder jb = customMultiReleaseJar("short-multi-release.jar", "true"); 101 addEntries(jb); 102 jb.build(); 103 } 104 105 private JarBuilder customMultiReleaseJar(String filename, String multiReleaseValue) 106 throws IOException { 107 JarBuilder jb = new JarBuilder(filename); 108 jb.addAttribute("Multi-Release", multiReleaseValue); 109 return jb; 110 } 111 112 public void buildCustomMultiReleaseJar(String filename, String multiReleaseValue, 113 Map<String, String> extraAttributes) throws IOException { 114 buildCustomMultiReleaseJar(filename, multiReleaseValue, extraAttributes, false); 115 } 116 117 public void buildCustomMultiReleaseJar(String filename, String multiReleaseValue, 118 Map<String, String> extraAttributes, boolean addEntries) throws IOException { 119 JarBuilder jb = new JarBuilder(filename); 120 extraAttributes.entrySet() 121 .forEach(entry -> jb.addAttribute(entry.getKey(), entry.getValue())); 122 if (addEntries) { 123 addEntries(jb); 124 } 125 jb.addAttribute("Multi-Release", multiReleaseValue); 126 jb.build(); 127 } 128 129 private void addEntries(JarBuilder jb) { 130 jb.addEntry("README", readme8.getBytes()); 131 jb.addEntry("version/Main.java", main.getBytes()); 132 jb.addEntry("version/Main.class", rootClasses.get("version.Main")); 133 jb.addEntry("version/Version.java", java8.getBytes()); 134 jb.addEntry("version/Version.class", rootClasses.get("version.Version")); 135 jb.addEntry("META-INF/versions/9/README", readme9.getBytes()); 136 jb.addEntry("META-INF/versions/9/version/Version.java", java9.getBytes()); 137 jb.addEntry("META-INF/versions/9/version/PackagePrivate.java", ppjava9.getBytes()); 138 jb.addEntry("META-INF/versions/9/version/PackagePrivate.class", version9Classes.get("version.PackagePrivate")); 139 jb.addEntry("META-INF/versions/" + currentVersionStr + "/README", readmeCurrent.getBytes()); 140 jb.addEntry("META-INF/versions/" + currentVersionStr + "/version/Version.java", javaCurrent.getBytes()); 141 jb.addEntry("META-INF/versions/" + currentVersionStr + "/version/Version.class", versionCurrentClasses.get("version.Version")); 142 } 143 144 public void buildSignedMultiReleaseJar() throws Exception { 145 String testsrc = System.getProperty("test.src","."); 146 String testdir = findTestDir(testsrc); 147 String keystore = testdir + "/sun/security/tools/jarsigner/JarSigning.keystore"; 148 149 // jarsigner -keystore keystore -storepass "bbbbbb" 150 // -signedJar signed-multi-release.jar multi-release.jar b 151 152 char[] password = "bbbbbb".toCharArray(); 153 KeyStore ks = KeyStore.getInstance(new File(keystore), password); 154 PrivateKey pkb = (PrivateKey)ks.getKey("b", password); 155 CertPath cp = CertificateFactory.getInstance("X.509") 156 .generateCertPath(Arrays.asList(ks.getCertificateChain("b"))); 157 JarSigner js = new JarSigner.Builder(pkb, cp).build(); 158 try (ZipFile in = new ZipFile("multi-release.jar"); 159 FileOutputStream os = new FileOutputStream("signed-multi-release.jar")) 160 { 161 js.sign(in, os); 162 } 163 } 164 165 String findTestDir(String dir) throws IOException { 166 Path path = Paths.get(dir).toAbsolutePath(); 167 Path child = null; 168 while (path != null && !path.endsWith("test")) { 169 child = path; 170 path = path.getParent(); 171 } 172 if (child == null) { 173 throw new IllegalArgumentException(dir + " is not in a test directory"); 174 } 175 if (!Files.isDirectory(child)) { 176 throw new IOException(child.toString() + " is not a directory"); 177 } 178 return child.toString(); 179 } 180 181 void compileEntries() { 182 Map<String,String> input = new HashMap<>(); 183 input.put("version.Main", main); 184 input.put("version.Version", java8); 185 rootClasses = (new Compiler(input)).setRelease(8).compile(); 186 input.clear(); 187 input.put("version.Version", java9); 188 input.put("version.PackagePrivate", ppjava9); 189 version9Classes = (new Compiler(input)).setRelease(9).compile(); 190 input.clear(); 191 input.put("version.Version", javaCurrent); 192 versionCurrentClasses = (new Compiler(input)).compile(); // Use default release 193 } 194 }