8131334: SAAJ Plugability Layer: using java.util.ServiceLoader
Reviewed-by: lancea
This commit is contained in:
parent
d13176b6ba
commit
4c4de3a28b
@ -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 @@ class FactoryFinder {
|
||||
* 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;
|
||||
// standard services: java.util.ServiceLoader
|
||||
T factory = ServiceLoaderUtil.firstByServiceLoader(
|
||||
factoryClass,
|
||||
logger,
|
||||
EXCEPTION_HANDLER);
|
||||
if (factory != null) {
|
||||
return factory;
|
||||
}
|
||||
|
||||
// try to find services in CLASSPATH
|
||||
try {
|
||||
InputStream is=null;
|
||||
if (classLoader == null) {
|
||||
is=ClassLoader.getSystemResourceAsStream(serviceId);
|
||||
} else {
|
||||
is=classLoader.getResourceAsStream(serviceId);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
} catch( Exception ex ) {
|
||||
}
|
||||
|
||||
// If not found and fallback should not be tried, return a null result.
|
||||
@ -191,46 +132,133 @@ class FactoryFinder {
|
||||
throw new SOAPException(
|
||||
"Provider for " + factoryId + " cannot be found", null);
|
||||
}
|
||||
return newInstance(defaultClassName, classLoader);
|
||||
return (T) newInstance(defaultClassName, defaultClassName, tccl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
throw se;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -68,27 +68,15 @@ import java.io.InputStream;
|
||||
*/
|
||||
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 @@ public abstract class MessageFactory {
|
||||
|
||||
try {
|
||||
MessageFactory factory = (MessageFactory) FactoryFinder.find(
|
||||
MESSAGE_FACTORY_PROPERTY,
|
||||
MessageFactory.class,
|
||||
DEFAULT_MESSAGE_FACTORY,
|
||||
false);
|
||||
|
||||
|
@ -27,25 +27,49 @@ package javax.xml.soap;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
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 @@ public abstract class SAAJMetaFactory {
|
||||
* 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 @@ public abstract class SAAJMetaFactory {
|
||||
* 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 @@ public abstract class SAAJMetaFactory {
|
||||
* 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
|
||||
|
@ -36,23 +36,21 @@ package javax.xml.soap;
|
||||
* @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 @@ public abstract class SOAPConnectionFactory {
|
||||
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());
|
||||
|
@ -47,18 +47,11 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
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 @@ public abstract class SOAPFactory {
|
||||
|
||||
/**
|
||||
* 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 @@ public abstract class SOAPFactory {
|
||||
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(
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
Loading…
Reference in New Issue
Block a user