View Javadoc
1   package com.atlassian.sal.spring.connection;
2   
3   import io.atlassian.fugue.Option;
4   import com.atlassian.sal.api.rdbms.ConnectionCallback;
5   import com.atlassian.sal.spi.HostConnectionAccessor;
6   import org.springframework.transaction.PlatformTransactionManager;
7   import org.springframework.transaction.TransactionDefinition;
8   import org.springframework.transaction.support.DefaultTransactionDefinition;
9   import org.springframework.transaction.support.TransactionCallback;
10  import org.springframework.transaction.support.TransactionTemplate;
11  
12  import javax.annotation.Nonnull;
13  import java.sql.Connection;
14  
15  /**
16   * Default implementation for spring environments.
17   * <p>
18   * Host should instantiate and export this.
19   * <p>
20   * Host must implement ConnectionProvider.
21   *
22   * @since 3.0
23   */
24  public class SpringHostConnectionAccessor implements HostConnectionAccessor {
25  
26      private final ConnectionProvider connectionProvider;
27  
28      private final PlatformTransactionManager transactionManager;
29  
30      public SpringHostConnectionAccessor(@Nonnull final ConnectionProvider connectionProvider, @Nonnull final PlatformTransactionManager transactionManager) {
31          this.connectionProvider = connectionProvider;
32          this.transactionManager = transactionManager;
33      }
34  
35      @Override
36      public <A> A execute(final boolean readOnly, final boolean newTransaction, @Nonnull final ConnectionCallback<A> callback) {
37          // create a transaction with the properties requested
38          final DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
39          transactionDefinition.setName("SALSpringTx");
40          transactionDefinition.setReadOnly(readOnly);
41          transactionDefinition.setPropagationBehavior(newTransaction
42                  ? TransactionDefinition.PROPAGATION_REQUIRES_NEW : TransactionDefinition.PROPAGATION_REQUIRED);
43  
44          // transaction template
45          final TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager, transactionDefinition);
46  
47          // execute the callback within the transaction
48          //noinspection unchecked
49          return (A) transactionTemplate.execute((TransactionCallback) status -> {
50  
51              // retrieve the connection
52              final Connection connection = connectionProvider.getConnection();
53  
54              // execute the user's callback
55              return callback.execute(connection);
56          });
57      }
58  
59      @Nonnull
60      @Override
61      public Option<String> getSchemaName() {
62          return connectionProvider.getSchemaName();
63      }
64  
65      /**
66       * Host specific implementation.
67       */
68      public interface ConnectionProvider {
69          /**
70           * Supply a connection to be used within
71           * {@link org.springframework.transaction.support.TransactionTemplate#execute(org.springframework.transaction.support.TransactionCallback)}
72           * <p>
73           * Note that this should be a "regular" connection, not a {@code com.atlassian.sal.core.rdbms.WrappedConnection}.
74           * <p>
75           * Example implementations might be:
76           * <code>return dataSource.getConnection();</code>
77           * or
78           * <code>return sessionFactory.getSession().connection();</code>
79           */
80          @Nonnull
81          Connection getConnection();
82  
83          /**
84           * Returns the configured schema name (if any), for connections provided by {@link #getConnection()}.
85           * <p>
86           * The host must ensure that the provided connection has <code>autoCommit=false</code>.
87           *
88           * @return schema name, if there is one
89           */
90          @Nonnull
91          Option<String> getSchemaName();
92      }
93  }