org.oasisopen.sca.client.impl.SCAClientFactoryFinderImpl Maven / Gradle / Ivy
/*
* Copyright(C) OASIS(R) 2005,2010. All Rights Reserved.
* OASIS trademark, IPR and other policies apply.
*/
package org.oasisopen.sca.client.impl;
import org.oasisopen.sca.client.SCAClientFactoryFinder;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.net.URI;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Properties;
import org.oasisopen.sca.NoSuchDomainException;
import org.oasisopen.sca.ServiceRuntimeException;
import org.oasisopen.sca.client.SCAClientFactory;
/**
* This is a default implementation of an SCAClientFactoryFinder which is
* used to find an implementation of the SCAClientFactory interface.
*
* @see SCAClientFactoryFinder
* @see SCAClientFactory
*
* @author OASIS Open
*/
public class SCAClientFactoryFinderImpl implements SCAClientFactoryFinder {
/**
* The name of the System Property used to determine the SPI
* implementation to use for the SCAClientFactory.
*/
private static final String SCA_CLIENT_FACTORY_PROVIDER_KEY =
SCAClientFactory.class.getName();
/**
* The name of the file loaded from the ClassPath to determine
* the SPI implementation to use for the SCAClientFactory.
*/
private static final String SCA_CLIENT_FACTORY_PROVIDER_META_INF_SERVICE
= "META-INF/services/" + SCA_CLIENT_FACTORY_PROVIDER_KEY;
/**
* Public Constructor
*/
public SCAClientFactoryFinderImpl() {
}
/**
* Creates an instance of the SCAClientFactorySPI implementation.
* This discovers the SCAClientFactorySPI Implementation and instantiates
* the provider's implementation.
*
* @param properties Properties that may be used when creating a new
* instance of the SCAClient
* @param classLoader ClassLoader that may be used when creating a new
* instance of the SCAClient
* @param domainURI URI for the Domain to which this client instance is connected
* @return new instance of the SCAClientFactory
* @throws ServiceRuntimeException Failed to create SCAClientFactory
* Implementation.
*/
public SCAClientFactory find(Properties properties,
ClassLoader classLoader,
URI domainURI )
throws NoSuchDomainException, ServiceRuntimeException {
if (classLoader == null) {
classLoader = getThreadContextClassLoader ();
}
final String factoryImplClassName =
discoverProviderFactoryImplClass(properties, classLoader);
final Class factoryImplClass
= loadProviderFactoryClass(factoryImplClassName,
classLoader);
final SCAClientFactory factory =
instantiateSCAClientFactoryClass(factoryImplClass,
domainURI, properties );
return factory;
}
/**
* Gets the Context ClassLoader for the current Thread.
*
* @return The Context ClassLoader for the current Thread.
*/
private static ClassLoader getThreadContextClassLoader () {
return AccessController.doPrivileged(
new PrivilegedAction() {
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
});
}
/**
* Attempts to discover the class name for the SCAClientFactorySPI
* implementation from the specified Properties, the System Properties
* or the specified ClassLoader.
*
* @param properties Properties that may be used when creating a new
* instance of the SCAClient
* @param classLoader ClassLoader that may be used when creating a new
* instance of the SCAClient
* @return The class name of the SCAClientFactorySPI implementation
* @throw ServiceRuntimeException Failed to find implementation for
* SCAClientFactorySPI.
*/
private static String
discoverProviderFactoryImplClass(Properties properties,
ClassLoader classLoader)
throws ServiceRuntimeException {
String providerClassName =
checkPropertiesForSPIClassName(properties);
if (providerClassName != null) {
return providerClassName;
}
providerClassName =
checkPropertiesForSPIClassName(System.getProperties());
if (providerClassName != null) {
return providerClassName;
}
providerClassName = checkMETAINFServicesForSPIClassName(classLoader);
if (providerClassName == null) {
throw new ServiceRuntimeException(
"Failed to find implementation for SCAClientFactory");
}
return providerClassName;
}
/**
* Attempts to find the class name for the SCAClientFactorySPI
* implementation from the specified Properties.
*
* @param properties Properties that may be used when creating a new
* instance of the SCAClient
* @return The class name for the SCAClientFactorySPI implementation
* or null
if not found.
*/
private static String
checkPropertiesForSPIClassName(Properties properties) {
if (properties == null) {
return null;
}
final String providerClassName =
properties.getProperty(SCA_CLIENT_FACTORY_PROVIDER_KEY);
if (providerClassName != null && providerClassName.length() > 0) {
return providerClassName;
}
return null;
}
/**
* Attempts to find the class name for the SCAClientFactorySPI
* implementation from the META-INF/services directory
*
* @param cl ClassLoader that may be used when creating a new
* instance of the SCAClient
* @return The class name for the SCAClientFactorySPI implementation or
* null
if not found.
*/
private static String checkMETAINFServicesForSPIClassName(ClassLoader cl)
{
final URL url =
cl.getResource(SCA_CLIENT_FACTORY_PROVIDER_META_INF_SERVICE);
if (url == null) {
return null;
}
InputStream in = null;
try {
in = url.openStream();
BufferedReader reader = null;
try {
reader =
new BufferedReader(new InputStreamReader(in, "UTF-8"));
String line;
while ((line = readNextLine(reader)) != null) {
if (!line.startsWith("#") && line.length() > 0) {
return line;
}
}
return null;
} finally {
closeStream(reader);
}
} catch (IOException ex) {
throw new ServiceRuntimeException(
"Failed to discover SCAClientFactory provider", ex);
} finally {
closeStream(in);
}
}
/**
* Reads the next line from the reader and returns the trimmed version
* of that line
*
* @param reader The reader from which to read the next line
* @return The trimmed next line or null
if the end of the
* stream has been reached
* @throws IOException I/O error occurred while reading from Reader
*/
private static String readNextLine(BufferedReader reader)
throws IOException {
String line = reader.readLine();
if (line != null) {
line = line.trim();
}
return line;
}
/**
* Loads the specified SCAClientFactory Implementation class.
*
* @param factoryImplClassName The name of the SCAClientFactory
* Implementation class to load
* @param classLoader ClassLoader that may be used when creating a new
* instance of the SCAClient
* @return The specified SCAClientFactory Implementation class
* @throws ServiceRuntimeException Failed to load the SCAClientFactory
* Implementation class
*/
private static Class
loadProviderFactoryClass(String factoryImplClassName,
ClassLoader classLoader)
throws ServiceRuntimeException {
try {
final Class providerClass =
classLoader.loadClass(factoryImplClassName);
final Class providerFactoryClass =
providerClass.asSubclass(SCAClientFactory.class);
return providerFactoryClass;
} catch (ClassNotFoundException ex) {
throw new ServiceRuntimeException(
"Failed to load SCAClientFactory implementation class "
+ factoryImplClassName, ex);
} catch (ClassCastException ex) {
throw new ServiceRuntimeException(
"Loaded SCAClientFactory implementation class "
+ factoryImplClassName
+ " is not a subclass of "
+ SCAClientFactory.class.getName() , ex);
}
}
/**
* Instantiate an instance of the specified SCAClientFactorySPI
* Implementation class.
*
* @param factoryImplClass The SCAClientFactorySPI Implementation
* class to instantiate.
* @param domainURI URI for the Domain to which this client instance is connected
* @param properties Properties that may be used when creating a new
* instance of the SCAClient
* @return An instance of the SCAClientFactorySPI Implementation class
* @throws ServiceRuntimeException Failed to instantiate the specified
* specified SCAClientFactorySPI Implementation class
*/
private static SCAClientFactory instantiateSCAClientFactoryClass(
Class factoryImplClass,
URI domainURI, Properties properties)
throws NoSuchDomainException, ServiceRuntimeException {
try {
Constructor URIConstructor =
factoryImplClass.getConstructor(URI.class, Properties.class);
SCAClientFactory provider =
URIConstructor.newInstance( domainURI, properties );
return provider;
} catch (Throwable ex) {
throw new ServiceRuntimeException(
"Failed to instantiate SCAClientFactory implementation class "
+ factoryImplClass, ex);
}
}
/**
* Utility method for closing Closeable Object.
*
* @param closeable The Object to close.
*/
private static void closeStream(Closeable closeable) {
if (closeable != null) {
try{
closeable.close();
} catch (IOException ex) {
throw new ServiceRuntimeException("Failed to close stream",
ex);
}
}
}
}