com.arjuna.ats.internal.arjuna.common.ClassloadingUtility Maven / Gradle / Ivy
The newest version!
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat, Inc. and/or its affiliates,
* and individual contributors as indicated by the @author tags.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2010,
* @author JBoss, by Red Hat.
*/
package com.arjuna.ats.internal.arjuna.common;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import com.arjuna.ats.arjuna.logging.tsLogger;
import com.arjuna.common.internal.util.propertyservice.BeanPopulator;
/**
* Utility functions, used mainly by the EnvironmentBeans, for managing dynamic classloading.
*
* @author Jonathan Halliday ([email protected]) 2010-04
*/
public class ClassloadingUtility
{
// this really belongs in common...
/**
* Load a class. No instantiation.
*
* In the event of error (ClassNotFound etc) this method will log the error and return null.
*
* @param className the name of the class to load and instantiate.
* @return the specified Class, or null.
*/
public static Class loadClass(String className) {
// This should be pretty much the only point in the codebase that actually does classloading.
// Once upon a time it used TCCL, but that does not play nice with AS and is fairly pointless
// anyhow, so we changed it... JBTM-828 and JBTM-735
Class clazz;
try
{
//clazz = Thread.currentThread().getContextClassLoader().loadClass( className ) ;
clazz = Class.forName( className );
} catch(ClassNotFoundException e) {
tsLogger.i18NLogger.warn_common_ClassloadingUtility_2(className, e);
return null;
}
return clazz;
}
/**
* Load and return the named class, which is expected to be an implementation of the specified interface.
*
* In the event of error (ClassNotFound, ClassCast, ...) this method will log the error and return null.
*
* @param iface the expected interface type.
* @param className the name of the class to load and instantiate.
* @return the specified class, or null.
*/
public static Class extends T> loadClass(Class iface, String className)
{
if (tsLogger.logger.isTraceEnabled()) {
tsLogger.logger.trace("Loading class " + className);
}
if (className == null) {
tsLogger.i18NLogger.warn_common_ClassloadingUtility_1();
return null;
}
Class> clazz = loadClass( className );
if(clazz == null) {
return null;
}
try {
Class extends T> clazz2 = clazz.asSubclass(iface);
return clazz2;
} catch (ClassCastException e) {
tsLogger.i18NLogger.warn_common_ClassloadingUtility_3(className, iface.getName(), e);
return null;
}
}
/**
* Load, instantiate and return an instance of the named class, which is expected to be an implementation of
* the specified interface.
*
* In the event of error (ClassNotFound, ClassCast, can't instantiate, ...) this method will log the error and return null.
*
*
* @param iface the expected interface type.
* @param className the name of the class to load and instantiate.
* @param environmentBeanInstanceName When the class ctor requires a *EnvironmentBean instance, the name of the bean.
* null for default ctor or default bean instance..
* @return an instance of the specified class, or null.
*/
public static T loadAndInstantiateClass(Class iface, String className, String environmentBeanInstanceName)
{
T instance = null;
try {
Class extends T> clazz = loadClass(iface, className);
if(clazz == null) {
return null;
}
Constructor[] ctors = clazz.getConstructors();
Class environmentBeanClass = null;
for(Constructor constructor : ctors) {
if(constructor.getParameterTypes().length == 1 &&
constructor.getParameterTypes()[0].getCanonicalName().endsWith("EnvironmentBean")) {
environmentBeanClass = constructor.getParameterTypes()[0];
Object envBean = BeanPopulator.getNamedInstance(environmentBeanClass, environmentBeanInstanceName);
instance = (T)constructor.newInstance(envBean);
break;
}
}
if(environmentBeanClass == null && environmentBeanInstanceName == null) {
// no bean ctor, try default ctor
instance = clazz.newInstance();
}
} catch (InstantiationException e) {
tsLogger.i18NLogger.warn_common_ClassloadingUtility_4(className, e);
} catch (IllegalAccessException e) {
tsLogger.i18NLogger.warn_common_ClassloadingUtility_5(className, e);
} catch(InvocationTargetException e) {
tsLogger.i18NLogger.warn_common_ClassloadingUtility_4(className, e);
}
return instance;
}
public static List loadAndInstantiateClasses(Class iface, List classNames)
{
List instances = new ArrayList();
if(classNames != null) {
for(String className : classNames)
{
T instance = loadAndInstantiateClass(iface, className, null);
if(instance != null)
{
instances.add(instance);
}
}
}
return instances;
}
public static List loadAndInstantiateClassesWithInit(Class iface, List classNamesWithOptionalInitParams)
{
List instances = new ArrayList();
if(classNamesWithOptionalInitParams != null) {
for(String theClassAndParameter : classNamesWithOptionalInitParams)
{
// see if there is a string parameter
int breakPosition = theClassAndParameter.indexOf(BREAKCHARACTER);
String theClass = null;
String theParameter = null;
if (breakPosition != -1)
{
theClass = theClassAndParameter.substring(0, breakPosition);
theParameter = theClassAndParameter.substring(breakPosition + 1);
}
else
{
theClass = theClassAndParameter;
}
T instance = loadAndInstantiateClass(iface, theClass, null);
if (theClass != null && theParameter != null)
{
try {
Method method = instance.getClass().getMethod("initialise", new Class[] {String.class}); // yup, UK English spelling
method.invoke(instance, theParameter);
} catch(Exception e) {
tsLogger.i18NLogger.warn_common_ClassloadingUtility_6(theClassAndParameter, e);
continue;
}
}
if(instance != null)
{
instances.add(instance);
}
}
}
return instances;
}
/**
* Reverse mapping - obtain the class name for a given Object.
*
* @param instance the Object of interest
* @return the class name of the Object, or null.
*/
public static String getNameForClass(Object instance)
{
if(instance == null) {
return null;
}
return instance.getClass().getName();
}
/**
* Reverse mapping - obtain the class names from a given set of Objects.
*
* If the input list is null a zero length list is returned.
* If the input list contains nulls, these will not be present in the returned list.
*
* @param instances a list of Objects of interest.
* @return a non-null list of zero or more elements, being class names of the Objects.
*/
public static List getNamesForClasses(List extends Object> instances)
{
List names = new ArrayList();
if(instances != null)
{
for(Object instance : instances)
{
String name = getNameForClass(instance);
if(name != null) {
names.add(name);
}
}
}
return names;
}
private static final char BREAKCHARACTER = ';';
}