1/*
2 * Copyright (c) 2014, 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 8067138
27 * @summary Verify that compiling against the exploded JDK image works, and that Locations close
28 *          the directory streams properly when working with exploded JDK image.
29 * @library /tools/lib
30 * @modules jdk.compiler/com.sun.tools.javac.api
31 *          jdk.compiler/com.sun.tools.javac.code
32 *          jdk.compiler/com.sun.tools.javac.main
33 * @build toolbox.ToolBox ExplodedImage
34 * @run main/othervm ExplodedImage modules/* testDirectoryStreamClosed
35 * @run main/othervm ExplodedImage modules/* testCanCompileAgainstExplodedImage
36 */
37
38import java.io.File;
39import java.io.IOException;
40import java.io.InputStream;
41import java.net.URI;
42import java.nio.file.DirectoryStream;
43import java.nio.file.FileSystems;
44import java.nio.file.Files;
45import java.nio.file.Path;
46import java.util.Arrays;
47import java.util.EnumSet;
48import java.util.List;
49import javax.lang.model.element.TypeElement;
50import javax.tools.Diagnostic;
51import javax.tools.DiagnosticListener;
52import javax.tools.JavaCompiler;
53import javax.tools.JavaFileObject;
54import javax.tools.StandardJavaFileManager;
55import javax.tools.StandardLocation;
56import javax.tools.ToolProvider;
57
58import com.sun.source.util.JavacTask;
59import com.sun.tools.javac.code.Symbol.ClassSymbol;
60
61import toolbox.ToolBox;
62
63public class ExplodedImage {
64    public static void main(String... args) throws IOException {
65        new ExplodedImage().run(args);
66    }
67
68    void run(String... args) throws IOException {
69        switch (args[0]) {
70            case "testDirectoryStreamClosed":
71                testDirectoryStreamClosed(args[1]);
72                break;
73            case "testCanCompileAgainstExplodedImage":
74                testCanCompileAgainstExplodedImage(args[1]);
75                break;
76        }
77    }
78
79    void testDirectoryStreamClosed(String loc) throws IOException {
80        System.err.println("testDirectoryStreamClosed(" + loc + ")");
81        Path javaHome = prepareJavaHome();
82        Path targetPath = javaHome.resolve(loc.replace("*", "/java.base").replace("/", sep));
83        Path testClass = targetPath.resolve(("java/lang/" + TEST_FILE).replace("/", sep));
84        Files.createDirectories(testClass.getParent());
85        Files.createFile(testClass);
86        System.setProperty("java.home", javaHome.toString());
87
88        for (int i = 0; i < REPEATS; i++) {
89            try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) {
90                Iterable<JavaFileObject> javaLangContent =
91                        fm.list(StandardLocation.PLATFORM_CLASS_PATH,
92                                "java.lang",
93                                EnumSet.allOf(JavaFileObject.Kind.class),
94                                false);
95                boolean found = false;
96
97                for (JavaFileObject fo : javaLangContent) {
98                    if (!fo.getName().endsWith(TEST_FILE)) {
99                        throw new IllegalStateException("Wrong file: " + fo);
100                    }
101                    found = true;
102                }
103
104                if (!found)
105                    throw new IllegalStateException("Could not find the expected file!");
106            }
107        }
108
109        System.err.println("finished.");
110    }
111    //where:
112        static final String TEST_FILE = "ExplodedImageTestFile.class";
113        static final int REPEATS = 16 * 1024 + 1;
114
115    void testCanCompileAgainstExplodedImage(String loc) throws IOException {
116        System.err.println("testCanCompileAgainstExplodedImage(" + loc + ")");
117        Path javaHome = prepareJavaHome();
118        Path targetPath = javaHome.resolve(loc.replace("*", "/java.base").replace("/", sep));
119        try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) {
120            for (String pack : REQUIRED_PACKAGES) {
121                Iterable<JavaFileObject> content = fm.list(StandardLocation.PLATFORM_CLASS_PATH,
122                                                           pack,
123                                                           EnumSet.allOf(JavaFileObject.Kind.class),
124                                                           false);
125
126                for (JavaFileObject jfo : content) {
127                    String name = jfo.getName();
128                    int lastSlash = name.lastIndexOf('/');
129                    name = lastSlash >= 0 ? name.substring(lastSlash + 1) : name;
130                    Path target = targetPath.resolve(pack.replace(".", sep) + sep + name);
131                    Files.createDirectories(target.getParent());
132                    try (InputStream in = jfo.openInputStream()) {
133                        Files.copy(in, target);
134                    }
135                }
136            }
137        }
138
139        System.setProperty("java.home", javaHome.toString());
140
141        try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) {
142            DiagnosticListener<JavaFileObject> noErrors = d -> {
143                if (d.getKind() == Diagnostic.Kind.ERROR)
144                    throw new IllegalStateException("Unexpected error: " + d);
145            };
146            ToolBox.JavaSource inputFile =
147                    new ToolBox.JavaSource("import java.util.List; class Test { List l; }");
148            List<JavaFileObject> inputFiles = Arrays.asList(inputFile);
149            boolean result =
150                    javaCompiler.getTask(null, fm, noErrors, null, null, inputFiles).call();
151            if (!result) {
152                throw new IllegalStateException("Could not compile correctly!");
153            }
154            JavacTask task =
155                    (JavacTask) javaCompiler.getTask(null, fm, noErrors, null, null, inputFiles);
156            task.parse();
157            TypeElement juList = task.getElements().getTypeElement("java.util.List");
158            if (juList == null)
159                throw new IllegalStateException("Cannot resolve java.util.List!");
160            URI listSource = ((ClassSymbol) juList).classfile.toUri();
161            if (!listSource.toString().startsWith(javaHome.toUri().toString()))
162                throw new IllegalStateException(  "Did not load java.util.List from correct place, " +
163                                                  "actual location: " + listSource.toString() +
164                                                "; expected prefix: " + javaHome.toUri());
165        }
166
167        System.err.println("finished.");
168    }
169    //where:
170        static final String[] REQUIRED_PACKAGES = {"java.lang", "java.io", "java.util"};
171
172    Path prepareJavaHome() throws IOException {
173        Path javaHome = new File("javahome").getAbsoluteFile().toPath();
174        delete(javaHome);
175        Files.createDirectory(javaHome);
176        return javaHome;
177    }
178
179    String sep = FileSystems.getDefault().getSeparator();
180    JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
181    String originalJavaHome = System.getProperty("java.home");
182
183    void delete(Path p) throws IOException {
184        if (!Files.exists(p))
185            return ;
186        if (Files.isDirectory(p)) {
187            try (DirectoryStream<Path> dir = Files.newDirectoryStream(p)) {
188                for (Path child : dir) {
189                    delete(child);
190                }
191            }
192        }
193        Files.delete(p);
194    }
195}
196