package edu.ualberta.med.biobank.common.wrappers;
import java.util.HashMap;
import edu.ualberta.med.biobank.common.wrappers.util.ProxyUtil;
/**
* A registry of wrapped model objects to the {@link ModelWrapper} that wrap
* them. Used so that when get is called on a model object graph to expand the
* graph (by lazily loading more objects from the database), if a model object
* already exists in the session, then it is used instead of what the database
* returned.
*
* @author jferland
*
*/
public class WrapperSession {
// HashMap instead of IdentityHashMap because if the same model is read from
// the database twice, we want to use the model we already have in memory
// instead so there is only ever one copy of any object read from the
// database in an object graph made by get-method calls. However, if an
// object is set from a completely separate graph, this guarantee is no
// longer made.
private HashMap<Object, ModelWrapper<?>> map = new HashMap<Object, ModelWrapper<?>>();
public WrapperSession(ModelWrapper<?> wrapper) {
// TODO: if a wrapper already has a WrapperSession, then perhaps it
// should be removed from its old value. This can happen on a reset or
// reload or setWrappedObject. Note that this is really messed up
// because wrappers will still have a reference to this wrapper, but the
// model objects wont. I really don't like reset and reload.
add(wrapper);
}
public void add(ModelWrapper<?> wrapper) {
if (wrapper != null) {
wrapper.session = this;
map.put(new ModelKey(wrapper.wrappedObject), wrapper);
}
}
public Object get(Object model) {
return map.get(new ModelKey(model));
}
public Object remove(Object model) {
return map.remove(new ModelKey(model));
}
/**
* Necessary because model objects only equals() each other if
* {@code getId()} is not null, otherwise they return false, even if they
* are literally the exact same object in memory.
*
* @author jferland
*
*/
private static class ModelKey {
private final Object object;
public ModelKey(Object object) {
// at some point it looked like multiple proxies exist for the same
// model object, so work with the raw model object instead of the
// possible proxy
Object unproxied = ProxyUtil.convertProxyToObject(object);
this.object = unproxied;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((object == null) ? 0 : object.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ModelKey other = (ModelKey) obj;
if (object == null) {
if (other.object != null)
return false;
} else if (!object.equals(other.object) && object != other.object)
return false;
return true;
}
}
}