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

Java tutorial

Introduction

Here is the source code for org.LexGrid.LexBIG.caCore.client.proxy.DataServiceProxyHelperImpl.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.ListProxy;
import gov.nih.nci.system.client.proxy.ProxyHelperImpl;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;

import org.LexGrid.LexBIG.caCore.interfaces.LexEVSApplicationService;
import org.LexGrid.LexBIG.caCore.utils.LexEVSCaCoreUtils;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;
import org.hibernate.Hibernate;
import org.springframework.aop.framework.ProxyFactory;

/**
 * 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 DataServiceProxyHelperImpl extends ProxyHelperImpl {

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

    /*
     * Special methods to exclude from Lazy Loading
     */
    private static final String[] NON_LAZY_LOAD_METHODS = new String[] { "getAllProperties" };

    public Object convertToProxy(ApplicationService as, Object obj) {
        if (obj == null)
            return null;
        if (obj instanceof LexEVSListProxy)
            return convertLexEVSListProxyToProxy(as, (LexEVSListProxy) obj);
        if (obj instanceof ListProxy)
            return convertListProxyToProxy(as, (ListProxy) obj);
        if (obj instanceof java.util.Collection)
            return convertCollectionToProxy(as, (Collection) obj);
        else if (obj instanceof Object[])
            return convertArrayToProxy(as, (Object[]) obj);
        else
            return convertObjectToProxy(as, obj);
    }

    protected Object convertLexEVSListProxyToProxy(ApplicationService as, LexEVSListProxy proxy) {
        proxy.setAppService(as);
        List chunk = proxy.getListChunk();

        List modifiedChunk = new ArrayList((Collection) convertToProxy(as, chunk));
        proxy.setListChunk(modifiedChunk);

        return proxy;
    }

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

        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;

        ProxyFactory pf = new ProxyFactory(obj);
        pf.setProxyTargetClass(true);
        pf.addAdvice(new LexEVSBeanProxy(as, this));
        pf.setExposeProxy(true);
        return pf.getProxy();
    }

    /**
     * Returns true if the object is initialized
     */
    @SuppressWarnings("unchecked")
    @Override
    public boolean isInitialized(MethodInvocation invocation) throws Exception {
        if (isLazyLoadableMethod(invocation.getMethod())) {
            return isMethodInitialized(invocation);
        } else {
            return true;
        }
    }

    protected boolean isLazyLoadableMethod(Method method) {
        if (!method.getDeclaringClass().getName().startsWith("org.LexGrid")) {
            return false;
        }

        String methodName = method.getName();

        //if this method has been flagged to be skipped from Lazy Loading, skip it here
        if (ArrayUtils.contains(NON_LAZY_LOAD_METHODS, methodName)) {
            return false;
        }

        if (methodName.startsWith("get") || methodName.startsWith("iterate")
                || methodName.startsWith("enumerate")) {
            return true;
        }
        return false;
    }

    /**
    * Determine the property within the bean that is being referenced by the method called.
    * This is due to Castor's naming conventions -- for example:
    * 
    * The method 'getPresentationCount'
    * May reference '_presentationList' in the bean.
    * 
    * We need to know the specific name of the property associated with each method call so
    * that we know what property Hibernate needs to lazy load.
    * 
    * This also needs to take into account that Castor may assign multiple methods to a property,
    * for example, it may return a count of the property (getPresentationCount), or an Iterator
    * (IteratePresentation)... and so on. All these methods in the end reference the same property in
    * the bean, '_presentationList'.
    * 
    * @param invocation The Method Invocation.
    * @return The property name within the bean that will be referenced by this MethodInvocation.
    * @throws Exception
    */
    protected String getPropertyNameFromMethodName(MethodInvocation invocation) throws Exception {
        String methodName = invocation.getMethod().getName();

        //Lets say we have the method 'getPresentationCount"
        //so now we know that its a getter -- chop off the 'get' and start looking
        methodName = methodName.replaceFirst("get", "");

        //Do the same for 'iterate' and 'enumerate'
        methodName = methodName.replaceFirst("enumerate", "");
        methodName = methodName.replaceFirst("iterate", "");

        //we now have 'PresentationCount'
        //make the first letter lower case and add the goofy Castor underscore
        methodName = makeFirstLetterLowerCase(methodName);
        methodName = "_" + methodName;

        //now we have _PresentationCount
        //if this is supposed to return a list, add the "List"
        if (invocation.getMethod().getReturnType() == List.class
                || invocation.getMethod().getReturnType() == Iterator.class
                || invocation.getMethod().getReturnType() == Enumeration.class
                || invocation.getMethod().getReturnType().isArray()) {
            //if this is a List, we must append the "List"
            methodName = methodName + "List";
            //now we have _presentationList, which is what we want!
        }

        //Account for the Castor get...(int) methods for Collections
        if (invocation.getMethod().getParameterTypes().length == 1
                && invocation.getMethod().getParameterTypes()[0] == int.class) {
            methodName = methodName + "List";
        }

        //chop off the "Count" and replace with "List".
        if (methodName.endsWith("Count")) {
            //if this is a List, we must append the "List"
            methodName = methodName.replace("Count", "List");
            //now we have _presentationList, which is what we want!
        }
        return methodName;
    }

    protected String makeFirstLetterLowerCase(String searchString) {
        return searchString.substring(0, 1).toLowerCase() + searchString.substring(1);
    }

    /**
    * Determine whether or not this method call has been fully initialized by Hibernate. If
    * not, it will need to be lazy-loaded. 
    * 
    * @param invocation The MethodInvocation to check.
    * @return Whether or not it has been fully initialized by Hibernate.
    * @throws Exception
    */
    protected boolean isMethodInitialized(MethodInvocation invocation) throws Exception {
        String propertyName = getPropertyNameFromMethodName(invocation);
        return isFieldHibernateInit(invocation.getThis(), propertyName);
    }

    /**
    * Determine whether or not a Field has been initialized by Hibernate or not.
    * 
    * @param obj The object to check.
    * @param fieldName The field name.
    * @return If the given field has been initialized or not.
    * @throws Exception
    */
    protected boolean isFieldHibernateInit(Object obj, String fieldName) throws Exception {
        Class clazz = obj.getClass();
        Field field = LexEVSCaCoreUtils.getField(clazz, fieldName);
        field.setAccessible(true);
        return Hibernate.isInitialized(field.get(obj));
    }

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

        LexEVSApplicationService eas = (LexEVSApplicationService) as;

        String associationName = getPropertyNameFromMethodName(invocation);

        List results = (List) eas.getAssociation(createClone(source), associationName);
        if (results.size() > 1) {
            throw new Exception(
                    "LazyLoad returned more results than expected. Please set the QueryOption to initialize the query.");
        }

        Object result = results.get(0);

        if (result instanceof List) {
            return accountForCastorMethods((List) result, invocation);
        } else {
            return result;
        }
    }

    /**
    * Account for all the extra methods Castor puts in its beans. This needs to be done because
    * the properties themselves may not be initialized by Hibernate (lazy loaded), but calling 
    * one of these methods on a Castor bean will try to invoke the un-initialized property. So,
    * we have to determine what method is being called and process the result accordingly.
    *  
    * @param result The right result given the Method being called.
    * @param methodInvocation The method being invoked.
    * @return
    */
    protected Object accountForCastorMethods(List result, MethodInvocation methodInvocation) {
        Method method = methodInvocation.getMethod();
        String methodName = method.getName();

        if (methodName.startsWith("get") && methodName.endsWith("Count")) {
            return new Integer(result.size());
        }
        if (methodName.startsWith("enumerate")) {
            return java.util.Collections.enumeration(result);
        }
        if (methodName.startsWith("iterate")) {
            return result.iterator();
        }
        if (methodName.startsWith("get") && method.getReturnType().isArray()) {
            Class returnType = method.getReturnType().getComponentType();
            Object[] array = (Object[]) Array.newInstance(returnType, result.size());
            return result.toArray(array);
        }
        if (methodName.startsWith("get") && method.getParameterTypes().length == 1
                && method.getParameterTypes()[0] == int.class) {
            return result.get((Integer) methodInvocation.getArguments()[0]);
        }

        return result;
    }
}