org.LexGrid.LexBIG.caCore.client.proxy.LexEVSProxyHelperImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.LexGrid.LexBIG.caCore.client.proxy.LexEVSProxyHelperImpl.java

Source

/*
* Copyright: (c) Mayo Foundation for Medical Education and
* Research (MFMER). All rights reserved. MAYO, MAYO CLINIC, and the
* triple-shield Mayo logo are trademarks and service marks of MFMER.
*
* Distributed under the OSI-approved BSD 3-Clause License.
* See http://ncip.github.com/lexevs-remote/LICENSE.txt for details.
*/
package org.LexGrid.LexBIG.caCore.client.proxy;

import gov.nih.nci.system.applicationservice.ApplicationService;
import gov.nih.nci.system.client.proxy.BeanProxy;
import gov.nih.nci.system.client.proxy.ProxyHelperImpl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.LexGrid.LexBIG.caCore.applicationservice.RemoteExecutionResults;
import org.LexGrid.LexBIG.caCore.applicationservice.resource.RemoteShell;
import org.LexGrid.LexBIG.caCore.interfaces.LexEVSApplicationService;
import org.LexGrid.LexBIG.caCore.utils.LexEVSCaCoreUtils;
import org.LexGrid.annotations.LgAdminFunction;
import org.LexGrid.annotations.LgClientSideSafe;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.target.SingletonTargetSource;

/**
 * Object proxy implementation for EVS. Certain methods are overridden to
 * provide EVS-specific proxying functionality.
 *
 * @author <a href="mailto:muhsins@mail.nih.gov">Shaziya Muhsin</a>
 * @author <a href="mailto:rokickik@mail.nih.gov">Konrad Rokicki</a>
 */
public class LexEVSProxyHelperImpl extends ProxyHelperImpl {

    private static final Logger log = Logger.getLogger(LexEVSProxyHelperImpl.class);

    /**
     * Annotation class used to mark LexBig classes and methods as
     * safe for execution on a client without the LexBig environment.
     */
    private static final Class CLIENT_SAFE = LgClientSideSafe.class;

    /**
     * Annotation class used to mark LexBig methods which are admin
     * functions and thus illegal for execution via the distributed API.
     */
    private static final Class ADMIN_FUNCTION = LgAdminFunction.class;

    @Override
    protected Object convertObjectToProxy(ApplicationService as, Object obj) {
        if (null == obj)
            return null;

        //Check to see if the returned object is an EVSRemoteExecutionResults.
        //If so, unwrap it and update the proxy target
        if (obj instanceof RemoteExecutionResults) {
            RemoteExecutionResults results = (RemoteExecutionResults) obj;

            //if the returned results are null, return null
            if (results.getReturnValue() == null)
                return null;

            //Get the current proxy target and update it with the retuned value
            //from the server
            Advised advised = (Advised) AopContext.currentProxy();
            advised.setTargetSource(new SingletonTargetSource(results.getObj()));

            obj = results.getReturnValue();
        }

        if (obj instanceof RemoteShell) {
            Class<?>[] targetInterfaces = ((RemoteShell) obj).getTargetInterfaces();
            Class<?> targetClass = ((RemoteShell) obj).getTargetClass();
            ProxyFactory pf = new ProxyFactory(targetInterfaces);
            pf.addAdvice(new LexEVSBeanProxy(as, this));
            pf.setProxyTargetClass(true);
            pf.setTargetClass(targetClass);
            pf.setTarget(obj);

            return pf.getProxy();
        }

        if (obj instanceof Integer || obj instanceof Float || obj instanceof Double || obj instanceof Character
                || obj instanceof Long || obj instanceof Boolean || obj instanceof String || obj instanceof Date
                || obj instanceof LexEVSBeanProxy || obj instanceof BeanProxy)
            return obj;

        if (!LexEVSCaCoreUtils.isLexBigClass(obj.getClass())) {
            return obj;
        }

        // Don't proxy client-safe LexBig objects
        if (isClientSafe(obj.getClass())) {
            return obj;
        } else {
            return LexEVSCaCoreUtils.createProxy(obj, as, this);
        }
    }

    /**
     * Returns true if the object is initialized
     */
    @SuppressWarnings("unchecked")
    @Override
    public boolean isInitialized(MethodInvocation invocation) throws Throwable {
        if (invocation.getThis() == null || invocation.getThis() instanceof RemoteShell) {
            return false;
        }

        Class implClass = invocation.getThis().getClass();

        // LexBig objects have methods that must be executed remotely
        if (LexEVSCaCoreUtils.isLexBigClass(implClass)) {
            Method method = invocation.getMethod();
            Method methodImpl = implClass.getMethod(method.getName(), method.getParameterTypes());

            if (methodImpl.isAnnotationPresent(ADMIN_FUNCTION)) {
                throw new UnsupportedOperationException(
                        "Admin functions cannot be executed using the distributed API");
            }

            if (isClientSafe(methodImpl)) {
                log.info("DLB calling locally: " + implClass.getName() + "." + methodImpl.getName());
                return true;
            }

            log.info("DLB calling remotely: " + implClass.getName() + "." + methodImpl.getName());
            return false;
        }

        return true;
    }

    /**
     * Implements the LazyLoading
     */
    @SuppressWarnings("unchecked")
    @Override
    public Object lazyLoad(ApplicationService as, MethodInvocation invocation) throws Throwable {

        Object bean = invocation.getThis();
        Method method = invocation.getMethod();
        String methodName = method.getName();

        Object args[] = invocation.getArguments();

        Class implClass = bean.getClass();

        // LexBig objects have methods that must be executed remotely
        if (LexEVSCaCoreUtils.isLexBigClass(implClass)) {

            LexEVSApplicationService eas = (LexEVSApplicationService) as;
            Object results = eas.executeRemotely(bean, methodName, getParameterTypes(method), args);

            return results;
        }

        return null;
    }

    /**
     * Returns true if the given method or class is marked client-safe.
     *
     * @param object the object
     *
     * @return true, if checks if is client safe
     */
    @SuppressWarnings("unchecked")
    private boolean isClientSafe(Object object) {
        if (object instanceof Method) {
            return ((Method) object).isAnnotationPresent(CLIENT_SAFE);
        } else {
            return ((Class) object).isAnnotationPresent(CLIENT_SAFE);
        }
    }

    /**
     * Returns a list of class names that are parameters to the given method.
     * @param methodImpl
     * @return list of fully-qualified class names
     */
    private String[] getParameterTypes(Method methodImpl) {
        String[] paramClasses = new String[methodImpl.getParameterTypes().length];
        int i = 0;
        for (Class paramClass : methodImpl.getParameterTypes()) {
            if (paramClass == null)
                continue;
            paramClasses[i++] = paramClass.getName();
        }
        return paramClasses;
    }

    /**
     * Creates a serializable copy of a given object
     */
    protected Object createClone(Object source) {
        try {
            Object target = source.getClass().newInstance();
            List<Field> fieldList = new ArrayList<Field>();
            getAllFields(source.getClass(), fieldList);
            for (Field field : fieldList) {
                Object obj = field.get(source);

                if (obj instanceof Integer || obj instanceof Float || obj instanceof Double
                        || obj instanceof Character || obj instanceof Long || obj instanceof Boolean
                        || obj instanceof String) {
                    if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers())) {
                        field.setAccessible(true);
                        field.set(target, obj);
                    }
                }
            }
            return target;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    protected List<Field> getAnnotatedFields(Object obj, Class annotation) {
        List<Field> returnList = new ArrayList<Field>();
        for (Field field : obj.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(annotation)) {
                returnList.add(field);
            }
        }
        return returnList;
    }
}