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
16
17
18
19
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
85 try (final WrappedConnection wrappedConnection = new WrappedConnection(connection)) {
86
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 }