6176978: current Javadoc's invocation and extension (Doclet) mechanisms are problematic
authorjjg
Tue, 27 Jan 2009 18:38:39 -0800
changeset 1990 5d90be5d60bb
parent 1989 a891da9d8db1
child 1991 aafb4bf914ee
6176978: current Javadoc's invocation and extension (Doclet) mechanisms are problematic Reviewed-by: darcy
langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java
langtools/test/tools/javadoc/6176978/T6176978.java
langtools/test/tools/javadoc/6176978/X.java
--- a/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java	Tue Jan 27 17:50:53 2009 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java	Tue Jan 27 18:38:39 2009 -0800
@@ -83,7 +83,7 @@
         cpString = appendPath(docletPath, cpString);
         URL[] urls = pathToURLs(cpString);
         if (docletParentClassLoader == null)
-            appClassLoader = new URLClassLoader(urls);
+            appClassLoader = new URLClassLoader(urls, getDelegationClassLoader(docletClassName));
         else
             appClassLoader = new URLClassLoader(urls, docletParentClassLoader);
 
@@ -98,6 +98,57 @@
         docletClass = dc;
     }
 
+    /*
+     * Returns the delegation class loader to use when creating
+     * appClassLoader (used to load the doclet).  The context class
+     * loader is the best choice, but legacy behavior was to use the
+     * default delegation class loader (aka system class loader).
+     *
+     * Here we favor using the context class loader.  To ensure
+     * compatibility with existing apps, we revert to legacy
+     * behavior if either or both of the following conditions hold:
+     *
+     * 1) the doclet is loadable from the system class loader but not
+     *    from the context class loader,
+     *
+     * 2) this.getClass() is loadable from the system class loader but not
+     *    from the context class loader.
+     */
+    private ClassLoader getDelegationClassLoader(String docletClassName) {
+        ClassLoader ctxCL = Thread.currentThread().getContextClassLoader();
+        ClassLoader sysCL = ClassLoader.getSystemClassLoader();
+        if (sysCL == null)
+            return ctxCL;
+        if (ctxCL == null)
+            return sysCL;
+
+        // Condition 1.
+        try {
+            sysCL.loadClass(docletClassName);
+            try {
+                ctxCL.loadClass(docletClassName);
+            } catch (ClassNotFoundException e) {
+                return sysCL;
+            }
+        } catch (ClassNotFoundException e) {
+        }
+
+        // Condition 2.
+        try {
+            if (getClass() == sysCL.loadClass(getClass().getName())) {
+                try {
+                    if (getClass() != ctxCL.loadClass(getClass().getName()))
+                        return sysCL;
+                } catch (ClassNotFoundException e) {
+                    return sysCL;
+                }
+            }
+        } catch (ClassNotFoundException e) {
+        }
+
+        return ctxCL;
+    }
+
     /**
      * Generate documentation here.  Return true on success.
      */
@@ -231,6 +282,8 @@
                                docletClassName, methodName);
                 throw new DocletInvokeException();
             }
+            ClassLoader savedCCL =
+                Thread.currentThread().getContextClassLoader();
             try {
                 Thread.currentThread().setContextClassLoader(appClassLoader);
                 return meth.invoke(null , params);
@@ -256,6 +309,8 @@
                     exc.getTargetException().printStackTrace();
                 }
                 throw new DocletInvokeException();
+            } finally {
+                Thread.currentThread().setContextClassLoader(savedCCL);
             }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/6176978/T6176978.java	Tue Jan 27 18:38:39 2009 -0800
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6176978
+ * @summary current Javadoc's invocation and extension (Doclet) mechanisms are problematic
+ * @build T6176978
+ * @run main T6176978
+ */
+
+import java.io.*;
+import java.net.*;
+
+public class T6176978
+{
+    public static void main(String[] args) throws Exception {
+        // create and use a temp dir that will not be on jtreg's
+        // default class path
+        File tmpDir = new File("tmp");
+        tmpDir.mkdirs();
+
+        File testSrc = new File(System.getProperty("test.src", "."));
+        String[] javac_args = {
+            "-d",
+            "tmp",
+            new File(testSrc, "X.java").getPath()
+        };
+
+        int rc = com.sun.tools.javac.Main.compile(javac_args);
+        if (rc != 0)
+            throw new Error("javac exit code: " + rc);
+
+        String[] jdoc_args = {
+            "-doclet",
+            "X",
+            new File(testSrc, "T6176978.java").getPath()
+        };
+
+        rc = com.sun.tools.javadoc.Main.execute(jdoc_args);
+        if (rc == 0)
+            throw new Error("javadoc unexpectedly succeeded");
+
+
+
+        Thread currThread = Thread.currentThread();
+        ClassLoader saveClassLoader = currThread.getContextClassLoader();
+        URLClassLoader urlCL = new URLClassLoader(new URL[] { tmpDir.toURL() });
+        currThread.setContextClassLoader(urlCL);
+
+        try {
+            rc = com.sun.tools.javadoc.Main.execute(jdoc_args);
+            if (rc != 0)
+                throw new Error("javadoc exit: " + rc);
+        }
+        finally {
+            currThread.setContextClassLoader(saveClassLoader);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/6176978/X.java	Tue Jan 27 18:38:39 2009 -0800
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import com.sun.javadoc.*;
+
+public class X {
+    public static boolean start(RootDoc root) {
+        System.out.println("X.start");
+        return true;
+    }
+}