package pt.ist.fenixframework.pstm;
import jvstm.VBoxBody;
import pt.ist.fenixframework.DomainObject;
public class VBox<E> extends jvstm.VBox<E> implements VersionedSubject,dml.runtime.FenixVBox<E> {
static final Object NOT_LOADED_VALUE = new Object();
//initialized in the constructor
private final DomainObject ownerObj;
private final String slotName;
public static <T> T notLoadedValue() {
return (T)NOT_LOADED_VALUE;
}
public VBox(DomainObject ownerObj, String slotName) {
super();
this.ownerObj = ownerObj;
this.slotName = slotName;
}
public VBox(DomainObject ownerObj, String slotName, E initial) {
super(initial);
this.ownerObj = ownerObj;
this.slotName = slotName;
}
protected VBox(DomainObject ownerObj, String slotName, VBoxBody<E> body) {
super(body);
this.ownerObj = ownerObj;
this.slotName = slotName;
}
public DomainObject getOwnerObject() {
return this.ownerObj;
}
public String getSlotName() {
return this.slotName;
}
public E get(Object obj, String attrName) {
return Transaction.currentFenixTransaction().getBoxValue(this, obj, attrName);
}
public void put(Object obj, String attrName, E newValue) {
// TODO: eventually remove this
if (! (attrName.equals("idInternal") || attrName.equals("ackOptLock"))) {
// the set of the idInternal or ackOptLock is performed by OJB and should not be logged
Transaction.storeObject((DomainObject)obj, attrName);
}
put(newValue);
}
public boolean hasValue() {
return Transaction.currentFenixTransaction().isBoxValueLoaded(this);
}
public void putNotLoadedValue() {
this.put(VBox.<E>notLoadedValue());
}
protected void persistentLoad(E value) {
int txNumber = Transaction.current().getNumber();
persistentLoad(value, txNumber);
}
public void persistentLoad(Object value, int txNumber) {
// find appropriate body
VBoxBody<E> body = this.body.getBody(txNumber);
if (body.value == NOT_LOADED_VALUE) {
body.value = (E)value;
}
}
public VBoxBody addNewVersion(String attr, int txNumber) {
if (body.version < txNumber) {
return commit(VBox.<E>notLoadedValue(), txNumber);
} else {
// when adding a new version to a box it may happen that a
// version with the same number exists already, if we are
// processing the change logs in the same server that
// committed those changelogs, between the time when the
// changelog were written to the database and the commit
// finishes setting the committed tx number
//
// so, do nothing and just return null
//System.out.println("!!! WARNING !!!: adding older version for a box attr " + attr + " -> " + body.version + " not < " + txNumber);
return null;
}
}
public Object getCurrentValue(Object obj, String attrName) {
return this.get(obj, attrName);
}
boolean reload(Object obj, String attr) {
try {
doReload(obj, attr);
return true;
} catch (Throwable e) {
// what to do?
System.err.println("Couldn't reload attribute '" + attr + "': " + e.getMessage());
//e.printStackTrace();
return false;
}
}
protected void doReload(Object obj, String attr) {
throw new Error("Can't reload a simple VBox. Use a PrimitiveBox or a ReferenceBox instead.");
}
public static <T> VBox<T> makeNew(DomainObject ownerObj, String slotName, boolean allocateOnly, boolean isReference) {
if (isReference) {
if (allocateOnly) {
// when a box is allocated, it is safe
// to say that the version number is 0
return new ReferenceBox<T>(ownerObj, slotName, makeNewBody((T)NOT_LOADED_VALUE, 0, null));
} else {
return new ReferenceBox<T>(ownerObj, slotName);
}
} else {
if (allocateOnly) {
// when a box is allocated, it is safe
// to say that the version number is 0
return new PrimitiveBox<T>(ownerObj, slotName, makeNewBody((T)NOT_LOADED_VALUE, 0, null));
} else {
return new PrimitiveBox<T>(ownerObj, slotName);
}
}
}
public void setFromOJB(Object obj, String attr, E value) {
persistentLoad(value);
}
}