org.nebularis.defproxy.introspection.MethodInvokerTemplate.java Source code

Java tutorial

Introduction

Here is the source code for org.nebularis.defproxy.introspection.MethodInvokerTemplate.java

Source

/*
 * def-proxy
 *
 * Copyright (c) 2010-2011
 * Tim Watson (watson.timothy@gmail.com), Charles Care (c.p.care@gmail.com).
 * All Rights Reserved.
 *
 * This file is provided to you 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.
 */

package org.nebularis.defproxy.introspection;

import org.nebularis.defproxy.configuration.ExceptionHandlingPolicy;
import org.nebularis.defproxy.introspection.CallSite;
import org.nebularis.defproxy.introspection.MethodSignature;
import org.nebularis.defproxy.introspection.MethodInvoker;
import org.nebularis.defproxy.introspection.TypeConverter;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static org.apache.commons.beanutils.MethodUtils.getMatchingAccessibleMethod;

/**
 * Default, reflection based {@link org.nebularis.defproxy.introspection.MethodInvoker},
 * providing additional support for template methods. Subclasses can override the
 * details of the target site prior to method invocation (by overriding the
 * {@link org.nebularis.defproxy.introspection.MethodInvokerTemplate#beforeInvocation(Object, java.lang.reflect.Method, Object[])}
 * method), or alter the return value
 * (overriding the {@link org.nebularis.defproxy.introspection.MethodInvokerTemplate#afterInvocation(Object, CallSite)} method).
 */
public class MethodInvokerTemplate implements MethodInvoker {

    private final MethodSignature sig;
    private TypeConverter converter;
    private ExceptionHandlingPolicy policy = new ExceptionHandlingPolicy() {
        @Override
        public Object handleException(final Throwable ex) throws Throwable {
            if (ex instanceof InvocationTargetException) {
                throw ex.getCause();
            }
            throw ex;
        }
    };

    public MethodInvokerTemplate(final MethodSignature sig) {
        this.sig = sig;
    }

    /**
     * @inheritDoc
     */
    @Override
    public MethodSignature getMethodSignature() {
        return sig;
    }

    /**
     * @inheritDoc
     */
    @Override
    public ExceptionHandlingPolicy getExceptionHandlingPolicy() {
        return policy;
    }

    /**
     * @inheritDoc
     */
    @Override
    public void setExceptionHandlerPolicy(final ExceptionHandlingPolicy exceptionHandlerPolicy) {
        this.policy = exceptionHandlerPolicy;
    }

    /**
     * @inheritDoc
     */
    @Override
    public TypeConverter getTypeConverter() {
        return converter;
    }

    /**
     * @inheritDoc
     */
    @Override
    public void setTypeConverter(final TypeConverter converter) {
        this.converter = converter;
    }

    /**
     * @inheritDoc
     */
    @Override
    public final Object handleInvocation(final Object delegate, final Object... params) throws Throwable {
        try {
            final Method method = getMethodBySignature(delegate.getClass(), getMethodSignature());
            if (method == null) {
                throw new NoSuchMethodException(String.format("Method %s was not found.", sig.getName()));
            }
            final CallSite site = beforeInvocation(delegate, method, params);
            final Object returnValue = site.dispatch();
            if (converter != null) {
                //noinspection unchecked
                return afterInvocation(converter.convert(returnValue), site);
            }
            return afterInvocation(returnValue, site);
        } catch (Throwable e) {
            return getExceptionHandlingPolicy().handleException(e);
        }
    }

    /**
     * Called immediately before invocation, this method <b>must</b> generate a
     * {@link org.nebularis.defproxy.introspection.CallSite} for the invocation, whose
     * return value (i.e., the result of calling {@link org.nebularis.defproxy.introspection.CallSite#dispatch()})
     * will be passed to {@link MethodInvokerTemplate#afterInvocation(Object, org.nebularis.defproxy.introspection.CallSite)}
     * for post-processing prior to returning it to the caller.
     * @param delegate
     * @param method
     * @param params
     * @return
     */
    protected CallSite beforeInvocation(final Object delegate, final Method method, final Object[] params) {
        return new CallSite(method, delegate, params);
    }

    /**
     * Called immediately after invocation, allowing for post-processing of the return value.
     * @param returnValue
     * @param site
     * @return
     */
    protected Object afterInvocation(final Object returnValue, final CallSite site) {
        return returnValue;
    }

    /**
     * Gets the correct method from the supplied class using the supplied method signature.
     * @param delegate
     * @param sig
     * @return
     */
    /* oh for the CLR's assembly protection level! */
    Method getMethodBySignature(final Class delegate, final MethodSignature sig) {
        return getMatchingAccessibleMethod(delegate, sig.getName(), sig.getParameterTypes());
    }
}