package pt.ist.fenixframework.backend.jvstmojb.pstm;
import jvstm.Transaction;
import jvstm.VBoxBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pt.ist.fenixframework.DomainObject;
public class VBox<E> extends jvstm.VBox<E> implements VersionedSubject {
private static final Logger logger = LoggerFactory.getLogger(VBox.class);
static final Object NOT_LOADED_VALUE = new Object();
private static final class ThisObjectHasBeenDeleted {
@Override
public String toString() {
return "This object has been deleted";
}
}
protected static final Object DELETED_VALUE = new ThisObjectHasBeenDeleted();
//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 TransactionSupport.currentFenixTransaction().getBoxValue(this, obj, attrName);
}
public void put(Object obj, String attrName, E newValue) {
TransactionSupport.storeObject((AbstractDomainObject) obj, attrName);
put(newValue);
}
/*
* Allows a nested FenixConsistencyCheckTransaction, that cannot perform writes,
* to delegate the write to boxes to the parent TopLevelTransaction.
*/
public void putInParent(E newE) {
FenixTransaction tx = TransactionSupport.currentFenixTransaction();
if (tx == null) {
throw new Error("Trying to putInParent() a box value without a running transaction!");
} else {
tx.setBoxValueInParent(this, newE);
}
}
public boolean hasValue() {
return TransactionSupport.currentFenixTransaction().isBoxValueLoaded(this);
}
public void putNotLoadedValue() {
this.put(VBox.<E> notLoadedValue());
}
@SuppressWarnings("unchecked")
void markAsDeleted() {
put((E) DELETED_VALUE);
}
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;
}
}
@Override
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
// logger.warn("!!! WARNING !!!: adding older version for a box attr " + attr + " -> " + body.version + " not < " + txNumber);
return null;
}
}
@Override
public Object getCurrentValue(Object obj, String attrName) {
return this.get(obj, attrName);
}
void reload(Object obj, String attr) {
try {
doReload(obj, attr);
} catch (Throwable e) {
throw new VersionNotAvailableException(attr, obj, e);
}
}
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);
}
}