package edu.ualberta.med.biobank.common.wrappers.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.sf.cglib.proxy.Enhancer;
import org.hibernate.Hibernate;
import org.hibernate.proxy.HibernateProxy;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import edu.ualberta.med.biobank.common.wrappers.ModelWrapper;
import gov.nih.nci.system.applicationservice.WritableApplicationService;
public class WrapperUtil {
private static final Map<Class<?>, Class<?>> modelClassMap =
new HashMap<Class<?>, Class<?>>();
public static <E> Class<? extends ModelWrapper<E>> getWrapperClass(
Class<E> modelClass) {
@SuppressWarnings("unchecked")
Class<? extends ModelWrapper<E>> wrapperClass =
(Class<? extends ModelWrapper<E>>) modelClassMap
.get(modelClass);
if (wrapperClass == null && !modelClassMap.containsKey(modelClass)) {
wrapperClass = findWrapperClass(modelClass);
modelClassMap.put(modelClass, wrapperClass);
}
return wrapperClass;
}
public static <E> Class<? extends ModelWrapper<E>> findWrapperClass(
Class<E> modelClass) {
Class<? extends ModelWrapper<E>> wrapperClass = null;
String packageName = ModelWrapper.class.getPackage().getName();
String internalPackageName = packageName + ".internal"; //$NON-NLS-1$
String classSimpleName = modelClass.getSimpleName() + "Wrapper"; //$NON-NLS-1$
try {
@SuppressWarnings("unchecked")
Class<? extends ModelWrapper<E>> tmp =
(Class<? extends ModelWrapper<E>>) Class
.forName(packageName + "." + classSimpleName); //$NON-NLS-1$
wrapperClass = tmp;
} catch (ClassNotFoundException e) {
try {
@SuppressWarnings("unchecked")
Class<? extends ModelWrapper<E>> tmp =
(Class<? extends ModelWrapper<E>>) Class
.forName(internalPackageName + "." + classSimpleName); //$NON-NLS-1$
wrapperClass = tmp;
} catch (ClassNotFoundException e1) {
}
}
return wrapperClass;
}
@SuppressWarnings("unchecked")
public static <W extends ModelWrapper<? extends M>, M> W wrapModel(
WritableApplicationService appService, M model, Class<W> wrapperKlazz) {
if (model == null)
return null;
try {
Class<?> modelKlazz = model.getClass();
if (Enhancer.isEnhanced(modelKlazz)) {
// if the given model's Class is 'enhanced' by CGLIB, then the
// superclass container the real class
modelKlazz = modelKlazz.getSuperclass();
if (Modifier.isAbstract(modelKlazz.getModifiers())) {
// The super class can be a problem when the class is
// abstract,
// but it should be an instance of Advised, that contain the
// real (non-proxied/non-enhanced) model object.
if (model instanceof Advised) { // ok for client side
TargetSource ts = ((Advised) model).getTargetSource();
modelKlazz = ts.getTarget().getClass();
} else if (model instanceof HibernateProxy) {
// only on server side (?).
Object implementation = ((HibernateProxy) model)
.getHibernateLazyInitializer().getImplementation();
modelKlazz = implementation.getClass();
// Is this bad to do that ? On server side, will get a
// proxy
// that inherit from Center, not from Site, so won't be
// able
// to create a SiteWrapper unless is using the direct
// implementation
model = (M) implementation;
}
}
} else
modelKlazz = Hibernate.getClass(model);
if (wrapperKlazz == null
|| Modifier.isAbstract(wrapperKlazz.getModifiers())) {
Class<W> tmp = (Class<W>) getWrapperClass(modelKlazz);
wrapperKlazz = tmp;
}
Class<?>[] params = new Class[] { WritableApplicationService.class,
modelKlazz };
Constructor<W> constructor = wrapperKlazz.getConstructor(params);
Object[] args = new Object[] { appService, model };
W wrapper = constructor.newInstance(args);
return wrapper;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// TODO: can this be replaced with wrapModel?
public static ModelWrapper<?> wrapObject(
WritableApplicationService appService, Object nakedObject)
throws Exception {
Class<?> nakedKlazz = nakedObject.getClass();
String wrapperClassName = ModelWrapper.class.getPackage().getName()
+ "." + nakedObject.getClass().getSimpleName() + "Wrapper"; //$NON-NLS-1$//$NON-NLS-2$
try {
Class<?> wrapperKlazz = Class.forName(wrapperClassName);
Class<?>[] params = new Class[] { WritableApplicationService.class,
nakedKlazz };
Constructor<?> constructor = wrapperKlazz.getConstructor(params);
Object[] args = new Object[] { appService, nakedObject };
return (ModelWrapper<?>) constructor.newInstance(args);
} catch (Exception e) {
throw new Exception("cannot find or create expected Wrapper (" //$NON-NLS-1$
+ wrapperClassName + ") for " + nakedKlazz.getName(), e); //$NON-NLS-1$
}
}
// public static <E> Property<Integer, ? super E> getIdProperty() {
//
// }
// TODO: write function to return ID property for a given class!!!!
public static <E> Collection<E> unwrapCollection(
Collection<ModelWrapper<E>> wrapperCollection) {
Collection<E> unwrapped = new ArrayList<E>();
for (ModelWrapper<E> wrapper : wrapperCollection) {
unwrapped.add(wrapper.getWrappedObject());
}
return unwrapped;
}
public static Set<Integer> getCollectionIds(
Collection<? extends ModelWrapper<?>> wrapperCollection) {
Set<Integer> ids = new HashSet<Integer>();
for (ModelWrapper<?> wrapper : wrapperCollection) {
ids.add(wrapper.getId());
}
return ids;
}
}