com.iterranux.droolsjbpmCore.internal.AbstractGenericFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.iterranux.droolsjbpmCore.internal.AbstractGenericFactory.java

Source

/*
 * Copyright (c) 2013. Alexander Herwix
 * This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as
 *     published by the Free Software Foundation, either version 3 of the
 *     License, or (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * You can also obtain a commercial license. Contact: alex@herwix.com for further details.
 */

package com.iterranux.droolsjbpmCore.internal;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.annotation.PostConstruct;
import java.lang.reflect.*;
import java.util.*;

/**
 * Abstract Generic Factory that can be easily extended with new manufacturables.
 * The implementing generic factory needs to provide the class of manufacturables
 * as well as the specific production logic itself. Beans implementing the manufacturable
 * class are then automatically registered on init and can be used in the production logic.
 *
 * @param <T>
 */
public abstract class AbstractGenericFactory<T extends GenericFactoryManufacturable>
        implements ApplicationContextAware {

    protected ApplicationContext applicationContext;

    protected Map<String, T> manufacturableBeans;

    @PostConstruct
    @SuppressWarnings("unchecked")
    public void init() {
        Map<String, T> beanMap = new HashMap<String, T>();

        for (T bean : (Collection<T>) applicationContext.getBeansOfType(getManufacturableClass()).values()) {
            beanMap.put(bean.getManufacturableTypeName(), bean);
        }
        setManufacturableBeans(beanMap);
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    public Map<String, T> getManufacturableBeans() {
        return this.manufacturableBeans;
    }

    public void setManufacturableBeans(Map<String, T> manufacturableBeans) {
        this.manufacturableBeans = manufacturableBeans;
    }

    public T getManufacturableBean(String manufacturableName)
            throws InstantiationException, IllegalAccessException {

        return manufacturableBeans.get(manufacturableName);
    }

    /**
     * Reflection technique to determine the actual class of the generic at runtime.
     * http://www.artima.com/weblogs/viewpost.jsp?thread=208860
     */

    public Class getManufacturableClass() {
        return getTypeArguments(AbstractGenericFactory.class, getClass()).get(0);
    }

    /**
     * Get the underlying class for a type, or null if the type is a variable type.
     * @param type the type
     * @return the underlying class
     */
    public static Class<?> getClass(Type type) {

        if (type instanceof Class) {
            return (Class) type;
        } else if (type instanceof ParameterizedType) {
            return getClass(((ParameterizedType) type).getRawType());
        } else if (type instanceof GenericArrayType) {
            Type componentType = ((GenericArrayType) type).getGenericComponentType();
            Class<?> componentClass = getClass(componentType);
            if (componentClass != null) {
                return Array.newInstance(componentClass, 0).getClass();
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * Get the actual type arguments a child class has used to extend a generic base class.
     *
     * @param baseClass the base class
     * @param childClass the child class
     * @return a list of the raw classes for the actual type arguments.
     */
    @SuppressWarnings("all")
    public static <T> List<Class<?>> getTypeArguments(Class<T> baseClass, Class<? extends T> childClass) {

        Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
        Type type = childClass;
        // start walking up the inheritance hierarchy until we hit baseClass
        while (!getClass(type).equals(baseClass)) {
            if (type instanceof Class) {
                // there is no useful information for us in raw types, so just keep going.
                type = ((Class) type).getGenericSuperclass();
            } else {
                ParameterizedType parameterizedType = (ParameterizedType) type;

                Class<?> rawType = (Class) parameterizedType.getRawType();

                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
                }

                if (!rawType.equals(baseClass)) {
                    type = rawType.getGenericSuperclass();
                }
            }
        }

        // finally, for each actual type argument provided to baseClass, determine (if possible)
        // the raw class for that type argument.
        Type[] actualTypeArguments;
        if (type instanceof Class) {
            actualTypeArguments = ((Class) type).getTypeParameters();
        } else {
            actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
        }
        List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
        // resolve types by chasing down type variables.
        for (Type baseType : actualTypeArguments) {
            while (resolvedTypes.containsKey(baseType)) {
                baseType = resolvedTypes.get(baseType);
            }
            typeArgumentsAsClasses.add(getClass(baseType));
        }
        return typeArgumentsAsClasses;
    }
}