com.bstek.dorado.data.resolver.manager.DataResolverInterceptorInvoker.java Source code

Java tutorial

Introduction

Here is the source code for com.bstek.dorado.data.resolver.manager.DataResolverInterceptorInvoker.java

Source

/*
 * This file is part of Dorado 7.x (http://dorado7.bsdn.org).
 * 
 * Copyright (c) 2002-2012 BSTEK Corp. All rights reserved.
 * 
 * This file is dual-licensed under the AGPLv3 (http://www.gnu.org/licenses/agpl-3.0.html) 
 * and BSDN commercial (http://www.bsdn.org/licenses) licenses.
 * 
 * If you are unsure which license is appropriate for your use, please contact the sales department
 * at http://www.bstek.com/contact.
 */

package com.bstek.dorado.data.resolver.manager;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.bstek.dorado.core.bean.BeanFactoryUtils;
import com.bstek.dorado.core.resource.ResourceManager;
import com.bstek.dorado.core.resource.ResourceManagerUtils;
import com.bstek.dorado.data.ParameterWrapper;
import com.bstek.dorado.data.entity.NullWrapper;
import com.bstek.dorado.data.method.MethodAutoMatchingException;
import com.bstek.dorado.data.method.MethodAutoMatchingUtils;
import com.bstek.dorado.data.method.MoreThanOneMethodsMatchsException;
import com.bstek.dorado.data.resolver.DataItems;
import com.bstek.dorado.data.resolver.DataResolver;
import com.bstek.dorado.data.type.DataType;
import com.bstek.dorado.util.Assert;

/**
 * @author Benny Bao (mailto:benny.bao@bstek.com)
 * @since Apr 29, 2009
 */
public class DataResolverInterceptorInvoker implements MethodInterceptor {
    private static final Log logger = LogFactory.getLog(DataResolverInterceptorInvoker.class);
    private static final ResourceManager resourceManager = ResourceManagerUtils
            .get(DataResolverInterceptorInvoker.class);

    public static final String INTERCEPTING_METHOD_NAME = "resolve";
    public static final String DEFAULT_METHOD_NAME = INTERCEPTING_METHOD_NAME;

    private static final Object[] EMPTY_ARGS = new Object[0];
    private static final String[] EMPTY_NAMES = new String[0];
    private static final Class<?>[] EMPTY_TYPES = new Class[0];

    private static final class AbortException extends RuntimeException {
        private static final long serialVersionUID = -3143779968350839581L;
    };

    private String interceptorName;
    private String methodName;
    private Object interceptor;

    /**
     * @param interceptorExpression
     *            
     */
    public DataResolverInterceptorInvoker(String interceptorExpression) {
        Assert.notEmpty(interceptorExpression, "\"interceptorExpression\" could not be empty.");
        int i = interceptorExpression.lastIndexOf("#");
        if (i > 0) {
            interceptorName = interceptorExpression.substring(0, i);
            methodName = interceptorExpression.substring(i + 1);
        } else {
            interceptorName = interceptorExpression;
        }
        if (StringUtils.isEmpty(methodName)) {
            methodName = DEFAULT_METHOD_NAME;
        }
    }

    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        Method proxyMethod = methodInvocation.getMethod();
        if (!proxyMethod.getName().equals(INTERCEPTING_METHOD_NAME)) {
            return methodInvocation.proceed();
        }

        if (interceptor == null) {
            interceptor = BeanFactoryUtils.getBean(interceptorName);
        }

        Method[] methods = MethodAutoMatchingUtils.getMethodsByName(interceptor.getClass(), methodName);
        if (methods.length == 0) {
            throw new NoSuchMethodException(resourceManager.getString("dorado.common/methodNotFoundInInterceptor",
                    interceptorName, methodName));
        }

        DataResolver dataResolver = (DataResolver) methodInvocation.getThis();
        MethodAutoMatchingException[] exceptions = new MethodAutoMatchingException[4];
        int i = 0;

        try {
            try {
                return invokeInterceptorByParamName(dataResolver, methods, methodInvocation, false);
            } catch (MoreThanOneMethodsMatchsException e) {
                throw e;
            } catch (MethodAutoMatchingException e) {
                exceptions[i++] = e;
            } catch (AbortException e) {
                // do nothing
            }

            try {
                return invokeInterceptorByParamName(dataResolver, methods, methodInvocation, true);
            } catch (MoreThanOneMethodsMatchsException e) {
                throw e;
            } catch (MethodAutoMatchingException e) {
                exceptions[i++] = e;
            } catch (AbortException e) {
                // do nothing
            }

            try {
                return invokeInterceptorByParamType(dataResolver, methods, methodInvocation, false);
            } catch (MoreThanOneMethodsMatchsException e) {
                throw e;
            } catch (MethodAutoMatchingException e) {
                exceptions[i++] = e;
            } catch (AbortException e) {
                // do nothing
            }

            try {
                return invokeInterceptorByParamType(dataResolver, methods, methodInvocation, true);
            } catch (MoreThanOneMethodsMatchsException e) {
                throw e;
            } catch (MethodAutoMatchingException e) {
                exceptions[i++] = e;
            } catch (AbortException e) {
                // do nothing
            }
        } catch (MethodAutoMatchingException e) {
            exceptions[i++] = e;
        }

        for (MethodAutoMatchingException e : exceptions) {
            if (e == null) {
                break;
            }
            logger.error(e.getMessage());
        }
        throw new IllegalArgumentException(resourceManager.getString("dorado.common/noMatchingMethodError",
                interceptor.getClass().getName(), methodName));
    }

    private Object invokeInterceptorByParamName(DataResolver dataResolver, Method[] methods,
            MethodInvocation methodInvocation, boolean disassembleParameter) throws Exception {
        Object[] proxyArgs = methodInvocation.getArguments();
        DataItems dataItems = (DataItems) proxyArgs[0];
        Object parameter = (proxyArgs.length > 1) ? proxyArgs[1] : null;
        Map<String, Object> sysParameter = null;

        if (parameter instanceof ParameterWrapper) {
            ParameterWrapper parameterWrapper = (ParameterWrapper) parameter;
            parameter = parameterWrapper.getParameter();
            sysParameter = parameterWrapper.getSysParameter();
        }

        if (disassembleParameter && (parameter == null && !(parameter instanceof Map<?, ?>))) {
            throw new AbortException();
        }

        String[] optionalParameterNames = null;
        Object[] optionalParameters = null;
        String[] extraParameterNames = null;
        Object[] extraParameters = null;

        String[] parameterParameterNames = EMPTY_NAMES;
        Object[] parameterParameters = EMPTY_ARGS;
        if (parameter != null && parameter instanceof Map<?, ?>) {
            if (disassembleParameter) {
                Map<?, ?> map = (Map<?, ?>) parameter;
                parameterParameterNames = new String[map.size()];
                parameterParameters = new Object[parameterParameterNames.length];

                int i = 0;
                for (Map.Entry<?, ?> entry : map.entrySet()) {
                    parameterParameterNames[i] = (String) entry.getKey();
                    parameterParameters[i] = entry.getValue();
                    i++;
                }
            } else {
                parameterParameterNames = new String[] { "parameter" };
                parameterParameters = new Object[] { parameter };
            }
        } else {
            parameterParameterNames = new String[] { "parameter" };
            parameterParameters = new Object[] { parameter };
        }

        int dataItemsParameterCount = (dataItems != null) ? dataItems.size() : 0;
        optionalParameterNames = new String[dataItemsParameterCount + parameterParameterNames.length + 3];
        optionalParameters = new Object[optionalParameterNames.length];
        optionalParameterNames[0] = "dataItems";
        optionalParameterNames[1] = "dataResolver";
        optionalParameterNames[2] = "methodInvocation";
        optionalParameters[0] = dataItems;
        optionalParameters[1] = dataResolver;
        optionalParameters[2] = methodInvocation;

        if (dataItems != null) {
            int i = 3;
            for (Map.Entry<String, Object> entry : dataItems.entrySet()) {
                Object dataItem = entry.getValue();
                if (dataItem != null && dataItem instanceof NullWrapper) {
                    dataItem = null;
                }
                optionalParameterNames[i] = entry.getKey();
                optionalParameters[i] = dataItem;
                i++;
            }
        }

        System.arraycopy(parameterParameterNames, 0, optionalParameterNames, dataItemsParameterCount + 3,
                parameterParameterNames.length);
        System.arraycopy(parameterParameters, 0, optionalParameters, dataItemsParameterCount + 3,
                parameterParameters.length);

        if (sysParameter != null && !sysParameter.isEmpty()) {
            extraParameterNames = new String[sysParameter.size()];
            extraParameters = new Object[extraParameterNames.length];

            int i = 0;
            for (Map.Entry<?, ?> entry : sysParameter.entrySet()) {
                extraParameterNames[i] = (String) entry.getKey();
                extraParameters[i] = entry.getValue();
                i++;
            }
        }

        return MethodAutoMatchingUtils.invokeMethod(methods, interceptor, null, null, optionalParameterNames,
                optionalParameters, extraParameterNames, extraParameters);
    }

    private Object invokeInterceptorByParamType(DataResolver dataResolver, Method[] methods,
            MethodInvocation methodInvocation, boolean disassembleParameter)
            throws MethodAutoMatchingException, Exception {
        Object[] proxyArgs = methodInvocation.getArguments();
        DataItems dataItems = (DataItems) proxyArgs[0];
        Object parameter = (proxyArgs.length > 1) ? proxyArgs[1] : null;
        Map<String, Object> sysParameter = null;

        if (parameter instanceof ParameterWrapper) {
            ParameterWrapper parameterWrapper = (ParameterWrapper) parameter;
            parameter = parameterWrapper.getParameter();
            sysParameter = parameterWrapper.getSysParameter();
        }

        if (disassembleParameter && (parameter == null && !(parameter instanceof Map<?, ?>))) {
            throw new AbortException();
        }

        Map<Type, Object> extraArgMap = new HashMap<Type, Object>();
        if (sysParameter != null && !sysParameter.isEmpty()) {
            for (Map.Entry<?, ?> entry : sysParameter.entrySet()) {
                Object value = entry.getValue();
                if (value != null) {
                    extraArgMap.put(MethodAutoMatchingUtils.getTypeForMatching(value), value);
                }
            }
        }

        Type[] optionalArgTypes = null;
        Object[] optionalArgs = null;

        Type[] parameterArgTypes = EMPTY_TYPES;
        Object[] parameterArgs = EMPTY_ARGS;
        if (parameter != null) {
            if (parameter instanceof Map<?, ?>) {
                if (disassembleParameter) {
                    Map<?, ?> map = (Map<?, ?>) parameter;
                    parameterArgTypes = new Class[map.size()];
                    parameterArgs = new Object[parameterArgTypes.length];

                    int i = 0;
                    for (Object value : map.values()) {
                        if (value != null) {
                            parameterArgTypes[i] = MethodAutoMatchingUtils.getTypeForMatching(value);
                            parameterArgs[i] = value;
                            i++;
                        }
                    }
                } else {
                    parameterArgTypes = new Type[] { MethodAutoMatchingUtils.getTypeForMatching(parameter) };
                    parameterArgs = new Object[] { parameter };
                }
            } else {
                parameterArgTypes = new Type[] { MethodAutoMatchingUtils.getTypeForMatching(parameter) };
                parameterArgs = new Object[] { parameter };
            }
        } else {
            parameterArgTypes = new Type[] { Object.class };
            parameterArgs = new Object[] { null };
        }

        int dataItemsArgCount = (dataItems != null) ? dataItems.size() : 0;
        optionalArgTypes = new Type[dataItemsArgCount + parameterArgTypes.length];
        optionalArgs = new Object[optionalArgTypes.length];

        if (dataItems != null) {
            int i = 0;
            for (Object dataItem : dataItems.values()) {
                if (dataItem != null) {
                    if (dataItem instanceof NullWrapper) {
                        DataType dataType = ((NullWrapper) dataItem).getDataType();
                        if (dataType != null) {
                            Type typeForMatching = MethodAutoMatchingUtils.getTypeForMatching(dataType);
                            if (typeForMatching != null) {
                                optionalArgTypes[i] = typeForMatching;
                                optionalArgs[i] = null;
                                i++;
                            }
                        }
                    } else {
                        Type typeForMatching = MethodAutoMatchingUtils.getTypeForMatching(dataItem);
                        optionalArgTypes[i] = typeForMatching;
                        optionalArgs[i] = dataItem;
                        i++;
                    }
                }
            }
        }
        System.arraycopy(parameterArgTypes, 0, optionalArgTypes, dataItemsArgCount, parameterArgTypes.length);
        System.arraycopy(parameterArgs, 0, optionalArgs, dataItemsArgCount, parameterArgs.length);

        Type[] exactArgTypes = new Class[3 + extraArgMap.size()];
        Object[] exactArgs = new Object[exactArgTypes.length];
        exactArgTypes[0] = DataItems.class;
        exactArgs[0] = dataItems;
        exactArgTypes[1] = DataResolver.class;
        exactArgs[1] = dataResolver;
        exactArgTypes[2] = MethodInvocation.class;
        exactArgs[2] = methodInvocation;

        int i = 3;
        for (Map.Entry<?, ?> entry : extraArgMap.entrySet()) {
            exactArgTypes[i] = (Class<?>) entry.getKey();
            exactArgs[i] = entry.getValue();
            i++;
        }

        return MethodAutoMatchingUtils.invokeMethod(methods, interceptor, null, null, exactArgTypes, exactArgs,
                optionalArgTypes, optionalArgs, null);
    }
}