-
Notifications
You must be signed in to change notification settings - Fork 3
Tracked Views
Tracked views can be used to track values derived from the original stored object automatically up to date. This avoids the need to compute the values again and again. When creating the store the tracked views (implementing the TrackedView<ObjectType> interface where ObjectType is the class of the stored objects) are registered at the tracked view registry of the store. Later it is possible to access a snapshot of the tracked view by calling the getView method at the tracked view registry. Note that the snapshot includes all changes done inside the transaction where it was taken and all committed changes by other transactions.
First we show an example of a tracked view tracking the total balance of all stored accounts:
public static class TotalBalanceView implements TrackedView<Account> {
private long totalBalance = 0;
// tracked views must be cloneable to create the snapshots...
@SuppressWarnings("unchecked")
@Override
public TrackedView<Account> clone() {
try {
return (TrackedView<Account>) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException("clone failed");
}
}
// the method actually tracking the modification of an object
// (for creations / deletions the oldValue / newValue is null)
@Override
public void trackModification(Account oldValue, Account newValue) {
totalBalance += newValue == null ? 0 : newValue.getBalance();
totalBalance -= oldValue == null ? 0 : oldValue.getBalance();
}
// An (optional) method to check the value of the view.
// This is called after commit if configured in the JacisObjectTypeSpec passed to create the store.
@Override
public void checkView(List<Account> values) {
long checkValue = values.stream().mapToLong(a -> a.getBalance()).sum();
if (totalBalance != checkValue) {
throw new IllegalStateException("Corrupt view! Tracked value=" + totalBalance + " computed value=" + checkValue);
}
}
@Override
public void clear() {
totalBalance = 0;
}
public long getTotalBalance() {
return totalBalance;
}
}
The tracked view is registered after creation of the store. Later it is possible to get a snapshot of the view either inside or without a transaction.
JacisContainer container = new JacisContainer();
JacisObjectTypeSpec<String, Account> objectTypeSpec = new JacisObjectTypeSpec<>(String.class, Account.class);
JacisStore<String, Account> store = container.createStore(objectTypeSpec);
// First register the tracked view
store.getTrackedViewRegistry().registerTrackedView(new TotalBalanceView());
// First we create some accounts to have some test data...
container.withLocalTx(() -> {
store.update("account1", new Account("account1").deposit(-100));
store.update("account2", new Account("account2").deposit(10));
store.update("account3", new Account("account3").deposit(100));
});
// on commit the tracked view is updated automatically
TotalBalanceView view0 = store.getTrackedViewRegistry().getView(TotalBalanceView.class);
System.out.println("tracked balance=" + view0.getTotalBalance());
// inside a transaction the transaction local view of the values is respected
container.withLocalTx(() -> {
store.update("account1", store.get("account1").deposit(1000));
store.update("account4", new Account("account4").deposit(101));
// note that the getView method takes a snapshot at the time it is called...
TotalBalanceView view1 = store.getTrackedViewRegistry().getView(TotalBalanceView.class);
System.out.println("tracked balance=" + view1.getTotalBalance());
// later updates are not tracked by this snapshot
store.update("account1", store.get("account1").deposit(1000));
System.out.println("tracked balance old snapshot=" + view1.getTotalBalance());
TotalBalanceView view2 = store.getTrackedViewRegistry().getView(TotalBalanceView.class);
System.out.println("tracked balance new snapshot=" + view2.getTotalBalance());
});