package edu.ualberta.med.biobank.common.wrappers.property;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.Session;
import edu.ualberta.med.biobank.common.wrappers.Property;
// TODO: this class is pretty bad because it requires a new interceptor to be used with each property get. should try and use some sort of tracking information.
public class LazyLoaderInterceptor implements GetterInterceptor, Serializable {
private static final long serialVersionUID = 1L;
private static final String HQL = "SELECT o.{0} FROM {1} o WHERE o = ?"; //$NON-NLS-1$
private final Session session;
private final Integer maxMemoryDepth;
private Integer depth = 1;
public LazyLoaderInterceptor(Session session) {
this(session, null);
}
public LazyLoaderInterceptor(Session session, Integer maxMemoryDepth) {
this.session = session;
this.maxMemoryDepth = maxMemoryDepth;
}
@Override
public <P, M> P get(Property<P, M> subProperty, M model) {
P value = null;
String propertyName = subProperty.getName();
if (isLegalDepth()
&& Hibernate.isPropertyInitialized(model, propertyName)) {
value = subProperty.get(model);
} else {
String modelName = subProperty.getModelClass().getName();
String hql = MessageFormat.format(HQL, propertyName, modelName);
Query query = session.createQuery(hql);
query.setCacheable(false); // don't interfere with cache
query.setParameter(0, model);
List<?> results = query.list();
if (subProperty.isCollection()) {
@SuppressWarnings("unchecked")
P tmp = (P) results;
value = tmp;
} else {
@SuppressWarnings("unchecked")
P tmp = (P) results.get(0);
value = tmp;
}
}
depth++;
return value;
}
private boolean isLegalDepth() {
return maxMemoryDepth == null || depth <= maxMemoryDepth;
}
}