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 
  38 import java.io.File;
  39 import java.io.IOException;
  40 import java.io.InputStream;
  41 import java.net.URI;
  42 import java.nio.file.DirectoryStream;
  43 import java.nio.file.FileSystems;
  44 import java.nio.file.Files;
  45 import java.nio.file.Path;
  46 import java.util.Arrays;
  47 import java.util.EnumSet;
  48 import java.util.List;
  49 import javax.lang.model.element.TypeElement;
  50 import javax.tools.Diagnostic;
  51 import javax.tools.DiagnosticListener;
  52 import javax.tools.JavaCompiler;
  53 import javax.tools.JavaFileObject;
  54 import javax.tools.StandardJavaFileManager;
  55 import javax.tools.StandardLocation;
  56 import javax.tools.ToolProvider;
  57 
  58 import com.sun.source.util.JavacTask;
  59 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  60 
  61 import toolbox.ToolBox;
  62 
  63 public 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 }