jaxp/src/javax/xml/transform/FactoryFinder.java
changeset 12458 d601e4bba306
parent 12457 c348e06f0e82
child 14942 0dbd45cfc14b
--- a/jaxp/src/javax/xml/transform/FactoryFinder.java	Thu Apr 12 08:38:26 2012 -0700
+++ b/jaxp/src/javax/xml/transform/FactoryFinder.java	Tue Apr 17 11:17:59 2012 -0700
@@ -25,15 +25,13 @@
 
 package javax.xml.transform;
 
+import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileInputStream;
-
-import java.util.Properties;
-import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.net.URL;
+import java.lang.reflect.Method;
+import java.util.Properties;
 
 /**
  * <p>Implements pluggable Datatypes.</p>
@@ -42,6 +40,7 @@
  * sync.  It is package private for secure class loading.</p>
  *
  * @author Santiago.PericasGeertsen@sun.com
+ * @author Huizhe.Wang@oracle.com
  */
 class FactoryFinder {
 
@@ -59,7 +58,7 @@
      * Flag indicating if properties from java.home/lib/jaxp.properties
      * have been cached.
      */
-    static boolean firstTime = true;
+    static volatile boolean firstTime = true;
 
     /**
      * Security support class use to check access control before
@@ -95,18 +94,24 @@
      * If the class loader supplied is <code>null</code>, first try using the
      * context class loader followed by the current (i.e. bootstrap) class
      * loader.
+     *
+     * Use bootstrap classLoader if cl = null and useBSClsLoader is true
      */
     static private Class getProviderClass(String className, ClassLoader cl,
-            boolean doFallback) throws ClassNotFoundException
+            boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException
     {
         try {
             if (cl == null) {
-                cl = ss.getContextClassLoader();
-                if (cl == null) {
-                    throw new ClassNotFoundException();
-                }
-                else {
-                    return cl.loadClass(className);
+                if (useBSClsLoader) {
+                    return Class.forName(className, true, FactoryFinder.class.getClassLoader());
+                } else {
+                    cl = ss.getContextClassLoader();
+                    if (cl == null) {
+                        throw new ClassNotFoundException();
+                    }
+                    else {
+                        return cl.loadClass(className);
+                    }
                 }
             }
             else {
@@ -131,8 +136,8 @@
      * @param className Name of the concrete class corresponding to the
      * service provider
      *
-     * @param cl ClassLoader to use to load the class, null means to use
-     * the bootstrap ClassLoader
+     * @param cl <code>ClassLoader</code> used to load the factory class. If <code>null</code>
+     * current <code>Thread</code>'s context classLoader is used to load the factory class.
      *
      * @param doFallback True if the current ClassLoader should be tried as
      * a fallback if the class is not found using cl
@@ -140,9 +145,39 @@
     static Object newInstance(String className, ClassLoader cl, boolean doFallback)
         throws ConfigurationError
     {
+        return newInstance(className, cl, doFallback, false, false);
+    }
+
+    /**
+     * Create an instance of a class. Delegates to method
+     * <code>getProviderClass()</code> in order to load the class.
+     *
+     * @param className Name of the concrete class corresponding to the
+     * service provider
+     *
+     * @param cl <code>ClassLoader</code> used to load the factory class. If <code>null</code>
+     * current <code>Thread</code>'s context classLoader is used to load the factory class.
+     *
+     * @param doFallback True if the current ClassLoader should be tried as
+     * a fallback if the class is not found using cl
+     *
+     * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter
+     * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader.
+     *
+     * @param useServicesMechanism True use services mechanism
+     */
+    static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader, boolean useServicesMechanism)
+        throws ConfigurationError
+    {
         try {
-            Class providerClass = getProviderClass(className, cl, doFallback);
-            Object instance = providerClass.newInstance();
+            Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
+            Object instance = null;
+            if (!useServicesMechanism) {
+                instance = newInstanceNoServiceLoader(providerClass);
+            }
+            if (instance == null) {
+                instance = providerClass.newInstance();
+            }
             if (debug) {    // Extra check to avoid computing cl strings
                 dPrint("created new instance of " + providerClass +
                        " using ClassLoader: " + cl);
@@ -159,7 +194,29 @@
                 x);
         }
     }
-
+    /**
+     * Try to construct using newTransformerFactoryNoServiceLoader
+     *   method if available.
+     */
+    private static Object newInstanceNoServiceLoader(
+         Class<?> providerClass
+    ) {
+        // Retain maximum compatibility if no security manager.
+        if (System.getSecurityManager() == null) {
+            return null;
+        }
+        try {
+            Method creationMethod =
+                providerClass.getDeclaredMethod(
+                    "newTransformerFactoryNoServiceLoader"
+                );
+                return creationMethod.invoke(null, null);
+            } catch (NoSuchMethodException exc) {
+                return null;
+            } catch (Exception exc) {
+                return null;
+        }
+    }
     /**
      * Finds the implementation Class object in the specified order.  Main
      * entry point.
@@ -176,13 +233,12 @@
         throws ConfigurationError
     {
         dPrint("find factoryId =" + factoryId);
-
         // Use the system property first
         try {
             String systemProp = ss.getSystemProperty(factoryId);
             if (systemProp != null) {
                 dPrint("found system property, value=" + systemProp);
-                return newInstance(systemProp, null, true);
+                return newInstance(systemProp, null, true, false, true);
             }
         }
         catch (SecurityException se) {
@@ -210,7 +266,7 @@
 
             if (factoryClassName != null) {
                 dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
-                return newInstance(factoryClassName, null, true);
+                return newInstance(factoryClassName, null, true, false, true);
             }
         }
         catch (Exception ex) {
@@ -228,7 +284,7 @@
         }
 
         dPrint("loaded from fallback value: " + fallbackClassName);
-        return newInstance(fallbackClassName, null, true);
+        return newInstance(fallbackClassName, null, true, false, true);
     }
 
     /*
@@ -244,6 +300,7 @@
 
         // First try the Context ClassLoader
         ClassLoader cl = ss.getContextClassLoader();
+        boolean useBSClsLoader = false;
         if (cl != null) {
             is = ss.getResourceAsStream(cl, serviceId);
 
@@ -251,11 +308,13 @@
             if (is == null) {
                 cl = FactoryFinder.class.getClassLoader();
                 is = ss.getResourceAsStream(cl, serviceId);
-            }
+                useBSClsLoader = true;
+           }
         } else {
             // No Context ClassLoader, try the current ClassLoader
             cl = FactoryFinder.class.getClassLoader();
             is = ss.getResourceAsStream(cl, serviceId);
+            useBSClsLoader = true;
         }
 
         if (is == null) {
@@ -293,7 +352,7 @@
             // ClassLoader because we want to avoid the case where the
             // resource file was found using one ClassLoader and the
             // provider class was instantiated using a different one.
-            return newInstance(factoryClassName, cl, false);
+            return newInstance(factoryClassName, cl, false, useBSClsLoader, true);
         }
 
         // No provider found