View Javadoc
1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one or more
4    * contributor license agreements.  See the NOTICE file distributed with
5    * this work for additional information regarding copyright ownership.
6    * The ASF licenses this file to You under the Apache License, Version 2.0
7    * (the "License"); you may not use this file except in compliance with
8    * the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  package org.apache.commons.dbcp2.managed;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  
22  import java.sql.Connection;
23  import java.sql.SQLException;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.Properties;
27  
28  import javax.transaction.TransactionManager;
29  import javax.transaction.xa.XAException;
30  
31  import org.apache.commons.dbcp2.ConnectionFactory;
32  import org.apache.commons.dbcp2.Constants;
33  import org.apache.commons.dbcp2.DriverConnectionFactory;
34  import org.apache.commons.dbcp2.PoolableConnection;
35  import org.apache.commons.dbcp2.PoolableConnectionFactory;
36  import org.apache.commons.dbcp2.PoolingDataSource;
37  import org.apache.commons.dbcp2.TesterDriver;
38  import org.apache.commons.pool2.SwallowedExceptionListener;
39  import org.apache.commons.pool2.impl.GenericObjectPool;
40  import org.apache.geronimo.transaction.manager.TransactionManagerImpl;
41  import org.junit.jupiter.api.AfterEach;
42  import org.junit.jupiter.api.BeforeEach;
43  import org.junit.jupiter.api.Test;
44  
45  /**
46   * Test for ManagedConnection cached state.
47   */
48  public class TestManagedConnectionCachedState {
49  
50      private static final class SwallowedExceptionRecorder implements SwallowedExceptionListener {
51  
52          private final List<Exception> exceptions = new ArrayList<>();
53  
54          public List<Exception> getExceptions() {
55              return exceptions;
56          }
57  
58          @Override
59          public void onSwallowException(final Exception e) {
60              exceptions.add(e);
61          }
62      }
63  
64      private PoolingDataSource<PoolableConnection> ds;
65  
66      private GenericObjectPool<PoolableConnection> pool;
67  
68      private TransactionManager transactionManager;
69  
70      private SwallowedExceptionRecorder swallowedExceptionRecorder;
71  
72      public Connection getConnection() throws SQLException {
73          return ds.getConnection();
74      }
75  
76      @BeforeEach
77      public void setUp() throws XAException {
78          // create a GeronimoTransactionManager for testing
79          transactionManager = new TransactionManagerImpl();
80  
81          // create a driver connection factory
82          final Properties properties = new Properties();
83          properties.setProperty(Constants.KEY_USER, "userName");
84          properties.setProperty(Constants.KEY_PASSWORD, "password");
85          final ConnectionFactory connectionFactory = new DriverConnectionFactory(new TesterDriver(), "jdbc:apache:commons:testdriver", properties);
86  
87          // wrap it with a LocalXAConnectionFactory
88          final XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(transactionManager, connectionFactory);
89  
90          // create the pool object factory
91          // make sure we ask for state caching
92          final PoolableConnectionFactory factory = new PoolableConnectionFactory(xaConnectionFactory, null);
93          factory.setValidationQuery("SELECT DUMMY FROM DUAL");
94          factory.setCacheState(true);
95  
96          // create the pool
97          pool = new GenericObjectPool<>(factory);
98          factory.setPool(pool);
99          // record swallowed exceptions
100         swallowedExceptionRecorder = new SwallowedExceptionRecorder();
101         pool.setSwallowedExceptionListener(swallowedExceptionRecorder);
102 
103         // finally create the datasource
104         ds = new ManagedDataSource<>(pool, xaConnectionFactory.getTransactionRegistry());
105         ds.setAccessToUnderlyingConnectionAllowed(true);
106     }
107 
108     @AfterEach
109     public void tearDown() {
110         pool.close();
111     }
112 
113     @Test
114     public void testConnectionCachedState() throws Exception {
115         // see DBCP-568
116 
117         // begin a transaction
118         transactionManager.begin();
119         // acquire a connection enlisted in the transaction
120         try (final Connection conn = getConnection()) {
121             // check the autocommit status to trigger internal caching
122             conn.getAutoCommit();
123             // ask the transaction manager to rollback
124             transactionManager.rollback();
125         }
126         // check that no exceptions about failed rollback during close were logged
127         assertEquals(0, swallowedExceptionRecorder.getExceptions().size());
128     }
129 
130 }