/* * Copyright(C) OASIS(R) 2005,2009. All Rights Reserved. * OASIS trademark, IPR and other policies apply. */ package org.oasisopen.sca.client.impl; import java.io.BufferedReader; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.Properties; import org.oasisopen.sca.SCARuntimeException; import org.oasisopen.sca.client.SCAClientFactory; /** * This is a default class that returns an SCAClientFactory implementation - * this class can be replaced by a vendor implementation. * * @see SCAClientFactory * @author OASIS Open */ public class 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 2488 the SPI * implementation to use for the SCAClientFactory. 2489 */ private static final String SCA_CLIENT_FACTORY_PROVIDER_META_INF_SERVICE = "META-INF/services/" + SCA_CLIENT_FACTORY_PROVIDER_KEY; /** * Private Constructor. */ private SCAClientFactoryFinder() { } /** * Creates an instance of the SCAClientFactory implementation. This * discovers the SCAClientFactory 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 * @return new instance of the SCAClientFactory * @throws SCARuntimeException Failed to create SCAClientFactory * implementation. */ public static SCAClientFactory find(Properties properties, ClassLoader classLoader) { if (classLoader == null) { classLoader = getThreadContextClassLoader(); if (classLoader == null) { classLoader = SCAClientFactoryFinder.class.getClassLoader(); } } final String factoryImplClassName = discoverProviderFactoryImplClass(properties, classLoader); final Class factoryImplClass = loadProviderFactoryClass(factoryImplClassName, classLoader); final SCAClientFactory factory = instantiateSCAClientFactoryClass(factoryImplClass); return factory; } /** * Gets the Context ClassLoader for the current Thread. * * @return The Context ClassLoader for the current Thread. */ private static ClassLoader getThreadContextClassLoader() { final ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader(); return threadClassLoader; } /** * Attempts to discover the class name for the SCAClientFactory * implementation from the specified Properties, the System Properties or * the specified ClassLoader. * * @return The class name of the SCAClientFactory implementation * @throw SCARuntimeException Failed to find implementation for * SCAClientFactory. */ private static String discoverProviderFactoryImplClass(Properties properties, ClassLoader classLoader) throws SCARuntimeException { String providerClassName = checkPropertiesForSPIClassName(properties); if (providerClassName != null) { return providerClassName; } providerClassName = checkPropertiesForSPIClassName(System.getProperties()); if (providerClassName != null) { return providerClassName; } return checkMETAINFServicesForClassName(classLoader); } /** * Attempts to find the class name for the SCAClientFactory implementation * from the specified Properties. * * @return The class name for the SCAClientFactory 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 SCAClientFactory implementation * from the META-INF/services directory * * @return The class name for the SCAClientFactory implementation or * null if not found. */ private static String checkMETAINFServicesForClassName(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 SCARuntimeException("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 * @return The specified SCAClientFactory Implementation class * @throws SCARuntimeException Failed to load the SCAClientFactory * implementation class */ private static Class loadProviderFactoryClass(String factoryImplClassName, ClassLoader classLoader) throws SCARuntimeException { try { final Class providerClass = classLoader.loadClass(factoryImplClassName); final Class providerFactoryClass = providerClass.asSubclass(SCAClientFactory.class); return providerFactoryClass; } catch (ClassNotFoundException ex) { throw new SCARuntimeException("Failed to load SCAClientFactory implementation class " + factoryImplClassName, ex); } catch (ClassCastException ex) { throw new SCARuntimeException("Loaded SCAClientFactory implementation class " + factoryImplClassName + " is not a subclass of " + SCAClientFactory.class.getName(), ex); } } /** * Instantiate an instance of the specified SCAClientFactory implementation * class. * * @param factoryImplClass The SCAClientFactory implementation class to * instantiate. * @return An instance of the SCAClientFactory implementation class * @throws SCARuntimeException Failed to instantiate the specified specified * SCAClientFactory implementation class */ private static SCAClientFactory instantiateSCAClientFactoryClass(Class factoryImplClass) throws SCARuntimeException { try { final SCAClientFactory provider = factoryImplClass.newInstance(); return provider; } catch (Throwable ex) { throw new SCARuntimeException("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 SCARuntimeException("Failed to close stream", ex); } } } }