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

com.arjuna.common.internal.util.ClassloadingUtility Maven / Gradle / Ivy

The newest version!
/*
   Copyright The Narayana Authors
   SPDX-License-Identifier: Apache-2.0
 */

package com.arjuna.common.internal.util;

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.common.internal.util.propertyservice.BeanPopulator;
import com.arjuna.common.logging.commonLogger;

/**
 * Utility functions, used mainly by the EnvironmentBeans, for managing dynamic classloading.
 *
 * @author Jonathan Halliday ([email protected]) 2010-04
 */
public class ClassloadingUtility
{
    /**
     * 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) {
            commonLogger.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 loadClass(Class iface, String className)
    {
        if (commonLogger.logger.isTraceEnabled()) {
            commonLogger.logger.trace("Loading class " + className);
        }

        if (className == null) {
            commonLogger.i18NLogger.warn_common_ClassloadingUtility_1();
            return null;
        }

        Class clazz = loadClass( className );
        if(clazz == null) {
            return null;
        }

        try {
            Class clazz2 = clazz.asSubclass(iface);
            return clazz2;
        } catch (ClassCastException e) {
            commonLogger.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) {
        return loadAndInstantiateClass(iface, className, environmentBeanInstanceName, false);
    }

    public static  T loadAndInstantiateClass(Class iface, String className, String environmentBeanInstanceName,
                                                boolean failOnError) {
        T instance = null;

        try {
            Class clazz = loadClass(iface, className);
            if(clazz == null) {
                return null;
            }

            Constructor[] ctors = clazz.getConstructors();
            Class environmentBeanClass = null;
            for(Constructor constructor : ctors) {
                if(constructor.getParameterCount() == 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 | InvocationTargetException e) {
            String message = commonLogger.i18NLogger.warn_common_ClassloadingUtility_4(className, e);
            if (failOnError) {
                if (e.getCause() != null) {
                    throw new Error(message, e.getCause().fillInStackTrace());
                }
            }
            commonLogger.logger.warn(message);
        } catch (IllegalAccessException e) {
            String message = commonLogger.i18NLogger.warn_common_ClassloadingUtility_5(className, e);
            if (failOnError) {
                if (e.getCause() != null) {
                    throw new Error(message, e.getCause().fillInStackTrace());
                }
            }
            commonLogger.logger.warn(message);
        }

        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) {
                        commonLogger.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 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 = ';';
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy