org.jsimpledb.change.ChangeCopier Maven / Gradle / Ivy
/*
* Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
*/
package org.jsimpledb.change;
import com.google.common.base.Preconditions;
import org.jsimpledb.CopyState;
import org.jsimpledb.JObject;
import org.jsimpledb.JTransaction;
/**
* Creates a new {@link Change} object based on an existing one where the {@link JObject}s referred to by the
* new {@link Change} are copies in a different transaction of the originals. This is useful to allow database
* change information to be accessed after the transaction in which the change occured has completed.
*
*
* Each instance has an internal {@link CopyState} used to avoid redundant copies, accessible via {@link #getCopyState}.
*/
public class ChangeCopier implements ChangeSwitch> {
protected final JTransaction dest;
protected final CopyState copyState = new CopyState();
/**
* Primary constructor.
*
* @param dest destination transaction for copied {@link JObject}s
* @throws IllegalArgumentException if {@code dest} is null
*/
public ChangeCopier(JTransaction dest) {
Preconditions.checkArgument(dest != null, "null dest");
this.dest = dest;
}
/**
* "Snapshot" constructor for when the destination transaction is the "snapshot" transaction of the transaction
* associated with the current thread.
*
*
* This is a convenience constructor, equivalent to:
*
* ChangeCopier(JTransaction.getCurrent().getSnapshotTransaction())
*
*
* @throws IllegalStateException if this is not a snapshot instance and there is no {@link JTransaction}
* associated with the current thread
*/
public ChangeCopier() {
this(JTransaction.getCurrent().getSnapshotTransaction());
}
/**
* Get the destination transaction configured in this instance.
*
* @return destination transaction
*/
public JTransaction getDestinationTransaction() {
return this.dest;
}
/**
* Get the {@link CopyState} used by this instance.
*
* @return associated copy state
*/
public CopyState getCopyState() {
return this.copyState;
}
@Override
public ObjectCreate caseObjectCreate(ObjectCreate change) {
return new ObjectCreate(this.copyIfReference(change.getObject()));
}
@Override
public ObjectDelete caseObjectDelete(ObjectDelete change) {
return new ObjectDelete(this.copyIfReference(change.getObject()));
}
@Override
public ListFieldAdd caseListFieldAdd(ListFieldAdd change) {
return new ListFieldAdd(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(),
change.getIndex(), this.copyIfReference(change.getElement()));
}
@Override
public ListFieldClear caseListFieldClear(ListFieldClear change) {
return new ListFieldClear(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName());
}
@Override
public ListFieldRemove caseListFieldRemove(ListFieldRemove change) {
return new ListFieldRemove(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(),
change.getIndex(), this.copyIfReference(change.getElement()));
}
@Override
public ListFieldReplace caseListFieldReplace(ListFieldReplace change) {
return new ListFieldReplace(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(),
change.getIndex(), this.copyIfReference(change.getOldValue()), this.copyIfReference(change.getNewValue()));
}
@Override
public MapFieldAdd caseMapFieldAdd(MapFieldAdd change) {
return new MapFieldAdd(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(),
this.copyIfReference(change.getKey()), this.copyIfReference(change.getValue()));
}
@Override
public MapFieldClear caseMapFieldClear(MapFieldClear change) {
return new MapFieldClear(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName());
}
@Override
public MapFieldRemove caseMapFieldRemove(MapFieldRemove change) {
return new MapFieldRemove(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(),
this.copyIfReference(change.getKey()), this.copyIfReference(change.getValue()));
}
@Override
public MapFieldReplace caseMapFieldReplace(MapFieldReplace change) {
return new MapFieldReplace(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(),
this.copyIfReference(change.getKey()), this.copyIfReference(change.getOldValue()),
this.copyIfReference(change.getNewValue()));
}
@Override
public SetFieldAdd caseSetFieldAdd(SetFieldAdd change) {
return new SetFieldAdd(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(),
this.copyIfReference(change.getElement()));
}
@Override
public SetFieldClear caseSetFieldClear(SetFieldClear change) {
return new SetFieldClear(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName());
}
@Override
public SetFieldRemove caseSetFieldRemove(SetFieldRemove change) {
return new SetFieldRemove(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(),
this.copyIfReference(change.getElement()));
}
@Override
public SimpleFieldChange caseSimpleFieldChange(SimpleFieldChange change) {
return new SimpleFieldChange(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(),
this.copyIfReference(change.getOldValue()), this.copyIfReference(change.getNewValue()));
}
@SuppressWarnings("unchecked")
private T copyIfReference(T obj) {
return obj instanceof JObject ? (T)this.copy((JObject)obj) : obj;
}
/**
* Copy the given {@link JObject} into the destination transaction.
*
*
* The implementation in {@link ChangeCopier} invokes {@code jobj.copyTo(this.dest, null, this.getCopyState())} unless
* {@code jobj} does not exist, in which case it is not copied (but the
* {@linkplain JTransaction#get(ObjId) corresponding} {@link JObject} is still returned).
* Subclasses may override to copy additional objects referenced by {@code jobj} as needed.
*
* @param jobj original object
* @return copied object in {@link #dest}
* @throws IllegalArgumentException if {@code jobj} is null
*/
@SuppressWarnings("unchecked")
protected JObject copy(JObject jobj) {
Preconditions.checkArgument(jobj != null, "null jobj");
return !jobj.exists() ? this.dest.get(jobj) : jobj.copyTo(this.dest, null, this.getCopyState());
}
}