All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.oasisopen.sca.client.impl.SCAClientFactoryFinderImpl Maven / Gradle / Ivy

There is a newer version: 2.0.1
Show newest version
/*
 * 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);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy