package edu.ualberta.med.biobank.client.util; import edu.ualberta.med.biobank.common.util.AbstractBiobankListProxy; import edu.ualberta.med.biobank.common.util.NotAProxy; import gov.nih.nci.system.applicationservice.ApplicationService; import gov.nih.nci.system.client.proxy.ListProxy; import gov.nih.nci.system.client.proxy.ProxyHelperImpl; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.Transient; import org.aopalliance.intercept.MethodInvocation; import org.hibernate.Hibernate; import org.hibernate.criterion.DetachedCriteria; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.framework.Advised; public class BiobankProxyHelperImpl extends ProxyHelperImpl { private static Logger log = LoggerFactory .getLogger(BiobankProxyHelperImpl.class .getName()); @Override public Object convertToProxy(ApplicationService as, Object obj) { if (obj instanceof AbstractBiobankListProxy) { return convertListProxyToProxy(as, (AbstractBiobankListProxy<?>) obj); } else if (obj instanceof NotAProxy) { return obj; } else if (obj instanceof BigDecimal) { return obj; } return super.convertToProxy(as, obj); } @SuppressWarnings("rawtypes") @Override protected Object convertCollectionToProxy(ApplicationService as, Collection collection) { if (null == collection) return null; Collection<Object> modifiedCollection; if (collection instanceof List) modifiedCollection = new ArrayList<Object>(); else if (collection instanceof Set) modifiedCollection = new HashSet<Object>(); else throw new RuntimeException("Unable to convert collection to proxy"); for (Object obj : collection) modifiedCollection.add(convertToProxy(as, obj)); return modifiedCollection; } @Override @SuppressWarnings("unchecked") public Object convertToObject(Object proxyObject) throws Throwable { if (proxyObject instanceof NotAProxy) { return proxyObject; } else if (proxyObject instanceof BigDecimal) { return proxyObject; } Map<Object, Object> map = new IdentityHashMap<Object, Object>(); if (proxyObject instanceof Collection) { Collection<Object> unwrapedProxyObjects = new ArrayList<Object>(); Collection<Object> batchQueries = (Collection<Object>) proxyObject; for (Object tempProxyObject : batchQueries) { Object unwrapedProxyObject = convertToObject(map, tempProxyObject); unwrapedProxyObjects.add(unwrapedProxyObject); } return unwrapedProxyObjects; } Object unwrapedProxyObject = convertToObject(map, proxyObject); return unwrapedProxyObject; } @SuppressWarnings({ "unchecked", "nls" }) private Object convertToObject(Map<Object, Object> map, Object proxyObject) throws Exception { if (isPrimitiveObject(proxyObject) || proxyObject instanceof Class || proxyObject instanceof DetachedCriteria) { return proxyObject; } Object plainObject = convertProxyToObject(proxyObject); Object mapPlainObject = map.get(plainObject); if (mapPlainObject != null) return mapPlainObject; map.put(plainObject, plainObject); Method[] methods = plainObject.getClass().getMethods(); for (Method method : methods) { if (method.getName().startsWith("get") && method.getParameterTypes().length == 0 && !method.isAnnotationPresent(Transient.class)) { Object childObject = method.invoke(plainObject); if (!(childObject == null || isPrimitiveObject(childObject) || childObject instanceof Class) && Hibernate.isInitialized(childObject)) { if (childObject instanceof ListProxy) { ListProxy objectProxy = (ListProxy) childObject; int associationSize = objectProxy.size(); if (associationSize != objectProxy.getListChunk() .size()) { String associationName = null; if (objectProxy.getListChunk().size() > 0) { String cglibClassName = objectProxy .getListChunk().get(0).getClass().getName(); int startindex = cglibClassName .indexOf("$$EnhancerByCGLIB"); associationName = cglibClassName.substring(0, startindex); } String className = objectProxy.getTargetClassName(); throw new Exception( "update or delete elements for the association " + associationName + " is not allowed.association " + associationName + " for Class " + className + " is not fully initialized. Total size of assocation in database " + associationSize + " retrieved size is " + objectProxy.getListChunk().size() + "."); } } log.debug("invoking {} on class {}", method.getName(), plainObject.getClass()); String setterMethodName = "set" + method.getName().substring(3); if (childObject instanceof List && !(childObject instanceof Set)) { Object plainObjectCollection = convertProxyToObject(childObject); Collection<Object> objects = (Collection<Object>) plainObjectCollection; Collection<Object> tempObjects = new ArrayList<Object>(); for (Object object : objects) { Object child = convertToObject(map, object); tempObjects.add(child); } Method setterMethod = plainObject.getClass().getMethod( setterMethodName, new Class[] { method.getReturnType() }); setterMethod.invoke(plainObject, tempObjects); } else if (childObject instanceof Collection) { Object plainObjectCollection = convertProxyToObject(childObject); Collection<Object> objects = (Collection<Object>) plainObjectCollection; Collection<Object> tempObjects = new HashSet<Object>(); for (Object object : objects) { Object child = convertToObject(map, object); tempObjects.add(child); } Method setterMethod = plainObject.getClass().getMethod( setterMethodName, new Class[] { method.getReturnType() }); setterMethod.invoke(plainObject, tempObjects); } else { try { Method setterMethod = plainObject.getClass() .getMethod(setterMethodName, new Class[] { method.getReturnType() }); Object child = convertToObject(map, childObject); setterMethod.invoke(plainObject, child); } catch (Exception e) { // } } } } } return plainObject; } private boolean isPrimitiveObject(Object obj) { if (obj == null || obj instanceof Integer || obj instanceof Float || obj instanceof Double || obj instanceof Character || obj instanceof Long || obj instanceof Boolean || obj instanceof Byte || obj instanceof Short || obj instanceof String || obj instanceof Date) { return true; } return false; } private Object convertProxyToObject(Object obj) { if (obj == null) return null; while (obj != null && obj instanceof Advised) { Advised proxy = (org.springframework.aop.framework.Advised) obj; try { obj = proxy.getTargetSource().getTarget(); } catch (Exception e) { e.printStackTrace(); } } return obj; } private Object convertListProxyToProxy(ApplicationService as, AbstractBiobankListProxy<?> proxy) { proxy.setAppService(as); // We don't convert the chunk: it is suppose to contain only simple // object, no model objects // List<Object> chunk = proxy.getListChunk(); // @SuppressWarnings("unchecked") // List<Object> modifiedChunk = new ArrayList<Object>( // (Collection<Object>) convertToProxy(as, chunk)); // proxy.setListChunk(modifiedChunk); return proxy; } /** * Copy of ProxyHelperImpl.lazyLoad */ @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(); if (methodName.startsWith("get") && (args == null || args.length == 0)) { //$NON-NLS-1$ String fieldName = methodName.substring(3); fieldName = Character.toLowerCase(fieldName.charAt(0)) + fieldName.substring(1); Field field = getField(bean, fieldName); if (field == null) { // Fix for [#8200] Query generator assumes // lowercase association names fieldName = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); field = getField(bean, fieldName); } Object obj = as.getAssociation(createClone(bean), fieldName); Object value = obj; if (obj instanceof ListProxy) ((ListProxy) obj).setAppService(as); // Add this part for our own ListProxy if (obj instanceof AbstractBiobankListProxy) ((AbstractBiobankListProxy<?>) obj).setAppService(as); if (!Collection.class.isAssignableFrom(field.getType())) { Collection<?> results = (Collection<?>) obj; if (results.size() == 1) value = results.iterator().next(); else if (results.size() == 0) value = null; else throw new Exception( "Invalid data obtained from the database for the " //$NON-NLS-1$ + fieldName + " attribute of the " //$NON-NLS-1$ + bean.getClass().getName()); } Class<?>[] params = new Class[] { field.getType() }; Method setter = getMethod(bean, "set" + method.getName().substring(3), params); //$NON-NLS-1$ if (setter != null && params.length == 1) setter.invoke(bean, new Object[] { value }); return value; } return null; } @Override protected Object convertObjectToProxy(ApplicationService as, Object obj) { if (null == obj) return null; if (obj instanceof Map) return obj; return super.convertObjectToProxy(as, obj); } }