1/*
2 * Copyright (c) 2015, 2016, 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 8132734 8144062
27 * @summary Test the System properties for JarFile that support multi-release jar files
28 * @library /lib/testlibrary/java/util/jar
29 * @build Compiler JarBuilder CreateMultiReleaseTestJars
30 * @run testng MultiReleaseJarProperties
31 * @run testng/othervm -Djdk.util.jar.version=0 MultiReleaseJarProperties
32 * @run testng/othervm -Djdk.util.jar.version=8 MultiReleaseJarProperties
33 * @run testng/othervm -Djdk.util.jar.version=9 MultiReleaseJarProperties
34 * @run testng/othervm -Djdk.util.jar.version=10 MultiReleaseJarProperties
35 * @run testng/othervm -Djdk.util.jar.version=100 MultiReleaseJarProperties
36 * @run testng/othervm -Djdk.util.jar.version=8 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
37 * @run testng/othervm -Djdk.util.jar.version=9 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
38 * @run testng/othervm -Djdk.util.jar.version=10 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
39 * @run testng/othervm -Djdk.util.jar.version=8 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
40 * @run testng/othervm -Djdk.util.jar.version=9 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
41 * @run testng/othervm -Djdk.util.jar.version=10 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
42 * @run testng/othervm -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
43 * @run testng/othervm -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
44 */
45
46import java.io.File;
47import java.io.IOException;
48import java.io.InputStream;
49import java.lang.invoke.MethodHandle;
50import java.lang.invoke.MethodHandles;
51import java.lang.invoke.MethodType;
52import java.net.URL;
53import java.net.URLClassLoader;
54import java.nio.file.Files;
55import java.util.jar.JarEntry;
56import java.util.jar.JarFile;
57
58import org.testng.Assert;
59import org.testng.annotations.AfterClass;
60import org.testng.annotations.BeforeClass;
61import org.testng.annotations.Test;
62
63
64public class MultiReleaseJarProperties {
65    final static int BASE_VERSION = JarFile.baseVersion().major();
66
67    final static String userdir = System.getProperty("user.dir", ".");
68    final static File multirelease = new File(userdir, "multi-release.jar");
69    protected int rtVersion;
70    boolean force;
71    protected ClassLoader cldr;
72    protected Class<?> rootClass;
73
74    @BeforeClass
75    public void initialize() throws Exception {
76        CreateMultiReleaseTestJars creator =  new CreateMultiReleaseTestJars();
77        creator.compileEntries();
78        creator.buildMultiReleaseJar();
79        int RUNTIME_VERSION = Runtime.version().major();
80        rtVersion = Integer.getInteger("jdk.util.jar.version", RUNTIME_VERSION);
81        String mrprop = System.getProperty("jdk.util.jar.enableMultiRelease", "");
82        if (mrprop.equals("false")) {
83            rtVersion = BASE_VERSION;
84        } else if (rtVersion < BASE_VERSION) {
85            rtVersion = BASE_VERSION;
86        } else if (rtVersion > RUNTIME_VERSION) {
87            rtVersion = RUNTIME_VERSION;
88        }
89        force = mrprop.equals("force");
90
91        initializeClassLoader();
92    }
93
94    protected void initializeClassLoader() throws Exception {
95        URL[] urls = new URL[]{multirelease.toURI().toURL()};
96        cldr = new URLClassLoader(urls);
97        // load any class, Main is convenient and in the root entries
98        rootClass = cldr.loadClass("version.Main");
99    }
100
101    @AfterClass
102    public void close() throws IOException {
103        ((URLClassLoader)cldr).close();
104        Files.delete(multirelease.toPath());
105    }
106
107    /*
108     * jdk.util.jar.enableMultiRelease=force is a no-op for URLClassLoader
109     */
110    @Test
111    public void testURLClassLoader() throws Throwable {
112        Class<?> vcls = cldr.loadClass("version.Version");
113        invokeMethod(vcls, rtVersion);
114    }
115
116    protected void invokeMethod(Class<?> vcls, int expected) throws Throwable {
117        MethodType mt = MethodType.methodType(int.class);
118        MethodHandle mh = MethodHandles.lookup().findVirtual(vcls, "getVersion", mt);
119        Assert.assertEquals(expected, (int) mh.invoke(vcls.newInstance()));
120    }
121
122    /*
123     * jdk.util.jar.enableMultiRelease=force should affect a custom class loader
124     */
125    @Test
126    public void testClassLoader() throws Throwable {
127        try (JarFile jf = new JarFile(multirelease)) {  // do not set runtime versioning
128            ClassLoader cldr = new CustomClassLoader(jf);
129            Class<?> vcls = cldr.loadClass("version.Version");
130            if (rtVersion == 9) {
131                try {
132                    cldr.loadClass("version.PackagePrivate");
133                } catch (ClassNotFoundException x) {
134                    if (force) throw x;
135                }
136            }
137            invokeMethod(vcls, force ? rtVersion : BASE_VERSION);
138        }
139    }
140
141    private static class CustomClassLoader extends ClassLoader {
142        private final JarFile jf;
143
144        CustomClassLoader(JarFile jf) throws Exception {
145            super(null);
146            this.jf = jf;
147        }
148
149        protected Class<?> findClass(String name) throws ClassNotFoundException {
150            try {
151                byte[] b;
152                String entryName = name.replace(".", "/") + ".class";
153                JarEntry je = jf.getJarEntry(entryName);
154                if (je != null) {
155                    try (InputStream is = jf.getInputStream(je)) {
156                        b = new byte[(int) je.getSize()];
157                        is.read(b);
158                    }
159                    return defineClass(name, b, 0, b.length);
160                }
161                throw new ClassNotFoundException(name);
162            } catch (IOException x) {
163                throw new ClassNotFoundException(x.getMessage());
164            }
165        }
166    }
167
168    @Test
169    public void testGetResourceAsStream() throws Exception {
170        String resource = rtVersion == 9 ? "/version/PackagePrivate.java" : "/version/Version.java";
171        // use fileRootClass as a base for getting resources
172        getResourceAsStream(rootClass, resource);
173    }
174
175    protected void getResourceAsStream(Class<?> rootClass, String resource) throws Exception {
176        try (InputStream is = rootClass.getResourceAsStream(resource)) {
177            byte[] bytes = is.readAllBytes();
178            resource = new String(bytes);
179        }
180        String match = "return " + rtVersion + ";";
181        Assert.assertTrue(resource.contains(match));
182    }
183
184    @Test
185    public void testGetResource() throws Exception {
186        String resource = rtVersion == 9 ? "/version/PackagePrivate.java" : "/version/Version.java";
187        // use rootClass as a base for getting resources
188        getResource(rootClass, resource);
189    }
190
191    protected void getResource(Class<?> rootClass, String resource) throws Exception {
192        URL url = rootClass.getResource(resource);
193        try (InputStream is = url.openStream()) {
194            byte[] bytes = is.readAllBytes();
195            resource = new String(bytes);
196        }
197        String match = "return " + rtVersion + ";";
198        Assert.assertTrue(resource.contains(match));
199    }
200}
201