T8147801.java revision 3903:fed9310b4b93
1214478Srpaulo/* 217680Spst * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. 339297Sfenner * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 417680Spst * 517680Spst * This code is free software; you can redistribute it and/or modify it 617680Spst * under the terms of the GNU General Public License version 2 only, as 717680Spst * published by the Free Software Foundation. 817680Spst * 9214478Srpaulo * This code is distributed in the hope that it will be useful, but WITHOUT 10214478Srpaulo * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11214478Srpaulo * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12214478Srpaulo * version 2 for more details (a copy is included in the LICENSE file that 13214478Srpaulo * accompanied this code). 14214478Srpaulo * 15214478Srpaulo * You should have received a copy of the GNU General Public License version 16214478Srpaulo * 2 along with this work; if not, write to the Free Software Foundation, 17214478Srpaulo * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18214478Srpaulo * 19127668Sbms * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2017680Spst * or visit www.oracle.com if you need additional information or have any 2117680Spst * questions. 2298524Sfenner */ 2317680Spst 24214478Srpaulo/* 25214478Srpaulo * @test 2617680Spst * @bug 8147801 27111726Sfenner * @summary java.nio.file.ClosedFileSystemException when using Javadoc API's in JDK9 2875115Sfenner * @modules jdk.javadoc/com.sun.tools.javadoc 29214478Srpaulo * @library jarsrc 30214478Srpaulo * @build lib.* p.* 31214478Srpaulo * @run main T8147801 32235530Sdelphij */ 33172683Smlaier 34172683Smlaierimport java.io.IOException; 35172683Smlaierimport java.io.PrintWriter; 36190207Srpauloimport java.io.StringWriter; 37172683Smlaierimport java.nio.file.ClosedFileSystemException; 38172683Smlaierimport java.nio.file.Files; 39127668Sbmsimport java.nio.file.Path; 40127668Sbmsimport java.nio.file.Paths; 41146773Ssamimport java.util.ArrayList; 42146773Ssamimport java.util.List; 43146773Ssamimport java.util.jar.JarEntry; 44146773Ssamimport java.util.jar.JarOutputStream; 45146773Ssam 46146773Ssamimport com.sun.javadoc.ClassDoc; 47146773Ssamimport com.sun.javadoc.FieldDoc; 48146773Ssamimport com.sun.javadoc.RootDoc; 49146773Ssam 50146773Ssam/* 51146773Ssam * This test verifies the use of the hidden fileManager.deferClose 52146773Ssam * option, to work around the limitation that javadoc objects 53146773Ssam * (like RootDoc and related types) should cannot normally be used 54146773Ssam * after javadoc exits, closing its file manager (if it opened it.) 55146773Ssam * 56146773Ssam * The test runs javadoc on a chain of classes, 1 in source form, 57146773Ssam * and 2 in a jar file. javadoc/javac will "complete" classes found 58146773Ssam * in source, but will eagerly "classes" in class form. 5917680Spst * The chain is p/Test.java -> lib/Lib1.class -> lib/Lib2.class. 6017680Spst * After javadoc exits, the classes are examined, to finally force 6198524Sfenner * the classes to be completed, possibly causing javac to try and access 6239297Sfenner * references into a .jar file system which has now been closed. 63235530Sdelphij * 64235530Sdelphij * The test runs two test cases -- one without the workaround option, 65235530Sdelphij * to test the validity of the test case, and one with the workaround 66235530Sdelphij * option, to test that it works as expected. 67235530Sdelphij */ 68235530Sdelphijpublic class T8147801 { 69235530Sdelphij public static void main(String... args) throws Exception { 70235530Sdelphij new T8147801().run(); 71235530Sdelphij } 72235530Sdelphij 73235530Sdelphij void run() throws Exception { 74235530Sdelphij initJar(); 75235530Sdelphij test(false); 76235530Sdelphij test(true); 77235530Sdelphij if (errors > 0) { 78235530Sdelphij throw new Exception(errors + " errors occurred"); 79235530Sdelphij } 80235530Sdelphij } 81235530Sdelphij 82235530Sdelphij void test(boolean withOption) { 83235530Sdelphij System.err.println("Testing " + (withOption ? "with" : "without") + " option"); 84235530Sdelphij try { 85235530Sdelphij String dump = ""; 86235530Sdelphij RootDoc root = getRootDoc(withOption); 87235530Sdelphij for (ClassDoc cd: root.specifiedClasses()) { 88235530Sdelphij dump += dump(cd); 89235530Sdelphij } 9039297Sfenner if (dump.contains("lib.Lib2.i")) { 9139297Sfenner if (!withOption) { 9275115Sfenner error("control case failed: Lib2 class file was read, unexpectedly, without using option"); 9375115Sfenner } 9475115Sfenner } else { 9575115Sfenner if (withOption) { 9675115Sfenner error("test case failed: could not read Lib2 class file, using option"); 9775115Sfenner } 9875115Sfenner } 9975115Sfenner } catch (ClosedFileSystemException e) { 10039297Sfenner error("Unexpected exception: " + e); 10175115Sfenner } 10275115Sfenner System.err.println(); 10375115Sfenner } 10439297Sfenner 10539297Sfenner RootDoc getRootDoc(boolean withOption) { 10639297Sfenner List<String> opts = new ArrayList<>(); 10739297Sfenner if (withOption) 10839297Sfenner opts.add("-XDfileManager.deferClose=10"); 10939297Sfenner opts.add("-doclet"); 11039297Sfenner opts.add(getClass().getName()); 11139297Sfenner opts.add("-classpath"); 11239297Sfenner opts.add(jarPath.toString()); 11356893Sfenner opts.add(Paths.get(System.getProperty("test.src"), "p", "Test.java").toString()); 114214478Srpaulo System.err.println("javadoc opts: " + opts); 115214478Srpaulo int rc = com.sun.tools.javadoc.Main.execute( 116214478Srpaulo "javadoc", 117214478Srpaulo // by specifying our own class loader, we get the same Class instance as this 118214478Srpaulo getClass().getClassLoader(), 119214478Srpaulo opts.toArray(new String[opts.size()])); 12056893Sfenner if (rc != 0) { 12175115Sfenner error("unexpected exit from javadoc or doclet: " + rc); 12298524Sfenner } 12398524Sfenner return cachedRoot; 12456893Sfenner } 12556893Sfenner 12656893Sfenner String dump(ClassDoc cd) { 12756893Sfenner StringWriter sw = new StringWriter(); 12856893Sfenner PrintWriter pw = new PrintWriter(sw); 12975115Sfenner dump(pw, "", cd); 13075115Sfenner String out = sw.toString(); 13156893Sfenner System.err.println(out); 13256893Sfenner return out; 13375115Sfenner } 13475115Sfenner 13575115Sfenner void dump(PrintWriter out, String prefix, ClassDoc cd) { 13675115Sfenner out.println(prefix + "class: " + cd); 13775115Sfenner for (FieldDoc fd: cd.fields()) { 13875115Sfenner out.println(prefix + " " + fd); 13975115Sfenner if (fd.type().asClassDoc() != null) { 14075115Sfenner dump(out, prefix + " ", fd.type().asClassDoc()); 14156893Sfenner } 14256893Sfenner } 14356893Sfenner } 14456893Sfenner 14556893Sfenner void initJar() throws IOException { 14698524Sfenner Path testClasses = Paths.get(System.getProperty("test.classes")); 14798524Sfenner jarPath = Paths.get("lib.jar"); 14898524Sfenner try (JarOutputStream out = new JarOutputStream(Files.newOutputStream(jarPath))) { 14998524Sfenner String[] classNames = {"Lib1.class", "Lib2.class"}; 15098524Sfenner for (String cn : classNames) { 15198524Sfenner out.putNextEntry(new JarEntry("lib/" + cn)); 15298524Sfenner Path libClass = testClasses.resolve("jarsrc").resolve("lib").resolve(cn); 15398524Sfenner out.write(Files.readAllBytes(libClass)); 15498524Sfenner } 15598524Sfenner } 15675115Sfenner } 15775115Sfenner 15856893Sfenner void error(String msg) { 15956893Sfenner System.err.println("Error: " + msg); 16098524Sfenner errors++; 161214478Srpaulo } 16256893Sfenner 16398524Sfenner Path jarPath; 16498524Sfenner int errors; 16598524Sfenner 16698524Sfenner // Bad doclet caches the RootDoc for later use 16798524Sfenner 16898524Sfenner static RootDoc cachedRoot; 16998524Sfenner 17098524Sfenner public static boolean start(RootDoc root) { 17198524Sfenner cachedRoot = root; 17298524Sfenner return true; 17398524Sfenner } 17498524Sfenner} 17598524Sfenner