package io.ebean; import java.util.ArrayList; /** * Holds the definition of how a transactional method should run. * <p> * This information matches the features of the Transactional annotation. You * can use it directly with TxRunnable or TxCallable via * {@link Ebean#execute(TxScope, TxCallable)} or * {@link Ebean#execute(TxScope, TxRunnable)}. * </p> * <p> * This object is used internally with the enhancement of a method with * Transactional annotation. * </p> * * @see TxCallable * @see TxRunnable * @see Ebean#execute(TxScope, TxCallable) * @see Ebean#execute(TxScope, TxRunnable) */ public final class TxScope { TxType type; String serverName; TxIsolation isolation; PersistBatch batch; PersistBatch batchOnCascade; int batchSize; boolean skipGeneratedKeys; boolean readOnly; ArrayList<Class<? extends Throwable>> rollbackFor; ArrayList<Class<? extends Throwable>> noRollbackFor; /** * Helper method to create a TxScope with REQUIRES. */ public static TxScope required() { return new TxScope(TxType.REQUIRED); } /** * Helper method to create a TxScope with REQUIRES_NEW. */ public static TxScope requiresNew() { return new TxScope(TxType.REQUIRES_NEW); } /** * Helper method to create a TxScope with MANDATORY. */ public static TxScope mandatory() { return new TxScope(TxType.MANDATORY); } /** * Helper method to create a TxScope with SUPPORTS. */ public static TxScope supports() { return new TxScope(TxType.SUPPORTS); } /** * Helper method to create a TxScope with NOT_SUPPORTED. */ public static TxScope notSupported() { return new TxScope(TxType.NOT_SUPPORTED); } /** * Helper method to create a TxScope with NEVER. */ public static TxScope never() { return new TxScope(TxType.NEVER); } /** * Create a REQUIRED transaction scope. */ public TxScope() { this.type = TxType.REQUIRED; } /** * Create with a given transaction scope type. */ public TxScope(TxType type) { this.type = type; } /** * Describes this TxScope instance. */ @Override public String toString() { return "TxScope[" + type + "] readOnly[" + readOnly + "] isolation[" + isolation + "] serverName[" + serverName + "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]"; } /** * Return true if PersistBatch has been set. */ public boolean isBatchSet() { return batch != null && batch != PersistBatch.INHERIT; } /** * Return true if batch on cascade has been set. */ public boolean isBatchOnCascadeSet() { return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT; } /** * Return true if batch size has been set. */ public boolean isBatchSizeSet() { return batchSize > 0; } /** * Check for batchSize being set without batch mode and use this to imply PersistBatch.ALL. */ public void checkBatchMode() { if (batchSize > 0 && notSet(batch) && notSet(batchOnCascade)) { // Use setting the batchSize as implying PersistBatch.ALL for @Transactional batch = PersistBatch.ALL; } } /** * Return true if the mode is considered not set. */ private boolean notSet(PersistBatch batchMode) { return batchMode == null || batchMode == PersistBatch.INHERIT; } /** * Return the transaction type. */ public TxType getType() { return type; } /** * Set the transaction type. */ public TxScope setType(TxType type) { this.type = type; return this; } /** * Return the batch mode. */ public PersistBatch getBatch() { return batch; } /** * Set the batch mode to use. */ public TxScope setBatch(PersistBatch batch) { this.batch = batch; return this; } /** * Return the batch on cascade mode. */ public PersistBatch getBatchOnCascade() { return batchOnCascade; } /** * Set the batch on cascade mode. */ public TxScope setBatchOnCascade(PersistBatch batchOnCascade) { this.batchOnCascade = batchOnCascade; return this; } /** * Return the batch size. 0 means use the default value. */ public int getBatchSize() { return batchSize; } /** * Set the batch size to use. */ public TxScope setBatchSize(int batchSize) { this.batchSize = batchSize; return this; } /** * Set if the transaction should skip reading generated keys for inserts. */ public TxScope setSkipGeneratedKeys() { this.skipGeneratedKeys = true; return this; } /** * Return true if getGeneratedKeys should be skipped for this transaction. */ public boolean isSkipGeneratedKeys() { return skipGeneratedKeys; } /** * Return if the transaction should be treated as read only. */ public boolean isReadonly() { return readOnly; } /** * Set if the transaction should be treated as read only. */ public TxScope setReadOnly(boolean readOnly) { this.readOnly = readOnly; return this; } /** * Return the Isolation level this transaction should run with. */ public TxIsolation getIsolation() { return isolation; } /** * Set the transaction isolation level this transaction should run with. */ public TxScope setIsolation(TxIsolation isolation) { this.isolation = isolation; return this; } /** * Return the serverName for this transaction. If this is null then the * default server (default DataSource) will be used. */ public String getServerName() { return serverName; } /** * Set the serverName (DataSource name) for which this transaction will be. If * the serverName is not specified (left null) then the default server will be * used. */ public TxScope setServerName(String serverName) { this.serverName = serverName; return this; } /** * Return the throwable's that should cause a rollback. */ public ArrayList<Class<? extends Throwable>> getRollbackFor() { return rollbackFor; } /** * Set a Throwable that should explicitly cause a rollback. */ public TxScope setRollbackFor(Class<? extends Throwable> rollbackThrowable) { if (rollbackFor == null) { rollbackFor = new ArrayList<>(2); } rollbackFor.add(rollbackThrowable); return this; } /** * Set multiple throwable's that will cause a rollback. */ @SuppressWarnings("unchecked") public TxScope setRollbackFor(Class<?>[] rollbackThrowables) { if (rollbackFor == null) { rollbackFor = new ArrayList<>(rollbackThrowables.length); } for (Class<?> rollbackThrowable : rollbackThrowables) { rollbackFor.add((Class<? extends Throwable>) rollbackThrowable); } return this; } /** * Return the throwable's that should NOT cause a rollback. */ public ArrayList<Class<? extends Throwable>> getNoRollbackFor() { return noRollbackFor; } /** * Add a Throwable to a list that will NOT cause a rollback. You are able to * call this method multiple times with different throwable's and they will * added to a list. */ public TxScope setNoRollbackFor(Class<? extends Throwable> noRollback) { if (noRollbackFor == null) { noRollbackFor = new ArrayList<>(2); } this.noRollbackFor.add(noRollback); return this; } /** * Set multiple throwable's that will NOT cause a rollback. */ @SuppressWarnings("unchecked") public TxScope setNoRollbackFor(Class<?>[] noRollbacks) { if (noRollbackFor == null) { noRollbackFor = new ArrayList<>(noRollbacks.length); } for (Class<?> noRollback : noRollbacks) { noRollbackFor.add((Class<? extends Throwable>) noRollback); } return this; } }