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

Java tutorial

Introduction

Here is the source code for org.LexGrid.LexBIG.caCore.client.proxy.LexEVSApplicationServiceProxy.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.evs.security.SecurityToken;
import gov.nih.nci.system.applicationservice.ApplicationService;
import gov.nih.nci.system.client.proxy.ApplicationServiceProxy;
import gov.nih.nci.system.client.proxy.ProxyHelper;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;

import net.sf.cglib.proxy.Enhancer;

import org.LexGrid.LexBIG.Exceptions.LBException;
import org.LexGrid.LexBIG.caCore.applicationservice.annotations.DataServiceLazyLoadable;
import org.LexGrid.LexBIG.caCore.interfaces.LexEVSApplicationService;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;
import org.springframework.aop.framework.Advised;

/**
 * Application Service proxy for LexEVS.
 * Certain methods are overridden to
 * provide LexEVS-specific proxying functionality.
 *
 * @author <a href="mailto:ongki@mail.nih.gov">Kim L. Ong</a>
 * @author <a href="mailto:rajasimhah@mail.nih.gov">Harsha Karur Rajasimha</a>
 * @author <a href="mailto:kevin.peterson@mayo.edu">Kevin Peterson</a>
 * 
 */
public class LexEVSApplicationServiceProxy extends ApplicationServiceProxy {
    private static Logger log = Logger.getLogger(LexEVSApplicationServiceProxy.class.getName());

    private LexEVSApplicationService eas;

    protected HashMap<String, SecurityToken> securityToken_map = new HashMap<String, SecurityToken>();

    private ProxyHelper dataServiceProxyHelper;

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        //This is for Spring -- if it tries to call methods (like set the LexEVSApplicationService,
        //'toString', etc, on the creation of the bean. If we haven't set up the LexEVSApplicationService,
        //we can't do any of the remoting anyway.
        if (eas == null) {
            return invocation.proceed();
        }

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

        Object[] args = invocation.getArguments();
        Class implClass = bean.getClass();

        SecurityToken securityToken = null;
        String vocabulary = null;

        if (methodName.equals("getSecurityToken_map")) {
            return securityToken_map;
        }

        // Check if the invocation.methodName is registerToken
        if (methodName.equals("registerSecurityToken")) {

            /* User needs to determine which vocabulary to register
             * User needs to pass vocabulary name and token string.
             * registerSecurityToken(String vocabulary, String token)
             * First argument is assumed to be vocabulary name
             */
            vocabulary = (String) args[0];

            // Second parameter of registerSecurityToken method is assumed to be SecurityToken
            securityToken = (SecurityToken) args[1];

            if ((vocabulary.equals(null)) || (vocabulary == "")) {
                throw new IllegalArgumentException("vocabulary is null..args");
            }

            if (securityToken == null) {
                throw new IllegalArgumentException("Security token arg is null... ");
            }

            // insert them in the securityToken_map hashmap if not already present
            securityToken_map.put(vocabulary, securityToken);

            // return Boolean.TRUE or Boolean.FALSE
            return true;
        }

        /* Check if the method is annotated as requiring security token
         * (e.g., resolveCodingScheme() and handle it aptly
         * whether the coding scheme itself requires a security token (determined by configuration file)
          */
        if (methodName.equals("executeSecurely")) {
            if (isDataServiceLazyLoadable(args)) {
                return invokeDataService(invocation);
            }
            return super.invoke(invocation);
        } else {

            Method methodImpl = implClass.getMethod(methodName, method.getParameterTypes());

            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    if (args[i] != null) {
                        if (Enhancer.isEnhanced(args[i].getClass())) {
                            args[i] = unwrap(args[i]);
                        }
                    }
                }
            }
            try {
                return eas.executeSecurely(methodImpl.getName(), method.getAnnotations(),
                        getParameterTypes(methodImpl), args, securityToken_map);
            } catch (Exception e) {
                // throw e;
                throw digOutRealExceptionAndThrowIt(e);
                // throw new LBException("Something went wrong.");
                // digOutRealExceptionAndThrowIt();
            }
        }
    }

    /*
     * method: digOutRealExceptionAndThrowIt
     * purpose: return the lowest level LexBIG exception.
     *          In the distributed environment the exception stacks can get lengthy.
     *          The idea behind this method is to eliminate the extra exceptions that 
     *          are not actually related to the problem.
     *          
     * algorithm:  (1) method gets passed the topmost exception 
     *             (2) go through all passed exception's 'causes'
     *             (3) examine each cause exception; see if it is from the package: org.LexGrid.LexBIG.Exceptions
     *             (4) if so, set it as our new return exception 
     *             (5) if we don't find any exceptions from our desired package, use the original exception
     */
    public static Exception digOutRealExceptionAndThrowIt(Exception e) throws Exception {
        Throwable lbiEx = null;
        Throwable next = null;
        Throwable cur = e;
        boolean lexBigExceptionFound = false;
        boolean done = false;
        int i = 1;
        int max = 500; // a limit so we won't ever be in endless loop
        if (isLexBigException(cur) == true) {
            lexBigExceptionFound = true;
            lbiEx = cur;
        }
        while (!done) {
            next = cur.getCause();
            ++i;
            if (next == null) {
                done = true;
            } else {
                cur = next;
                if (isLexBigException(cur) == true) {
                    lexBigExceptionFound = true;
                    lbiEx = cur;
                }
                if (i == max) {
                    done = true;
                    log.error("digOutRealExceptionAndThrowIt: reached max depth of: " + max);
                }
            }
        }
        Exception returnException = null;
        if (lexBigExceptionFound == true) {
            returnException = new LBException(lbiEx.getMessage());
            returnException.setStackTrace(lbiEx.getStackTrace());
        } else {
            returnException = e;
        }
        return returnException;
    }

    private static boolean isLexBigException(Throwable th) {
        if (th.toString().indexOf("org.LexGrid.LexBIG.Exceptions") != -1) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 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;
    }

    public Object invokeDataService(MethodInvocation invocation) throws Throwable {
        Object value = invocation.proceed();
        value = dataServiceProxyHelper.convertToProxy(eas, value);
        return value;
    }

    /*
     * Determine if the method had any Annotations
     */
    protected boolean isDataServiceLazyLoadable(Object[] args) {
        for (Object arg : args) {
            if (arg instanceof Annotation[]) {
                for (Annotation annotation : (Annotation[]) arg) {
                    if (annotation instanceof DataServiceLazyLoadable) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Returns the underlying object that the specified proxy is advising.
     *
     * @param proxy the proxy
     *
     * @return the object
     *
     * @throws Exception the exception
     */
    private Object unwrap(Object proxy) throws Exception {
        Object interceptor = null;
        int i = 0;
        while (true) {
            Field field = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_" + i);
            field.setAccessible(true);
            Object value = field.get(proxy);
            if (value.getClass().getName().contains("EqualsInterceptor")) {
                interceptor = value;
                break;
            }
            i++;
        }

        Field field = interceptor.getClass().getDeclaredField("advised");
        field.setAccessible(true);
        Advised advised = (Advised) field.get(interceptor);
        Object realObject = advised.getTargetSource().getTarget();
        return realObject;
    }

    public ProxyHelper getDataServiceProxyHelper() {
        return dataServiceProxyHelper;
    }

    public void setDataServiceProxyHelper(ProxyHelper dataServiceProxyHelper) {
        this.dataServiceProxyHelper = dataServiceProxyHelper;
    }

    @Override
    public void setApplicationService(ApplicationService as) {
        eas = (LexEVSApplicationService) as;
        super.setApplicationService(eas);
    }

    public HashMap getSecurityToken_map() {
        return securityToken_map;
    }

}