View Javadoc

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