View Javadoc
1   package com.atlassian.sal.core.rdbms;
2   
3   import io.atlassian.fugue.Option;
4   import com.atlassian.sal.api.rdbms.ConnectionCallback;
5   import com.atlassian.sal.api.rdbms.RdbmsException;
6   import com.atlassian.sal.api.rdbms.TransactionalExecutor;
7   import com.atlassian.sal.spi.HostConnectionAccessor;
8   import com.google.common.annotations.VisibleForTesting;
9   
10  import javax.annotation.Nonnull;
11  import java.sql.Connection;
12  import java.sql.SQLException;
13  
14  /**
15   * Default implementation that invokes {@link com.atlassian.sal.spi.HostConnectionAccessor}.
16   * <p>
17   * Created by {@link com.atlassian.sal.core.rdbms.DefaultTransactionalExecutorFactory}
18   *
19   * @since 3.0
20   */
21  public class DefaultTransactionalExecutor implements TransactionalExecutor {
22  
23      private final HostConnectionAccessor hostConnectionAccessor;
24  
25      @VisibleForTesting
26      boolean readOnly;
27  
28      @VisibleForTesting
29      boolean newTransaction;
30  
31      public DefaultTransactionalExecutor(@Nonnull final HostConnectionAccessor hostConnectionAccessor,
32                                          final boolean readOnly, final boolean newTransaction) {
33          this.hostConnectionAccessor = hostConnectionAccessor;
34          this.readOnly = readOnly;
35          this.newTransaction = newTransaction;
36      }
37  
38      @Override
39      public <A> A execute(@Nonnull final ConnectionCallback<A> callback) {
40          return hostConnectionAccessor.execute(
41                  readOnly,
42                  newTransaction,
43                  connection -> executeInternal(connection, callback));
44      }
45  
46      @Nonnull
47      @Override
48      public Option<String> getSchemaName() {
49          return hostConnectionAccessor.getSchemaName();
50      }
51  
52      @Override
53      @Nonnull
54      public TransactionalExecutor readOnly() {
55          readOnly = true;
56          return this;
57      }
58  
59      @Override
60      @Nonnull
61      public TransactionalExecutor readWrite() {
62          readOnly = false;
63          return this;
64      }
65  
66      @Override
67      @Nonnull
68      public TransactionalExecutor newTransaction() {
69          newTransaction = true;
70          return this;
71      }
72  
73      @Override
74      @Nonnull
75      public TransactionalExecutor existingTransaction() {
76          newTransaction = false;
77          return this;
78      }
79  
80      @VisibleForTesting
81      <A> A executeInternal(@Nonnull final Connection connection, @Nonnull final ConnectionCallback<A> callback) {
82          assertAutoCommitFalse(connection);
83  
84          // give the user the restricted connection
85          try (final WrappedConnection wrappedConnection = new WrappedConnection(connection)) {
86              // execute the user's callback
87              return callback.execute(wrappedConnection);
88          }
89      }
90  
91      private void assertAutoCommitFalse(final Connection connection) {
92          try {
93              if (connection.getAutoCommit()) {
94                  throw new IllegalStateException("com.atlassian.sal.spi.HostConnectionAccessor returned connection with autocommit set");
95              }
96          } catch (final SQLException e) {
97              throw new RdbmsException("unable to invoke java.sql.Connection#getAutoCommit", e);
98          }
99      }
100 }