org.jgentleframework.utils.Utils.java Source code

Java tutorial

Introduction

Here is the source code for org.jgentleframework.utils.Utils.java

Source

/*
 * Copyright 2007-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 * 
 * Project: JGentleFramework
 */
package org.jgentleframework.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastConstructor;

import org.aopalliance.intercept.Interceptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jgentleframework.configure.Configurable;
import org.jgentleframework.configure.REF;
import org.jgentleframework.configure.annotation.DefaultConstructor;
import org.jgentleframework.configure.annotation.Inject;
import org.jgentleframework.context.aop.support.MatcherPointcut;
import org.jgentleframework.context.injecting.ObjectBeanFactory;
import org.jgentleframework.context.injecting.Provider;
import org.jgentleframework.context.support.InstantiationSelector;
import org.jgentleframework.core.GenericException;
import org.jgentleframework.core.InvalidOperationException;
import org.jgentleframework.core.factory.InOutDependencyException;
import org.jgentleframework.core.factory.InOutExecutor;
import org.jgentleframework.core.factory.support.CachedConstructor;
import org.jgentleframework.core.factory.support.MetaDefObject;
import org.jgentleframework.core.handling.DefinitionManager;
import org.jgentleframework.core.intercept.JGentleFastClass;
import org.jgentleframework.core.intercept.support.CoreIdentification;
import org.jgentleframework.core.intercept.support.InterceptConditioner;
import org.jgentleframework.core.intercept.support.Matcher;
import org.jgentleframework.reflection.metadata.Definition;

/**
 * The Class Utils.
 * 
 * @author LE QUOC CHUNG - mailto: <a
 *         href="mailto:skydunkpro@yahoo.com">skydunkpro@yahoo.com</a>
 * @date Aug 20, 2007
 */
public final class Utils {
    /** The log. */
    private static final Log log = LogFactory.getLog(Utils.class);

    /**
     * Creates a construction proxy given a class and parameter types.
     * 
     * @param definition
     *            the definition
     * @param clazz
     *            the clazz
     * @param parameterTypes
     *            the parameter types
     * @return the cached constructor
     */
    public static CachedConstructor createConstructionProxy(final Definition definition, Class<?> clazz,
            Class<?>[] parameterTypes, final MetaDefObject mdo) {

        FastConstructor constructor = null;
        try {
            FastClass fastClass = JGentleFastClass.create(clazz);
            constructor = fastClass.getConstructor(parameterTypes);
        } catch (NoSuchMethodError e) {
            if (parameterTypes == null) {
                if (log.isErrorEnabled()) {
                    log.error("[" + clazz + "] does not declare public default constructor !", e);
                }
            } else {
                if (log.isErrorEnabled()) {
                    StringBuffer buffer = new StringBuffer();
                    for (int i = 0; i < parameterTypes.length; i++) {
                        buffer.append(parameterTypes[i].getName());
                        if (!(i + 1 >= parameterTypes.length))
                            buffer.append(",");
                    }
                    log.error("[" + clazz + "] does not declare constructor appropriate to these parameter types ["
                            + buffer.toString() + "]!", e);
                }
            }
        }
        final FastConstructor fastConstructor = constructor;
        return new CachedConstructor() {
            MetaDefObject mdoInner = mdo;

            @Override
            public int hashcodeID() {

                return definition.hashCode() ^ this.hashCode();
            }

            public Object newInstance(Object... arguments) throws InvocationTargetException {

                return fastConstructor.newInstance(arguments);
            }

            @Override
            public MetaDefObject getMetaDefObject() {

                return this.mdoInner;
            }

            @Override
            public void setMetaDefObject(MetaDefObject mdo) {

                this.mdoInner = mdo;
            }

            @Override
            public Constructor<?> getJavaConstructor() {

                return fastConstructor.getJavaConstructor();
            }
        };
    }

    /**
     * Creates the instance object from the given {@link Constructor}.
     * 
     * @param provider
     *            the current {@link Provider}
     * @param constructor
     *            the given {@link Constructor}
     * @return Object
     */
    public static Object createInstanceFromInjectedConstructor(Provider provider, Constructor<?> constructor) {

        Object result = null;
        // Khi to v inject dependency cho parameter
        Object[] args = new Object[constructor.getParameterTypes().length];
        for (int i = 0; i < constructor.getParameterAnnotations().length; i++) {
            Map<Class<? extends Annotation>, Annotation> annoList = new HashMap<Class<? extends Annotation>, Annotation>();
            List<Class<? extends Annotation>> clazzlist = new ArrayList<Class<? extends Annotation>>();
            for (Annotation anno : constructor.getParameterAnnotations()[i]) {
                annoList.put(anno.annotationType(), anno);
                clazzlist.add(anno.annotationType());
            }
            if (!clazzlist.contains(Inject.class)) {
                args[i] = null;
            } else {
                args[i] = InOutExecutor.getInjectedDependency((Inject) annoList.get(Inject.class),
                        constructor.getParameterTypes()[i], provider);
            }
        }
        try {
            constructor.setAccessible(true);
            result = constructor.newInstance(args);
        } catch (Exception e) {
            if (log.isFatalEnabled()) {
                log.fatal("Could not new instance on this constructor [" + constructor + "]", e);
            }
        }
        return result;
    }

    /**
     * Creates the scope name.
     * 
     * @param type
     *            the type
     * @param targetClass
     *            the target class
     * @param definition
     *            the definition
     * @param mappingName
     *            the mapping name
     * @return the string
     */
    public static String createScopeName(Class<?> type, Class<?> targetClass, Definition definition,
            String mappingName) {

        Assertor.notNull(type);
        Assertor.notNull(targetClass);
        Assertor.notNull(definition);
        String scopeName = type.toString() + ":" + targetClass.toString() + ":" + definition.toString();
        if (mappingName != null && !mappingName.isEmpty()) {
            scopeName = scopeName + ":" + mappingName;
        }
        return scopeName;
        // StringBuffer buffer = new StringBuffer();
        // buffer.append(type.toString());
        // buffer.append(":");
        // buffer.append(targetClass.toString());
        // buffer.append(":");
        // buffer.append(definition.toString());
        // if (mappingName != null && !mappingName.isEmpty()) {
        // buffer.append(":");
        // buffer.append(mappingName);
        // }
        // return buffer.toString();
    }

    /**
     * Creates the scope name.
     * 
     * @param constantStr
     *            the constant string
     * @return the string
     */
    public static String createScopeName(String constantStr) {

        return REF.refConstant(constantStr);
    }

    /**
     * Creates the scope name.
     * 
     * @param referString
     *            the refer string
     * @param provider
     *            the provider
     * @return the scope name
     * @throws GenericException
     *             the generic exception
     */
    public static String createScopeName(String referString, Provider provider) throws GenericException {

        DefinitionManager definitionManager = provider.getDefinitionManager();
        ObjectBeanFactory objectBeanFactory = provider.getObjectBeanFactory();
        if (referString.indexOf(":") != -1) {
            String[] values = referString.split(":");
            if (values[0].equals(Configurable.REF_CONSTANT)) {
                return referString;
            } else if (values[0].equals(Configurable.REF_MAPPING)) {
                Class<?> clazz = null;
                if (values[1].indexOf(" ") != -1) {
                    String[] split = values[1].split(" ");
                    try {
                        clazz = Class.forName(split[1]);
                        Class<?> targetClass = objectBeanFactory.getMappingList().get(clazz);
                        targetClass = targetClass == null ? clazz : targetClass;
                        return createScopeName(clazz, targetClass, definitionManager.getDefinition(targetClass),
                                values[1]);
                    } catch (ClassNotFoundException e) {
                    }
                }
                Entry<Class<?>, Class<?>> entry = objectBeanFactory.getAliasMap().get(values[1]);
                if (entry == null) {
                    throw new GenericException("Does not found mapping name '" + values[1] + "'");
                }
                Class<?> type = entry.getKey();
                Class<?> targetClass = entry.getValue();
                return createScopeName(type, targetClass, definitionManager.getDefinition(targetClass), values[1]);
            } else if (values[0].equals(Configurable.REF_ID)) {
                Definition definition = definitionManager.getDefinition(values[1]);
                if (definition == null) {
                    throw new GenericException("Does not found the definition according to ID '" + values[1] + "'");
                }
                Class<?> inclass = (Class<?>) definition.getKey();
                return createScopeName(inclass, inclass, definition, null);
            }
        }
        return REF.refConstant(referString);
    }

    /**
     * Gets the bean from object identification.
     * 
     * @param object
     *            the object
     * @param provider
     *            the provider
     * @return the bean from object identification
     */
    public static Object getBeanFromObjectIdentification(Object object, Provider provider) {

        Object result = null;
        if (ReflectUtils.isCast(String.class, object)) {
            result = provider.getBean((String) object);
        } else {
            result = object;
        }
        return result;
    }

    /**
     * Returns the default {@link Constructor} of the given class. The default
     * constructor is identified with annotated {@link DefaultConstructor}
     * annotation.
     * 
     * @param clazz
     *            the given class
     * @return returns the default constructor if it exists, if not, return
     *         <code>null</code>.
     * @throws InOutDependencyException
     *             throws this exception if there are more than one default
     *             constructor.
     * @see DefaultConstructor
     */
    public static Constructor<?> getDefaultConstructor(Class<?> clazz) {

        Constructor<?> constructor = null;
        int i = 0;
        for (Constructor<?> objCons : clazz.getDeclaredConstructors()) {
            if (objCons.isAnnotationPresent(DefaultConstructor.class)) {
                constructor = objCons;
                i++;
            }
        }
        if (i > 1) {
            throw new RuntimeException("There are more than one default constructor.");
        }
        return constructor;
    }

    /**
     * Returns the specified default <code>getter</code> of the specified field.
     * 
     * @param declaringClass
     *            the object class declared specified field.
     * @param fieldName
     *            name of field
     * @return returns the <code>getter</code> method if it exists, if not,
     *         return <code>null</code>.
     */
    public static Method getDefaultGetter(Class<?> declaringClass, String fieldName) {

        Method getter = null;
        fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        try {
            getter = ReflectUtils.getSupportedMethod(declaringClass, "get" + fieldName, null);
        } catch (NoSuchMethodException e) {
            try {
                getter = ReflectUtils.getSupportedMethod(declaringClass, "is" + fieldName, null);
            } catch (NoSuchMethodException e1) {
                return null;
            }
        }
        if (getter != null && !Modifier.isPublic(getter.getModifiers()))
            try {
                throw new IllegalAccessException();
            } catch (IllegalAccessException e) {
                if (log.isErrorEnabled()) {
                    log.error("The getter method [" + getter.getName() + "] declared in [" + declaringClass
                            + "] must be public", e);
                }
            }
        return getter;
    }

    /**
     * Returns the specified default <code>setter</code> of the specified field.
     * 
     * @param declaringClass
     *            the object class declared specified field.
     * @param fieldName
     *            name of field
     * @return returns the <code>setter</code> method if it exists, if not,
     *         return <code>null</code>.
     */
    public static Method getDefaultSetter(Class<?> declaringClass, String fieldName) {

        Method setter = null;
        Field field = null;
        String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        try {
            field = ReflectUtils.getSupportedField(declaringClass, fieldName);
            setter = ReflectUtils.getSupportedMethod(declaringClass, methodName,
                    new Class<?>[] { field.getType() });
        } catch (NoSuchFieldException e1) {
            return null;
        } catch (NoSuchMethodException e) {
            return null;
        }
        try {
            if (setter != null && !Modifier.isPublic(setter.getModifiers()))
                throw new IllegalAccessException();
        } catch (IllegalAccessException e) {
            if (log.isErrorEnabled()) {
                log.error("The setter method [" + methodName + "] declared in [" + declaringClass
                        + "] must be public", e);
            }
        }
        return setter;
    }

    /**
     * Gets the field of default setter or getter method.
     * 
     * @param method
     *            the given setter/getter method
     * @param declaringClass
     *            the declaring class
     * @return the field of default setter/getter
     * @throws InvalidOperationException
     *             the invalid operation exception
     * @throws NoSuchFieldException
     *             the no such field exception
     */
    public static Field getFieldOfDefaultSetGetter(Method method, Class<?> declaringClass)
            throws InvalidOperationException, NoSuchFieldException {

        Assertor.notNull(method, "The given method must not be null !");
        String name = method.getName();
        if (name.startsWith("set") || name.startsWith("get")) {
            String fieldName = name.substring(3);
            fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
            return ReflectUtils.getSupportedField(declaringClass, fieldName);
        } else {
            throw new InvalidOperationException(
                    "The given setter or getter method is not observed to default setter or getter !");
        }
    }

    /**
     * Gets the injected parameters of the given method.
     * 
     * @param method
     *            the method
     * @param defMethod
     *            the definition according to given method.
     * @param provider
     *            the specified provider.
     * @return returns an array containing the injected arguments if they exist,
     *         if not, returns an empty array.
     */
    public static Object[] getInjectedParametersOf(Method method, Definition defMethod, Provider provider) {

        Assertor.notNull(method, "The method must not be null.");
        Assertor.notNull(defMethod, "The definition of method must not be null.");
        Assertor.notNull(provider, "The provider must not be null");
        if (defMethod.getKey() != method) {
            Assertor.throwRunTimeException("The given definition is not corresponding to the given method!");
        }
        Class<?>[] argTypes = method.getParameterTypes();
        Object[] args = new Object[argTypes.length];
        if (argTypes.length == 0)
            throw new InOutDependencyException("Invalid setter! The setter method has no any parameter!");
        if (defMethod.isAnnotationPresent(Inject.class)) {
            Inject anno = defMethod.getAnnotation(Inject.class);
            args = new Object[argTypes.length];
            for (int i = 0; i < argTypes.length; i++) {
                args[i] = InOutExecutor.getInjectedDependency(anno, argTypes[i], provider);
            }
        }
        if (defMethod.isAnnotationPresentOnAnyParameters(Inject.class)) {
            Definition[] defLst = defMethod.getParameterDefList();
            if (argTypes.length != defLst.length)
                throw new InOutDependencyException("Invalid definition! Could not execute the injecting !");
            for (int i = 0; i < argTypes.length; i++) {
                if (defLst[i] != null && defLst[i].isAnnotationPresent(Inject.class)) {
                    args[i] = InOutExecutor.getInjectedDependency(defLst[i].getAnnotation(Inject.class),
                            argTypes[i], provider);
                }
            }
        }
        return args;
    }

    /**
     * Returns <code>true</code> if the given method is a getter method.
     * 
     * @param method
     *            the given method.
     * @return <code>true</code> if the given method is a getter method,
     *         otherwise, returns <code>false</code>.
     */
    public static boolean isGetter(Method method) {

        Assertor.notNull(method, "The given method must not be null !");
        String name = method.getName();
        if (name.startsWith("get") || name.startsWith("is"))
            return true;
        return false;
    }

    /**
     * Returns <code>true</code> if the given method is a setter method.
     * 
     * @param method
     *            the given method.
     * @return <code>true</code> if the given method is a setter method,
     *         otherwise, returns <code>false</code>.
     */
    public static boolean isSetter(Method method) {

        Assertor.notNull(method, "The given method must not be null !");
        String name = method.getName();
        if (name.startsWith("set"))
            return true;
        return false;
    }

    /**
     * Validates intercept conditioner.
     * 
     * @param selector
     *            the selector
     * @param definition
     *            the definition
     * @param interceptor
     *            the interceptor
     * @return true, if successful
     */
    public static boolean validatesInterceptConditioner(InstantiationSelector selector, Definition definition,
            Interceptor interceptor) {

        Matcher<Definition> matcher = selector.getMapMatcherInterceptor().get(interceptor);
        return validatesInterceptConditioner(matcher, definition, interceptor);
    }

    /**
     * Validates intercept conditioner.
     * 
     * @param matcher
     *            the matcher
     * @param definition
     *            the definition
     * @param interceptor
     *            the interceptor
     * @return true, if successful
     */
    public static boolean validatesInterceptConditioner(Matcher<Definition> matcher, Definition definition,
            Interceptor interceptor) {

        if (matcher != null && (ReflectUtils.isCast(MatcherPointcut.class, matcher)
                || ReflectUtils.isCast(CoreIdentification.class, interceptor))) {
            CoreIdentification coreIden = (CoreIdentification) matcher;
            InterceptConditioner ic = coreIden.getInterceptConditioner();
            if (ic != null && !ic.isValidDefinition(definition)) {
                return false;
            }
        }
        return true;
    }
}