8131334: SAAJ Plugability Layer: using java.util.ServiceLoader
authormkos
Fri, 27 Nov 2015 11:28:43 +0100
changeset 34467 024f1ce7da02
parent 33718 09206c6513b3
child 34468 97117dc89b8f
8131334: SAAJ Plugability Layer: using java.util.ServiceLoader Reviewed-by: lancea
jaxws/src/java.xml.ws/share/classes/javax/xml/soap/FactoryFinder.java
jaxws/src/java.xml.ws/share/classes/javax/xml/soap/MessageFactory.java
jaxws/src/java.xml.ws/share/classes/javax/xml/soap/SAAJMetaFactory.java
jaxws/src/java.xml.ws/share/classes/javax/xml/soap/SOAPConnectionFactory.java
jaxws/src/java.xml.ws/share/classes/javax/xml/soap/SOAPFactory.java
jaxws/src/java.xml.ws/share/classes/javax/xml/soap/ServiceLoaderUtil.java
jaxws/src/java.xml.ws/share/classes/javax/xml/soap/package-info.java
--- a/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/FactoryFinder.java	Wed Jul 05 21:00:56 2017 +0200
+++ b/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/FactoryFinder.java	Fri Nov 27 11:28:43 2015 +0100
@@ -26,94 +26,46 @@
 package javax.xml.soap;
 
 import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 
 class FactoryFinder {
 
-    /**
-     * Creates an instance of the specified class using the specified
-     * {@code ClassLoader} object.
-     *
-     * @exception SOAPException if the given class could not be found
-     *            or could not be instantiated
-     */
-    private static Object newInstance(String className,
-                                      ClassLoader classLoader)
-            throws SOAPException
-    {
-        try {
-            Class spiClass = safeLoadClass(className, classLoader);
-            return spiClass.newInstance();
+    private static final Logger logger = Logger.getLogger("javax.xml.soap");
 
-        } catch (ClassNotFoundException x) {
-            throw new SOAPException("Provider " + className + " not found", x);
-        } catch (Exception x) {
-            throw new SOAPException("Provider " + className + " could not be instantiated: " + x, x);
-        }
-    }
+    private static final ServiceLoaderUtil.ExceptionHandler<SOAPException> EXCEPTION_HANDLER =
+            new ServiceLoaderUtil.ExceptionHandler<SOAPException>() {
+                @Override
+                public SOAPException createException(Throwable throwable, String message) {
+                    return new SOAPException(message, throwable);
+                }
+            };
 
     /**
      * Finds the implementation {@code Class} object for the given
-     * factory name, or null if that fails.
-     * <P>
-     * This method is package private so that this code can be shared.
-     *
-     * @return the {@code Class} object of the specified message factory;
-     *         or {@code null}
-     *
-     * @param factoryId             the name of the factory to find, which is
-     *                              a system property
-     * @exception SOAPException if there is a SOAP error
-     */
-    static Object find(String factoryId)
-            throws SOAPException
-    {
-        return find(factoryId, null, false);
-    }
-
-    /**
-     * Finds the implementation {@code Class} object for the given
-     * factory name, or if that fails, finds the {@code Class} object
-     * for the given fallback class name. The arguments supplied must be
-     * used in order. If using the first argument is successful, the second
-     * one will not be used.
-     * <P>
-     * This method is package private so that this code can be shared.
-     *
-     * @return the {@code Class} object of the specified message factory;
-     *         may be {@code null}
-     *
-     * @param factoryId             the name of the factory to find, which is
-     *                              a system property
-     * @param fallbackClassName     the implementation class name, which is
-     *                              to be used only if nothing else
-     *                              is found; {@code null} to indicate that
-     *                              there is no fallback class name
-     * @exception SOAPException if there is a SOAP error
-     */
-    static Object find(String factoryId, String fallbackClassName)
-            throws SOAPException
-    {
-        return find(factoryId, fallbackClassName, true);
-    }
-
-    /**
-     * Finds the implementation {@code Class} object for the given
-     * factory name, or if that fails, finds the {@code Class} object
-     * for the given default class name, but only if {@code tryFallback}
-     * is {@code true}.  The arguments supplied must be used in order
-     * If using the first argument is successful, the second one will not
-     * be used.  Note the default class name may be needed even if fallback
-     * is not to be attempted, so certain error conditions can be handled.
+     * factory type.  If it fails and {@code tryFallback} is {@code true}
+     * finds the {@code Class} object for the given default class name.
+     * The arguments supplied must be used in order
+     * Note the default class name may be needed even if fallback
+     * is not to be attempted in order to check if requested type is fallback.
      * <P>
      * This method is package private so that this code can be shared.
      *
      * @return the {@code Class} object of the specified message factory;
      *         may not be {@code null}
      *
-     * @param factoryId             the name of the factory to find, which is
-     *                              a system property
+     * @param factoryClass          factory abstract class or interface to be found
+     * @param deprecatedFactoryId   deprecated name of a factory; it is used for types
+     *                              where class name is different from a name
+     *                              being searched (in previous spec).
      * @param defaultClassName      the implementation class name, which is
      *                              to be used only if nothing else
      *                              is found; {@code null} to indicate
@@ -122,63 +74,52 @@
      *                              fallback
      * @exception SOAPException if there is a SOAP error
      */
-    static Object find(String factoryId, String defaultClassName,
-                       boolean tryFallback) throws SOAPException {
-        ClassLoader classLoader;
-        try {
-            classLoader = Thread.currentThread().getContextClassLoader();
-        } catch (Exception x) {
-            throw new SOAPException(x.toString(), x);
-        }
+    @SuppressWarnings("unchecked")
+    static <T> T find(Class<T> factoryClass,
+                      String defaultClassName,
+                      boolean tryFallback, String deprecatedFactoryId) throws SOAPException {
+
+        ClassLoader tccl = ServiceLoaderUtil.contextClassLoader(EXCEPTION_HANDLER);
+        String factoryId = factoryClass.getName();
 
         // Use the system property first
-        try {
-            String systemProp =
-                    System.getProperty( factoryId );
-            if( systemProp!=null) {
-                return newInstance(systemProp, classLoader);
+        String className = fromSystemProperty(factoryId, deprecatedFactoryId);
+        if (className != null) {
+            Object result = newInstance(className, defaultClassName, tccl);
+            if (result != null) {
+                return (T) result;
             }
-        } catch (SecurityException se) {
         }
 
         // try to read from $java.home/lib/jaxm.properties
-        try {
-            String javah=System.getProperty( "java.home" );
-            String configFile = javah + File.separator +
-                    "lib" + File.separator + "jaxm.properties";
-            File f=new File( configFile );
-            if( f.exists()) {
-                Properties props=new Properties();
-                props.load( new FileInputStream(f));
-                String factoryClassName = props.getProperty(factoryId);
-                return newInstance(factoryClassName, classLoader);
+        className = fromJDKProperties(factoryId, deprecatedFactoryId);
+        if (className != null) {
+            Object result = newInstance(className, defaultClassName, tccl);
+            if (result != null) {
+                return (T) result;
             }
-        } catch(Exception ex ) {
         }
 
-        String serviceId = "META-INF/services/" + factoryId;
-        // try to find services in CLASSPATH
-        try {
-            InputStream is=null;
-            if (classLoader == null) {
-                is=ClassLoader.getSystemResourceAsStream(serviceId);
-            } else {
-                is=classLoader.getResourceAsStream(serviceId);
-            }
+        // standard services: java.util.ServiceLoader
+        T factory = ServiceLoaderUtil.firstByServiceLoader(
+                factoryClass,
+                logger,
+                EXCEPTION_HANDLER);
+        if (factory != null) {
+            return factory;
+        }
 
-            if( is!=null ) {
-                BufferedReader rd =
-                        new BufferedReader(new InputStreamReader(is, "UTF-8"));
-
-                String factoryClassName = rd.readLine();
-                rd.close();
-
-                if (factoryClassName != null &&
-                        ! "".equals(factoryClassName)) {
-                    return newInstance(factoryClassName, classLoader);
-                }
+        // try to find services in CLASSPATH
+        className = fromMetaInfServices(deprecatedFactoryId, tccl);
+        if (className != null) {
+            logger.log(Level.WARNING,
+                    "Using deprecated META-INF/services mechanism with non-standard property: {0}. " +
+                            "Property {1} should be used instead.",
+                    new Object[]{deprecatedFactoryId, factoryId});
+            Object result = newInstance(className, defaultClassName, tccl);
+            if (result != null) {
+                return (T) result;
             }
-        } catch( Exception ex ) {
         }
 
         // If not found and fallback should not be tried, return a null result.
@@ -191,46 +132,133 @@
             throw new SOAPException(
                     "Provider for " + factoryId + " cannot be found", null);
         }
-        return newInstance(defaultClassName, classLoader);
+        return (T) newInstance(defaultClassName, defaultClassName, tccl);
+    }
+
+    // in most cases there is no deprecated factory id
+    static <T> T find(Class<T> factoryClass,
+                      String defaultClassName,
+                      boolean tryFallback) throws SOAPException {
+        return find(factoryClass, defaultClassName, tryFallback, null);
+    }
+
+    private static Object newInstance(String className, String defaultClassName, ClassLoader tccl) throws SOAPException {
+        return ServiceLoaderUtil.newInstance(
+                className,
+                defaultClassName,
+                tccl,
+                EXCEPTION_HANDLER);
     }
 
-    /**
-     * Loads the class, provided that the calling thread has an access to the
-     * class being loaded. If this is the specified default factory class and it
-     * is restricted by package.access we get a SecurityException and can do a
-     * Class.forName() on it so it will be loaded by the bootstrap class loader.
-     */
-    private static Class safeLoadClass(String className,
-                                       ClassLoader classLoader)
-            throws ClassNotFoundException {
-        try {
-            // make sure that the current thread has an access to the package of the given name.
-            SecurityManager s = System.getSecurityManager();
-            if (s != null) {
-                int i = className.lastIndexOf('.');
-                if (i != -1) {
-                    s.checkPackageAccess(className.substring(0, i));
+    // used only for deprecatedFactoryId;
+    // proper factoryId searched by java.util.ServiceLoader
+    private static String fromMetaInfServices(String deprecatedFactoryId, ClassLoader tccl) {
+        String serviceId = "META-INF/services/" + deprecatedFactoryId;
+        logger.log(Level.FINE, "Checking deprecated {0} resource", serviceId);
+
+        try (InputStream is =
+                     tccl == null ?
+                             ClassLoader.getSystemResourceAsStream(serviceId)
+                             :
+                             tccl.getResourceAsStream(serviceId)) {
+
+            if (is != null) {
+                String factoryClassName;
+                try (InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
+                     BufferedReader rd = new BufferedReader(isr)) {
+                    factoryClassName = rd.readLine();
+                }
+
+                logFound(factoryClassName);
+                if (factoryClassName != null && !"".equals(factoryClassName)) {
+                    return factoryClassName;
                 }
             }
 
-            if (classLoader == null)
-                return Class.forName(className);
-            else
-                return classLoader.loadClass(className);
-        } catch (SecurityException se) {
-            // (only) default implementation can be loaded
-            // using bootstrap class loader:
-            if (isDefaultImplementation(className))
-                return Class.forName(className);
+        } catch (IOException e) {
+            // keep original behavior
+        }
+        return null;
+    }
+
+    private static String fromJDKProperties(String factoryId, String deprecatedFactoryId) {
+        Path path = null;
+        try {
+            String JAVA_HOME = System.getProperty("java.home");
+            path = Paths.get(JAVA_HOME, "conf", "jaxm.properties");
+            logger.log(Level.FINE, "Checking configuration in {0}", path);
+
+            // to ensure backwards compatibility
+            if (!Files.exists(path)) {
+                path = Paths.get(JAVA_HOME, "lib", "jaxm.properties");
+            }
+
+            logger.log(Level.FINE, "Checking configuration in {0}", path);
+            if (Files.exists(path)) {
+                Properties props = new Properties();
+                try (InputStream inputStream = Files.newInputStream(path)) {
+                    props.load(inputStream);
+                }
+
+                // standard property
+                logger.log(Level.FINE, "Checking property {0}", factoryId);
+                String factoryClassName = props.getProperty(factoryId);
+                logFound(factoryClassName);
+                if (factoryClassName != null) {
+                    return factoryClassName;
+                }
 
-            throw se;
+                // deprecated property
+                if (deprecatedFactoryId != null) {
+                    logger.log(Level.FINE, "Checking deprecated property {0}", deprecatedFactoryId);
+                    factoryClassName = props.getProperty(deprecatedFactoryId);
+                    logFound(factoryClassName);
+                    if (factoryClassName != null) {
+                        logger.log(Level.WARNING,
+                                "Using non-standard property: {0}. Property {1} should be used instead.",
+                                new Object[]{deprecatedFactoryId, factoryId});
+                        return factoryClassName;
+                    }
+                }
+            }
+        } catch (Exception ignored) {
+            logger.log(Level.SEVERE, "Error reading SAAJ configuration from ["  + path +
+                    "] file. Check it is accessible and has correct format.", ignored);
+        }
+        return null;
+    }
+
+    private static String fromSystemProperty(String factoryId, String deprecatedFactoryId) {
+        String systemProp = getSystemProperty(factoryId);
+        if (systemProp != null) {
+            return systemProp;
+        }
+        if (deprecatedFactoryId != null) {
+            systemProp = getSystemProperty(deprecatedFactoryId);
+            if (systemProp != null) {
+                logger.log(Level.WARNING,
+                        "Using non-standard property: {0}. Property {1} should be used instead.",
+                        new Object[] {deprecatedFactoryId, factoryId});
+                return systemProp;
+            }
+        }
+        return null;
+    }
+
+    private static String getSystemProperty(String property) {
+        logger.log(Level.FINE, "Checking system property {0}", property);
+        String value = AccessController.doPrivileged(
+                (PrivilegedAction<String>) () -> System.getProperty(property));
+        logFound(value);
+        return value;
+    }
+
+    private static void logFound(String value) {
+        if (value != null) {
+            logger.log(Level.FINE, "  found {0}", value);
+        } else {
+            logger.log(Level.FINE, "  not found");
         }
     }
 
-    private static boolean isDefaultImplementation(String className) {
-        return MessageFactory.DEFAULT_MESSAGE_FACTORY.equals(className) ||
-                SOAPFactory.DEFAULT_SOAP_FACTORY.equals(className) ||
-                SOAPConnectionFactory.DEFAULT_SOAP_CONNECTION_FACTORY.equals(className) ||
-                SAAJMetaFactory.DEFAULT_META_FACTORY_CLASS.equals(className);
-    }
 }
--- a/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/MessageFactory.java	Wed Jul 05 21:00:56 2017 +0200
+++ b/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/MessageFactory.java	Fri Nov 27 11:28:43 2015 +0100
@@ -68,27 +68,15 @@
  */
 public abstract class MessageFactory {
 
-    static final String DEFAULT_MESSAGE_FACTORY
+    private static final String DEFAULT_MESSAGE_FACTORY
         = "com.sun.xml.internal.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl";
 
-    static private final String MESSAGE_FACTORY_PROPERTY
-        = "javax.xml.soap.MessageFactory";
-
     /**
      * Creates a new {@code MessageFactory} object that is an instance
-     * of the default implementation (SOAP 1.1),
+     * of the default implementation (SOAP 1.1).
      *
-     * This method uses the following ordered lookup procedure to determine the MessageFactory implementation class to load:
-     * <UL>
-     *  <LI> Use the javax.xml.soap.MessageFactory system property.
-     *  <LI> Use the properties file "lib/jaxm.properties" in the JRE directory. This configuration file is in standard
-     * java.util.Properties format and contains the fully qualified name of the implementation class with the key being the
-     * system property defined above.
-     *  <LI> Use the Services API (as detailed in the JAR specification), if available, to determine the classname. The Services API
-     * will look for a classname in the file META-INF/services/javax.xml.soap.MessageFactory in jars available to the runtime.
-     *  <LI> Use the SAAJMetaFactory instance to locate the MessageFactory implementation class.
-     * </UL>
-
+     * This method uses the lookup procedure specified in {@link javax.xml.soap} to locate and load the
+     * {@link javax.xml.soap.MessageFactory} class.
      *
      * @return a new instance of a {@code MessageFactory}
      *
@@ -103,7 +91,7 @@
 
         try {
             MessageFactory factory = (MessageFactory) FactoryFinder.find(
-                    MESSAGE_FACTORY_PROPERTY,
+                    MessageFactory.class,
                     DEFAULT_MESSAGE_FACTORY,
                     false);
 
--- a/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/SAAJMetaFactory.java	Wed Jul 05 21:00:56 2017 +0200
+++ b/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/SAAJMetaFactory.java	Fri Nov 27 11:28:43 2015 +0100
@@ -27,25 +27,49 @@
 
 /**
 * The access point for the implementation classes of the factories defined in the
-* SAAJ API. All of the {@code newInstance} methods defined on factories in
-* SAAJ 1.3 defer to instances of this class to do the actual object creation.
+* SAAJ API. The {@code newInstance} methods defined on factories {@link SOAPFactory} and
+* {@link MessageFactory} in SAAJ 1.3 defer to instances of this class to do the actual object creation.
 * The implementations of {@code newInstance()} methods (in SOAPFactory and MessageFactory)
 * that existed in SAAJ 1.2 have been updated to also delegate to the SAAJMetaFactory when the SAAJ 1.2
 * defined lookup fails to locate the Factory implementation class name.
 *
 * <p>
-* SAAJMetaFactory is a service provider interface. There are no public methods on this
+* SAAJMetaFactory is a service provider interface and it uses similar lookup mechanism as other SAAJ factories
+* to get actual instance:
+*
+* <ul>
+*  <li>If a system property with name {@code javax.xml.soap.SAAJMetaFactory} exists then its value is assumed
+*  to be the fully qualified name of the implementation class. This phase of the look up enables per-JVM
+*  override of the SAAJ implementation.
+*  <li>If a system property with name {@code javax.xml.soap.MetaFactory} exists then its value is assumed
+*  to be the fully qualified name of the implementation class. This property, defined by previous specifications
+ * (up to 1.3), is still supported, but it is strongly recommended to migrate to new property
+ * {@code javax.xml.soap.SAAJMetaFactory}.
+*  <li>Use the configuration file "jaxm.properties". The file is in standard {@link java.util.Properties} format
+*  and typically located in the {@code conf} directory of the Java installation. It contains the fully qualified
+*  name of the implementation class with key {@code javax.xml.soap.SAAJMetaFactory}. If no such property is defined,
+ * again, property with key {@code javax.xml.soap.MetaFactory} is used. It is strongly recommended to migrate to
+ * new property {@code javax.xml.soap.SAAJMetaFactory}.
+*  <li> Use the service-provider loading facilities, defined by the {@link java.util.ServiceLoader} class,
+*  to attempt to locate and load an implementation of the service using the {@linkplain
+*  java.util.ServiceLoader#load(java.lang.Class) default loading mechanism}.
+*  <li> Finally, if all the steps above fail, platform default implementation is used.
+* </ul>
+*
+* <p>
+* There are no public methods on this
 * class.
 *
 * @author SAAJ RI Development Team
 * @since 1.6, SAAJ 1.3
 */
+public abstract class SAAJMetaFactory {
 
-public abstract class SAAJMetaFactory {
-    static private final String META_FACTORY_CLASS_PROPERTY =
-        "javax.xml.soap.MetaFactory";
-    static final String DEFAULT_META_FACTORY_CLASS =
-        "com.sun.xml.internal.messaging.saaj.soap.SAAJMetaFactoryImpl";
+    private static final String META_FACTORY_DEPRECATED_CLASS_PROPERTY =
+            "javax.xml.soap.MetaFactory";
+
+    private static final String DEFAULT_META_FACTORY_CLASS =
+            "com.sun.xml.internal.messaging.saaj.soap.SAAJMetaFactoryImpl";
 
     /**
      * Creates a new instance of a concrete {@code SAAJMetaFactory} object.
@@ -54,27 +78,20 @@
      * implementation. Service providers provide the name of their {@code SAAJMetaFactory}
      * implementation.
      *
-     * This method uses the following ordered lookup procedure to determine the SAAJMetaFactory implementation class to load:
-     * <UL>
-     *  <LI> Use the javax.xml.soap.MetaFactory system property.
-     *  <LI> Use the properties file "lib/jaxm.properties" in the JRE directory. This configuration file is in standard
-     * java.util.Properties format and contains the fully qualified name of the implementation class with the key being the
-     * system property defined above.
-     *  <LI> Use the Services API (as detailed in the JAR specification), if available, to determine the classname. The Services API
-     * will look for a classname in the file META-INF/services/javax.xml.soap.MetaFactory in jars available to the runtime.
-     *  <LI> Default to com.sun.xml.internal.messaging.saaj.soap.SAAJMetaFactoryImpl.
-     * </UL>
+     * This method uses the lookup procedure specified in {@link javax.xml.soap} to locate and load the
+     * {@link javax.xml.soap.SAAJMetaFactory} class.
      *
      * @return a concrete {@code SAAJMetaFactory} object
      * @exception SOAPException if there is an error in creating the {@code SAAJMetaFactory}
      */
     static SAAJMetaFactory getInstance() throws SOAPException {
             try {
-                SAAJMetaFactory instance =
-                    (SAAJMetaFactory) FactoryFinder.find(
-                        META_FACTORY_CLASS_PROPERTY,
-                        DEFAULT_META_FACTORY_CLASS);
-                return instance;
+                return FactoryFinder.find(
+                        SAAJMetaFactory.class,
+                        DEFAULT_META_FACTORY_CLASS,
+                        true,
+                        META_FACTORY_DEPRECATED_CLASS_PROPERTY);
+
             } catch (Exception e) {
                 throw new SOAPException(
                     "Unable to create SAAJ meta-factory" + e.getMessage());
@@ -88,6 +105,7 @@
       * the given {@code String} protocol.
       *
       * @param protocol a {@code String} indicating the protocol
+      * @return a {@link MessageFactory}, not null
       * @exception SOAPException if there is an error in creating the
       *            MessageFactory
       * @see SOAPConstants#SOAP_1_1_PROTOCOL
@@ -102,6 +120,7 @@
       * the given {@code String} protocol.
       *
       * @param protocol a {@code String} indicating the protocol
+      * @return a {@link SOAPFactory}, not null
       * @exception SOAPException if there is an error in creating the
       *            SOAPFactory
       * @see SOAPConstants#SOAP_1_1_PROTOCOL
--- a/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/SOAPConnectionFactory.java	Wed Jul 05 21:00:56 2017 +0200
+++ b/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/SOAPConnectionFactory.java	Fri Nov 27 11:28:43 2015 +0100
@@ -36,23 +36,21 @@
  * @since 1.6
  */
 public abstract class SOAPConnectionFactory {
+
     /**
      * A constant representing the default value for a {@code SOAPConnection}
      * object. The default is the point-to-point SOAP connection.
      */
-    static final String DEFAULT_SOAP_CONNECTION_FACTORY
-        = "com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnectionFactory";
-
-    /**
-     * A constant representing the {@code SOAPConnection} class.
-     */
-    static private final String SF_PROPERTY
-        = "javax.xml.soap.SOAPConnectionFactory";
+    private static final String DEFAULT_SOAP_CONNECTION_FACTORY
+            = "com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnectionFactory";
 
     /**
      * Creates an instance of the default
      * {@code SOAPConnectionFactory} object.
      *
+     * This method uses the lookup procedure specified in {@link javax.xml.soap} to locate and load the
+     * {@link javax.xml.soap.SOAPConnectionFactory} class.
+     *
      * @return a new instance of a default
      *         {@code SOAPConnectionFactory} object
      *
@@ -66,9 +64,10 @@
         throws SOAPException, UnsupportedOperationException
     {
         try {
-        return (SOAPConnectionFactory)
-                FactoryFinder.find(SF_PROPERTY,
-                                   DEFAULT_SOAP_CONNECTION_FACTORY);
+            return FactoryFinder.find(
+                    SOAPConnectionFactory.class,
+                    DEFAULT_SOAP_CONNECTION_FACTORY,
+                    true);
         } catch (Exception ex) {
             throw new SOAPException("Unable to create SOAP connection factory: "
                                     +ex.getMessage());
--- a/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/SOAPFactory.java	Wed Jul 05 21:00:56 2017 +0200
+++ b/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/SOAPFactory.java	Fri Nov 27 11:28:43 2015 +0100
@@ -48,17 +48,10 @@
 public abstract class SOAPFactory {
 
     /**
-     * A constant representing the property used to lookup the name of
-     * a {@code SOAPFactory} implementation class.
-     */
-    static private final String SOAP_FACTORY_PROPERTY =
-        "javax.xml.soap.SOAPFactory";
-
-    /**
      * Class name of default {@code SOAPFactory} implementation.
      */
-    static final String DEFAULT_SOAP_FACTORY
-        = "com.sun.xml.internal.messaging.saaj.soap.ver1_1.SOAPFactory1_1Impl";
+    private static final String DEFAULT_SOAP_FACTORY
+            = "com.sun.xml.internal.messaging.saaj.soap.ver1_1.SOAPFactory1_1Impl";
 
     /**
      * Creates a {@code SOAPElement} object from an existing DOM
@@ -239,18 +232,10 @@
 
     /**
      * Creates a new {@code SOAPFactory} object that is an instance of
-     * the default implementation (SOAP 1.1),
+     * the default implementation (SOAP 1.1).
      *
-     * This method uses the following ordered lookup procedure to determine the SOAPFactory implementation class to load:
-     * <UL>
-     *  <LI> Use the javax.xml.soap.SOAPFactory system property.
-     *  <LI> Use the properties file "lib/jaxm.properties" in the JRE directory. This configuration file is in standard
-     * java.util.Properties format and contains the fully qualified name of the implementation class with the key being the
-     * system property defined above.
-     *  <LI> Use the Services API (as detailed in the JAR specification), if available, to determine the classname. The Services API
-     * will look for a classname in the file META-INF/services/javax.xml.soap.SOAPFactory in jars available to the runtime.
-     *  <LI> Use the SAAJMetaFactory instance to locate the SOAPFactory implementation class.
-     * </UL>
+     * This method uses the lookup procedure specified in {@link javax.xml.soap} to locate and load the
+     * {@link javax.xml.soap.SOAPFactory} class.
      *
      * @return a new instance of a {@code SOAPFactory}
      *
@@ -262,10 +247,13 @@
         throws SOAPException
     {
         try {
-            SOAPFactory factory = (SOAPFactory) FactoryFinder.find(
-                    SOAP_FACTORY_PROPERTY, DEFAULT_SOAP_FACTORY, false);
-            if (factory != null)
-                return factory;
+            SOAPFactory factory = FactoryFinder.find(
+                    SOAPFactory.class,
+                    DEFAULT_SOAP_FACTORY,
+                    false);
+            if (factory != null) return factory;
+
+            // leave it on SAAJMetaFactory
             return newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
         } catch (Exception ex) {
             throw new SOAPException(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/ServiceLoaderUtil.java	Fri Nov 27 11:28:43 2015 +0100
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2015, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package javax.xml.soap;
+
+import java.util.ServiceLoader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Shared ServiceLoader/FactoryFinder Utils shared among SAAJ, JAXB and JAXWS
+ * Class duplicated to all those projects.
+ *
+ * @author Miroslav.Kos@oracle.com
+ */
+class ServiceLoaderUtil {
+
+    static <P, T extends Exception> P firstByServiceLoader(Class<P> spiClass,
+                                                           Logger logger,
+                                                           ExceptionHandler<T> handler) throws T {
+        logger.log(Level.FINE, "Using java.util.ServiceLoader to find {0}", spiClass.getName());
+        // service discovery
+        try {
+            ServiceLoader<P> serviceLoader = ServiceLoader.load(spiClass);
+
+            for (P impl : serviceLoader) {
+                logger.fine("ServiceProvider loading Facility used; returning object [" +
+                        impl.getClass().getName() + "]");
+
+                return impl;
+            }
+        } catch (Throwable t) {
+            throw handler.createException(t, "Error while searching for service [" + spiClass.getName() + "]");
+        }
+        return null;
+    }
+
+    static void checkPackageAccess(String className) {
+        // make sure that the current thread has an access to the package of the given name.
+        SecurityManager s = System.getSecurityManager();
+        if (s != null) {
+            int i = className.lastIndexOf('.');
+            if (i != -1) {
+                s.checkPackageAccess(className.substring(0, i));
+            }
+        }
+    }
+
+    static Class nullSafeLoadClass(String className, ClassLoader classLoader) throws ClassNotFoundException {
+        if (classLoader == null) {
+            return Class.forName(className);
+        } else {
+            return classLoader.loadClass(className);
+        }
+    }
+
+    // Returns instance of required class. It checks package access (security)
+    // unless it is defaultClassname. It means if you are trying to instantiate
+    // default implementation (fallback), pass the class name to both first and second parameter.
+    static <T extends Exception> Object newInstance(String className,
+                                                    String defaultImplClassName, ClassLoader classLoader,
+                                                    final ExceptionHandler<T> handler) throws T {
+        try {
+            return safeLoadClass(className, defaultImplClassName, classLoader).newInstance();
+        } catch (ClassNotFoundException x) {
+            throw handler.createException(x, "Provider " + className + " not found");
+        } catch (Exception x) {
+            throw handler.createException(x, "Provider " + className + " could not be instantiated: " + x);
+        }
+    }
+
+    static Class safeLoadClass(String className,
+                               String defaultImplClassName,
+                               ClassLoader classLoader) throws ClassNotFoundException {
+
+        try {
+            checkPackageAccess(className);
+        } catch (SecurityException se) {
+            // anyone can access the platform default factory class without permission
+            if (defaultImplClassName != null && defaultImplClassName.equals(className)) {
+                return Class.forName(className);
+            }
+            // not platform default implementation ...
+            throw se;
+        }
+        return nullSafeLoadClass(className, classLoader);
+    }
+
+    static <T extends Exception> ClassLoader contextClassLoader(ExceptionHandler<T> exceptionHandler) throws T {
+        try {
+            return Thread.currentThread().getContextClassLoader();
+        } catch (Exception x) {
+            throw exceptionHandler.createException(x, x.toString());
+        }
+    }
+
+    static abstract class ExceptionHandler<T extends Exception> {
+
+        public abstract T createException(Throwable throwable, String message);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxws/src/java.xml.ws/share/classes/javax/xml/soap/package-info.java	Fri Nov 27 11:28:43 2015 +0100
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2005, 2015, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+/**
+ * Provides the API for creating and building SOAP messages. This package
+ * is defined in the <i>SOAP with Attachments API for Java<sup><font size="-2">TM</font></sup>
+ * (SAAJ) 1.4</i> specification.
+ *
+ * <p> The API in the <code>javax.xml.soap</code> package allows you to do the following:
+ *
+ * <ul>
+ *     <li>create a point-to-point connection to a specified endpoint
+ *     <li>create a SOAP message
+ *     <li>create an XML fragment
+ *     <li>add content to the header of a SOAP message
+ *     <li>add content to the body of a SOAP message
+ *     <li>create attachment parts and add content to them
+ *     <li>access/add/modify parts of a SOAP message
+ *     <li>create/add/modify SOAP fault information
+ *     <li>extract content from a SOAP message
+ *     <li>send a SOAP request-response message
+ * </ul>
+ *
+ * <p>
+ * In addition the APIs in the <code>javax.xml.soap</code> package extend
+ * their  counterparts in the <code>org.w3c.dom</code> package. This means that
+ * the  <code>SOAPPart</code> of a <code>SOAPMessage</code> is also a DOM Level
+ * 2 <code>Document</code>, and can be manipulated as such by applications,
+ * tools and libraries that use DOM (see http://www.w3.org/DOM/ for more information).
+ * It is important to note that, while it is possible to use DOM APIs to add
+ * ordinary DOM nodes to a SAAJ tree, the SAAJ APIs are still required to return
+ * SAAJ types when examining or manipulating the tree. In order to accomplish
+ * this the SAAJ APIs (specifically {@link javax.xml.soap.SOAPElement#getChildElements()})
+ * are allowed to silently replace objects that are incorrectly typed relative
+ * to SAAJ requirements with equivalent objects of the required type. These
+ * replacements must never cause the logical structure of the tree to change,
+ * so from the perspective of the DOM APIs the tree will remain unchanged. However,
+ * the physical composition of the tree will have changed so that references
+ * to the nodes that were replaced will refer to nodes that are no longer a
+ * part of the tree. The SAAJ APIs are not allowed to make these replacements
+ * if they are not required so the replacement objects will never subsequently
+ * be silently replaced by future calls to the SAAJ API.
+ * <p>
+ * What this means in practical terms is that an application that starts to use
+ * SAAJ APIs on a tree after manipulating it using DOM APIs must assume that the
+ * tree has been translated into an all SAAJ tree and that any references to objects
+ * within the tree that were obtained using DOM APIs are no longer valid. Switching
+ * from SAAJ APIs to DOM APIs is not allowed to cause invalid references and
+ * neither is using SAAJ APIs exclusively. It is only switching from using DOM
+ * APIs on a particular SAAJ tree to using SAAJ APIs that causes the risk of
+ * invalid references.
+ *
+ * <h3>Discovery of SAAJ implementation</h3>
+ * <p>
+ * There are several factories defined in the SAAJ API to discover and load specific implementation:
+ *
+ * <ul>
+ *     <li>{@link javax.xml.soap.SOAPFactory}
+ *     <li>{@link javax.xml.soap.MessageFactory}
+ *     <li>{@link javax.xml.soap.SOAPConnectionFactory}
+ *     <li>{@link javax.xml.soap.SAAJMetaFactory}
+ * </ul>
+ *
+ * First three define {@code newInstance()} method which uses a common lookup procedure to determine
+ * the implementation class:
+ *
+ * <ul>
+ *  <li>Checks if a system property with the same name as the factory class is set (e.g.
+ *  {@code javax.xml.soap.SOAPFactory}). If such property exists then its value is assumed to be the fully qualified
+ *  name of the implementation class. This phase of the look up enables per-JVM override of the SAAJ implementation.
+ *  <li>Use the configuration file "jaxm.properties". The file is in standard
+ *  {@link java.util.Properties} format and typically located in the
+ *  {@code conf} directory of the Java installation. It contains the fully qualified
+ *  name of the implementation class with the key being the system property
+ *  defined above.
+ *  <li> Use the service-provider loading facilities, defined by the {@link java.util.ServiceLoader} class,
+ *  to attempt to locate and load an implementation of the service using the {@linkplain
+ *  java.util.ServiceLoader#load(java.lang.Class) default loading mechanism}.
+ *  <li> Finally, if all the steps above fail, {@link javax.xml.soap.SAAJMetaFactory} instance is used
+ *  to locate specific implementation (for {@link javax.xml.soap.MessageFactory} and {@link javax.xml.soap.SOAPFactory})
+ *  or platform default implementation is used ({@link javax.xml.soap.SOAPConnectionFactory}).
+ *  Whenever {@link javax.xml.soap.SAAJMetaFactory} is used, its lookup procedure to get actual instance is performed.
+ * </ul>
+ */
+package javax.xml.soap;