org.multiverse.templates.OrElseTemplate Maven / Gradle / Ivy
package org.multiverse.templates;
import org.multiverse.api.Transaction;
import org.multiverse.api.exceptions.Retry;
import static org.multiverse.api.ThreadLocalTransaction.getThreadLocalTransaction;
/**
* A template for the 'orelse' functionality provided by the STM. Orelse has to do with blocking and not with clashing
* transactions. With the or else functionality you are able to block on multiple structures, for example (pseudo
* code):
*
* def stack1: new TransactionalStack();
* def stack2: new TransactionalStack();
*
* atomic{
* return stack1.pop();
* }orelse{
* return stack2.pop();
* }
*
*
* The possible outcomes are: - an item from stack 1 is popped and returned
- an item from stack 2 is
* popped and returned
- the transaction is going to block on stack1 and stack2 and is woken up once an item is
* placed on either of them. Once the transaction is woken up, it reexecutes the complete transaction.
This
* functionality is very hard to realize with classic lock based concurrency, but no problem with STM's.
*
* And OrElse templates are allowed to be nested!
*
* A template for the 'orelse' functionality. Example:
*
* String item = new OrElseTemplate(){
*
* String run(Transaction t){
* return stack1.pop();
* }
*
* String orelscerun(Transaction t){
* return stack2.pop();
* }
* }.execute();
*
*
* If an exception is thrown in the run block, the block is ended but the orelse block is not started and the exception
* is propagated.
*
* Does not start a transaction if no transaction is found.
*
* @author Peter Veentjer.
* @param
*/
public abstract class OrElseTemplate {
private final Transaction tx;
/**
* Creates a OrElseTemplate using the transaction in the getThreadLocalTransaction.
*
* @throws NullPointerException if no transaction is found.
*/
public OrElseTemplate() {
this(getThreadLocalTransaction());
}
/**
* Creates an OrElseTemplate using the provided transaction.
*
* @param tx the provided transaction.
* @throws NullPointerException if is null.
*/
public OrElseTemplate(Transaction tx) {
if (tx == null) {
throw new NullPointerException();
}
this.tx = tx;
}
public abstract E either(Transaction tx);
public abstract E orelse(Transaction tx);
public final E execute() {
try {
return either(tx);
}catch (Retry e){
return orelse(tx);
}
}
}