8165793: Provide an API to query if a ClassLoader is parallel capable
Reviewed-by: alanb, mchung
--- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Tue Oct 25 07:38:50 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Tue Oct 25 12:58:34 2016 -0700
@@ -104,9 +104,9 @@
* class or resource itself.
*
* <p> Class loaders that support concurrent loading of classes are known as
- * <em>parallel capable</em> class loaders and are required to register
- * themselves at their class initialization time by invoking the
- * {@link
+ * <em>{@linkplain #isParallelCapable() parallel capable}</em> class loaders and
+ * are required to register themselves at their class initialization time by
+ * invoking the {@link
* #registerAsParallelCapable <tt>ClassLoader.registerAsParallelCapable</tt>}
* method. Note that the <tt>ClassLoader</tt> class is registered as parallel
* capable by default. However, its subclasses still need to register themselves
@@ -1437,7 +1437,7 @@
}
/**
- * Registers the caller as parallel capable.
+ * Registers the caller as {@linkplain #isParallelCapable() parallel capable}.
* The registration succeeds if and only if all of the following
* conditions are met:
* <ol>
@@ -1448,8 +1448,10 @@
* <p>Note that once a class loader is registered as parallel capable, there
* is no way to change it back.</p>
*
- * @return true if the caller is successfully registered as
- * parallel capable and false if otherwise.
+ * @return {@code true} if the caller is successfully registered as
+ * parallel capable and {@code false} if otherwise.
+ *
+ * @see #isParallelCapable()
*
* @since 1.7
*/
@@ -1461,6 +1463,22 @@
}
/**
+ * Returns {@code true} if this class loader is
+ * {@linkplain #registerAsParallelCapable parallel capable}, otherwise
+ * {@code false}.
+ *
+ * @return {@code true} if this class loader is parallel capable,
+ * otherwise {@code false}.
+ *
+ * @see #registerAsParallelCapable()
+ *
+ * @since 9
+ */
+ public final boolean isParallelCapable() {
+ return ParallelLoaders.isRegistered(this.getClass());
+ }
+
+ /**
* Find a resource of the specified name from the search path used to load
* classes. This method locates the resource through the system class
* loader (see {@link #getSystemClassLoader()}).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ClassLoader/IsParallelCapable.java Tue Oct 25 12:58:34 2016 -0700
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8165793
+ * @summary Test ClassLoader.isParallelCapable() method
+ * @run main IsParallelCapable
+ */
+
+import java.util.stream.Stream;
+
+public class IsParallelCapable {
+ public abstract static class TestCL extends ClassLoader {
+ static {
+ ClassLoader.registerAsParallelCapable();
+ }
+ public abstract boolean expectCapable();
+ public Class findClass(String name) throws ClassNotFoundException {
+ throw new ClassNotFoundException("Why are you using this?");
+ }
+ }
+
+ public static class ParaCL extends TestCL {
+ static {
+ ClassLoader.registerAsParallelCapable();
+ }
+ @Override
+ public boolean expectCapable() { return true; }
+ }
+
+ public static class NonParaCL extends TestCL {
+ @Override
+ public boolean expectCapable() {
+ // Doesn't call registerAsParallelCapable()
+ return false;
+ }
+ }
+
+ public static class NonParaSubCL1 extends ParaCL {
+ @Override
+ public boolean expectCapable() {
+ // Doesn't call registerAsParallelCapable()
+ return false;
+ }
+ }
+
+ public static class NonParaSubCL2 extends NonParaCL {
+ static {
+ ClassLoader.registerAsParallelCapable();
+ }
+ @Override
+ public boolean expectCapable() {
+ // Superclass is not parallel capable
+ return false;
+ }
+ }
+
+ public static class ParaSubCL extends ParaCL {
+ static {
+ ClassLoader.registerAsParallelCapable();
+ }
+ @Override
+ public boolean expectCapable() { return true; }
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (!ClassLoader.getSystemClassLoader().isParallelCapable()) {
+ throw new RuntimeException("System classloader not parallel capable!?");
+ }
+
+ Stream.of(ParaCL.class,
+ NonParaCL.class,
+ NonParaSubCL1.class,
+ NonParaSubCL2.class,
+ ParaSubCL.class)
+ .forEach(IsParallelCapable::testClassLoaderClass);
+ }
+
+ private static void testClassLoaderClass(Class<? extends TestCL> klazz) {
+ try {
+ TestCL cl = (TestCL)klazz.newInstance();
+ if (cl.expectCapable() != cl.isParallelCapable()) {
+ throw new RuntimeException(klazz + " expectCapable: " +
+ cl.expectCapable() + ", isParallelCapable: " +
+ cl.isParallelCapable());
+ } else {
+ System.out.println(klazz + " passed");
+ }
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}