001package io.ebean;
002
003import io.ebean.annotation.PersistBatch;
004import io.ebean.annotation.TxIsolation;
005import io.ebean.annotation.TxType;
006
007import java.util.ArrayList;
008import java.util.concurrent.Callable;
009
010/**
011 * Holds the definition of how a transactional method should run.
012 * <p>
013 * This information matches the features of the Transactional annotation. You
014 * can use it directly with Runnable or Callable via
015 * {@link Ebean#execute(TxScope, Runnable)} or
016 * {@link Ebean#executeCall(TxScope, Callable)}.
017 * </p>
018 * <p>
019 * This object is used internally with the enhancement of a method with
020 * Transactional annotation.
021 * </p>
022 *
023 * @see Ebean#execute(TxScope, Runnable)
024 * @see Ebean#executeCall(TxScope, Callable)
025 */
026public final class TxScope {
027
028  private int profileId;
029
030  private TxType type;
031
032  private String serverName;
033
034  private TxIsolation isolation;
035
036  private PersistBatch batch;
037
038  private PersistBatch batchOnCascade;
039
040  private int batchSize;
041
042  private boolean skipGeneratedKeys;
043
044  private boolean readOnly;
045
046  /**
047   * Set this to false if the JDBC batch should not be automatically be flushed when a query is executed.
048   */
049  private boolean flushOnQuery = true;
050
051  private boolean skipCache;
052
053  private String label;
054
055  private ArrayList<Class<? extends Throwable>> rollbackFor;
056
057  private ArrayList<Class<? extends Throwable>> noRollbackFor;
058
059  private ProfileLocation profileLocation;
060
061  /**
062   * Helper method to create a TxScope with REQUIRES.
063   */
064  public static TxScope required() {
065    return new TxScope(TxType.REQUIRED);
066  }
067
068  /**
069   * Helper method to create a TxScope with REQUIRES_NEW.
070   */
071  public static TxScope requiresNew() {
072    return new TxScope(TxType.REQUIRES_NEW);
073  }
074
075  /**
076   * Helper method to create a TxScope with MANDATORY.
077   */
078  public static TxScope mandatory() {
079    return new TxScope(TxType.MANDATORY);
080  }
081
082  /**
083   * Helper method to create a TxScope with SUPPORTS.
084   */
085  public static TxScope supports() {
086    return new TxScope(TxType.SUPPORTS);
087  }
088
089  /**
090   * Helper method to create a TxScope with NOT_SUPPORTED.
091   */
092  public static TxScope notSupported() {
093    return new TxScope(TxType.NOT_SUPPORTED);
094  }
095
096  /**
097   * Helper method to create a TxScope with NEVER.
098   */
099  public static TxScope never() {
100    return new TxScope(TxType.NEVER);
101  }
102
103  /**
104   * Create a REQUIRED transaction scope.
105   */
106  public TxScope() {
107    this.type = TxType.REQUIRED;
108  }
109
110  /**
111   * Create with a given transaction scope type.
112   */
113  public TxScope(TxType type) {
114    this.type = type;
115  }
116
117  /**
118   * Describes this TxScope instance.
119   */
120  @Override
121  public String toString() {
122    return "TxScope[" + type + "] readOnly[" + readOnly + "] isolation[" + isolation
123      + "] serverName[" + serverName + "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
124  }
125
126  /**
127   * Return true if PersistBatch has been set.
128   */
129  public boolean isBatchSet() {
130    return batch != null && batch != PersistBatch.INHERIT;
131  }
132
133  /**
134   * Return true if batch on cascade has been set.
135   */
136  public boolean isBatchOnCascadeSet() {
137    return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
138  }
139
140  /**
141   * Return true if batch size has been set.
142   */
143  public boolean isBatchSizeSet() {
144    return batchSize > 0;
145  }
146
147  /**
148   * Check for batchSize being set without batch mode and use this to imply PersistBatch.ALL.
149   */
150  public void checkBatchMode() {
151    if (batchSize > 0 && notSet(batch) && notSet(batchOnCascade)) {
152      // Use setting the batchSize as implying PersistBatch.ALL for @Transactional
153      batch = PersistBatch.ALL;
154    }
155  }
156
157  /**
158   * Return true if the mode is considered not set.
159   */
160  private boolean notSet(PersistBatch batchMode) {
161    return batchMode == null || batchMode == PersistBatch.INHERIT;
162  }
163
164  /**
165   * Return the transaction type.
166   */
167  public TxType getType() {
168    return type;
169  }
170
171  /**
172   * Set the transaction type.
173   */
174  public TxScope setType(TxType type) {
175    this.type = type;
176    return this;
177  }
178
179  /**
180   * Return the transaction profile id.
181   */
182  public int getProfileId() {
183    return profileId;
184  }
185
186  /**
187   * Set the transaction profile id.
188   */
189  public TxScope setProfileId(int profileId) {
190    this.profileId = profileId;
191    return this;
192  }
193
194  /**
195   * Return the profile location.
196   */
197  public ProfileLocation getProfileLocation() {
198    return profileLocation;
199  }
200
201  /**
202   * Set the profile location.
203   */
204  public TxScope setProfileLocation(ProfileLocation profileLocation) {
205    this.profileLocation = profileLocation;
206    return this;
207  }
208
209  /**
210   * Return true if the L2 cache should be skipped for this transaction.
211   */
212  public boolean isSkipCache() {
213    return skipCache;
214  }
215
216  /**
217   * Set to true if the transaction should skip L2 cache access.
218   */
219  public TxScope setSkipCache(boolean skipCache) {
220    this.skipCache = skipCache;
221    return this;
222  }
223
224  /**
225   * Return the label for the transaction.
226   */
227  public String getLabel() {
228    return label;
229  }
230
231  /**
232   * Set a label for the transaction.
233   */
234  public TxScope setLabel(String label) {
235    this.label = label;
236    return this;
237  }
238
239  /**
240   * Return the batch mode.
241   */
242  public PersistBatch getBatch() {
243    return batch;
244  }
245
246  /**
247   * Set the batch mode to use.
248   */
249  public TxScope setBatch(PersistBatch batch) {
250    this.batch = batch;
251    return this;
252  }
253
254  /**
255   * Return the batch on cascade mode.
256   */
257  public PersistBatch getBatchOnCascade() {
258    return batchOnCascade;
259  }
260
261  /**
262   * Set the batch on cascade mode.
263   */
264  public TxScope setBatchOnCascade(PersistBatch batchOnCascade) {
265    this.batchOnCascade = batchOnCascade;
266    return this;
267  }
268
269  /**
270   * Return the batch size. 0 means use the default value.
271   */
272  public int getBatchSize() {
273    return batchSize;
274  }
275
276  /**
277   * Set the batch size to use.
278   */
279  public TxScope setBatchSize(int batchSize) {
280    this.batchSize = batchSize;
281    return this;
282  }
283
284  /**
285   * Set if the transaction should skip reading generated keys for inserts.
286   */
287  public TxScope setSkipGeneratedKeys() {
288    this.skipGeneratedKeys = true;
289    return this;
290  }
291
292  /**
293   * Return true if getGeneratedKeys should be skipped for this transaction.
294   */
295  public boolean isSkipGeneratedKeys() {
296    return skipGeneratedKeys;
297  }
298
299  /**
300   * Return if the transaction should be treated as read only.
301   */
302  public boolean isReadonly() {
303    return readOnly;
304  }
305
306  /**
307   * Set if the transaction should be treated as read only.
308   */
309  public TxScope setReadOnly(boolean readOnly) {
310    this.readOnly = readOnly;
311    return this;
312  }
313
314  /**
315   * Return false if the JDBC batch buffer should not be flushed automatically when a query is executed.
316   */
317  public boolean isFlushOnQuery() {
318    return flushOnQuery;
319  }
320
321  /**
322   * Set flushOnQuery to be false to stop automatically flushing the JDBC batch buffer when a query is executed.
323   */
324  public TxScope setFlushOnQuery(boolean flushOnQuery) {
325    this.flushOnQuery = flushOnQuery;
326    return this;
327  }
328
329  /**
330   * Return the isolation level.
331   */
332  public int getIsolationLevel() {
333    return isolation != null ? isolation.getLevel() : -1;
334  }
335
336  /**
337   * Return the Isolation level this transaction should run with.
338   */
339  public TxIsolation getIsolation() {
340    return isolation;
341  }
342
343  /**
344   * Set the transaction isolation level this transaction should run with.
345   */
346  public TxScope setIsolation(TxIsolation isolation) {
347    this.isolation = isolation;
348    return this;
349  }
350
351  /**
352   * Return the serverName for this transaction. If this is null then the
353   * default server (default DataSource) will be used.
354   */
355  public String getServerName() {
356    return serverName;
357  }
358
359  /**
360   * Set the serverName (DataSource name) for which this transaction will be. If
361   * the serverName is not specified (left null) then the default server will be
362   * used.
363   */
364  public TxScope setServerName(String serverName) {
365    this.serverName = serverName;
366    return this;
367  }
368
369  /**
370   * Return the throwable's that should cause a rollback.
371   */
372  public ArrayList<Class<? extends Throwable>> getRollbackFor() {
373    return rollbackFor;
374  }
375
376  /**
377   * Set a Throwable that should explicitly cause a rollback.
378   */
379  public TxScope setRollbackFor(Class<? extends Throwable> rollbackThrowable) {
380    if (rollbackFor == null) {
381      rollbackFor = new ArrayList<>(2);
382    }
383    rollbackFor.add(rollbackThrowable);
384    return this;
385  }
386
387  /**
388   * Set multiple throwable's that will cause a rollback.
389   */
390  @SuppressWarnings("unchecked")
391  public TxScope setRollbackFor(Class<?>[] rollbackThrowables) {
392    if (rollbackFor == null) {
393      rollbackFor = new ArrayList<>(rollbackThrowables.length);
394    }
395    for (Class<?> rollbackThrowable : rollbackThrowables) {
396      rollbackFor.add((Class<? extends Throwable>) rollbackThrowable);
397    }
398    return this;
399  }
400
401  /**
402   * Return the throwable's that should NOT cause a rollback.
403   */
404  public ArrayList<Class<? extends Throwable>> getNoRollbackFor() {
405    return noRollbackFor;
406  }
407
408  /**
409   * Add a Throwable to a list that will NOT cause a rollback. You are able to
410   * call this method multiple times with different throwable's and they will
411   * added to a list.
412   */
413  public TxScope setNoRollbackFor(Class<? extends Throwable> noRollback) {
414    if (noRollbackFor == null) {
415      noRollbackFor = new ArrayList<>(2);
416    }
417    this.noRollbackFor.add(noRollback);
418    return this;
419  }
420
421  /**
422   * Set multiple throwable's that will NOT cause a rollback.
423   */
424  @SuppressWarnings("unchecked")
425  public TxScope setNoRollbackFor(Class<?>[] noRollbacks) {
426    if (noRollbackFor == null) {
427      noRollbackFor = new ArrayList<>(noRollbacks.length);
428    }
429    for (Class<?> noRollback : noRollbacks) {
430      noRollbackFor.add((Class<? extends Throwable>) noRollback);
431    }
432    return this;
433  }
434
435  public boolean isBatchMode() {
436    return PersistBatch.ALL.equals(batch);
437  }
438
439  public boolean isBatchOnCascade() {
440    return PersistBatch.ALL.equals(batchOnCascade);
441  }
442}