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  import static org.junit.jupiter.api.Assertions.assertNotNull;
22  import static org.junit.jupiter.api.Assertions.assertNull;
23  import static org.junit.jupiter.api.Assertions.assertThrows;
24  import static org.junit.jupiter.api.Assertions.fail;
25  
26  import java.sql.Connection;
27  import java.sql.SQLException;
28  
29  import javax.sql.XADataSource;
30  import javax.transaction.TransactionManager;
31  import javax.transaction.TransactionSynchronizationRegistry;
32  import javax.transaction.xa.XAException;
33  
34  import org.apache.commons.dbcp2.BasicDataSource;
35  import org.apache.commons.dbcp2.TestBasicDataSource;
36  import org.apache.geronimo.transaction.manager.TransactionManagerImpl;
37  import org.h2.Driver;
38  import org.h2.jdbcx.JdbcDataSource;
39  import org.junit.jupiter.api.Test;
40  
41  import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
42  import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple;
43  
44  /**
45   * TestSuite for BasicManagedDataSource
46   */
47  public class TestBasicManagedDataSource extends TestBasicDataSource {
48  
49      @Override
50      protected BasicDataSource createDataSource() throws Exception {
51          final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource();
52          final TransactionManagerImpl transactionManager = new TransactionManagerImpl();
53          basicManagedDataSource.setTransactionManager(transactionManager);
54          basicManagedDataSource.setTransactionSynchronizationRegistry(transactionManager);
55          return basicManagedDataSource;
56      }
57  
58      @Test
59      public void testCreateXaDataSourceNewInstance() throws SQLException, XAException {
60          try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) {
61              basicManagedDataSource.setXADataSource(JdbcDataSource.class.getCanonicalName());
62              basicManagedDataSource.setDriverClassName(Driver.class.getName());
63              basicManagedDataSource.setTransactionManager(new TransactionManagerImpl());
64              assertNotNull(basicManagedDataSource.createConnectionFactory());
65          }
66      }
67  
68      @Test
69      public void testCreateXaDataSourceNoInstanceSetAndNoDataSource() throws SQLException, XAException {
70          try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) {
71              basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver");
72              basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver");
73              basicManagedDataSource.setTransactionManager(new TransactionManagerImpl());
74              assertNotNull(basicManagedDataSource.createConnectionFactory());
75          }
76      }
77  
78      /**
79       * JIRA: DBCP-294
80       * Verify that PoolableConnections created by BasicManagedDataSource unregister themselves
81       * when reallyClosed.
82       */
83      @Test
84      public void testReallyClose() throws Exception {
85          try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) {
86              basicManagedDataSource.setTransactionManager(new TransactionManagerImpl());
87              basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver");
88              basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver");
89              basicManagedDataSource.setUsername("userName");
90              basicManagedDataSource.setPassword("password");
91              basicManagedDataSource.setMaxIdle(1);
92              // Create two connections
93              final ManagedConnection<?> conn = (ManagedConnection<?>) basicManagedDataSource.getConnection();
94              assertNotNull(basicManagedDataSource.getTransactionRegistry().getXAResource(conn));
95              final ManagedConnection<?> conn2 = (ManagedConnection<?>) basicManagedDataSource.getConnection();
96              conn2.close(); // Return one connection to the pool
97              conn.close(); // No room at the inn - this will trigger reallyClose(), which should unregister
98              assertThrows(SQLException.class, () -> basicManagedDataSource.getTransactionRegistry().getXAResource(conn),
99                      "Expecting SQLException - XAResources orphaned");
100             conn2.close();
101         }
102     }
103 
104     @Test
105     public void testRuntimeExceptionsAreRethrown() throws SQLException, XAException {
106         try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) {
107             basicManagedDataSource.setTransactionManager(new TransactionManagerImpl());
108             basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver");
109             basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver");
110             basicManagedDataSource.setUsername("userName");
111             basicManagedDataSource.setPassword("password");
112             basicManagedDataSource.setMaxIdle(1);
113             // results in a NPE
114             assertThrows(NullPointerException.class, () -> basicManagedDataSource.createPoolableConnectionFactory(null));
115         }
116     }
117 
118     @Test
119     public void testSetDriverName() throws SQLException {
120         try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) {
121             basicManagedDataSource.setDriverClassName("adams");
122             assertEquals("adams", basicManagedDataSource.getDriverClassName());
123             basicManagedDataSource.setDriverClassName(null);
124             assertNull(basicManagedDataSource.getDriverClassName());
125         }
126     }
127 
128     @Test
129     public void testSetNullXaDataSourceInstance() throws SQLException, XAException {
130         try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) {
131             basicManagedDataSource.setTransactionManager(new TransactionManagerImpl());
132             basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver");
133             basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver");
134             basicManagedDataSource.setUsername("userName");
135             basicManagedDataSource.setPassword("password");
136             basicManagedDataSource.setMaxIdle(1);
137             basicManagedDataSource.setXaDataSourceInstance(null);
138             assertNull(basicManagedDataSource.getXaDataSourceInstance());
139         }
140     }
141 
142     /** DBCP-564 */
143     @Test
144     public void testSetRollbackOnlyBeforeGetConnectionDoesNotLeak() throws Exception {
145         final TransactionManager transactionManager = ((BasicManagedDataSource) ds).getTransactionManager();
146         final int n = 3;
147         ds.setMaxIdle(n);
148         ds.setMaxTotal(n);
149 
150         for (int i = 0; i <= n; i++) { // loop n+1 times
151             transactionManager.begin();
152             transactionManager.setRollbackOnly();
153             try (final Connection conn = getConnection()) {
154                 assertNotNull(conn);
155             }
156             transactionManager.rollback();
157         }
158 
159         assertEquals(0, ds.getNumActive());
160         assertEquals(1, ds.getNumIdle());
161     }
162 
163     @Test
164     public void testSetXaDataSourceInstance() throws SQLException, XAException {
165         try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) {
166             basicManagedDataSource.setTransactionManager(new TransactionManagerImpl());
167             basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver");
168             basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver");
169             basicManagedDataSource.setUsername("userName");
170             basicManagedDataSource.setPassword("password");
171             basicManagedDataSource.setMaxIdle(1);
172             basicManagedDataSource.setXaDataSourceInstance(new JdbcDataSource());
173             assertNotNull(basicManagedDataSource.createConnectionFactory());
174         }
175     }
176 
177     @Test
178     public void testTransactionManagerNotSet() throws SQLException {
179         try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) {
180             assertThrows(SQLException.class, basicManagedDataSource::createConnectionFactory);
181         }
182     }
183 
184     @Test
185     public void testTransactionSynchronizationRegistry() throws Exception {
186         try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) {
187             basicManagedDataSource.setTransactionManager(new TransactionManagerImple());
188             final TransactionSynchronizationRegistry tsr = new TransactionSynchronizationRegistryImple();
189             basicManagedDataSource.setTransactionSynchronizationRegistry(tsr);
190             final JdbcDataSource xaDataSource = new JdbcDataSource();
191             xaDataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
192             basicManagedDataSource.setXaDataSourceInstance(xaDataSource);
193             basicManagedDataSource.setMaxIdle(1);
194 
195             final TransactionManager tm = basicManagedDataSource.getTransactionManager();
196             tm.begin();
197             tsr.registerInterposedSynchronization(new SynchronizationAdapter() {
198                 @Override
199                 public void beforeCompletion() {
200                     Connection connection = null;
201                     try {
202                         connection = basicManagedDataSource.getConnection();
203                         assertNotNull(connection);
204                     } catch (final SQLException e) {
205                         fail(e.getMessage());
206                     } finally {
207                         if (connection != null) {
208                             try {
209                                 connection.close();
210                             } catch (final SQLException e) {
211                                 fail(e.getMessage());
212                             }
213                         }
214                     }
215                 }
216             });
217             tm.commit();
218         }
219     }
220 
221     @Test
222     public void testXADataSource() throws SQLException {
223         try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) {
224             basicManagedDataSource.setXADataSource("anything");
225             assertEquals("anything", basicManagedDataSource.getXADataSource());
226         }
227     }
228 
229     @Test
230     public void testXaDataSourceInstance() throws SQLException {
231         try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) {
232             final XADataSource ds = new JdbcDataSource();
233             basicManagedDataSource.setXaDataSourceInstance(ds);
234             assertEquals(ds, basicManagedDataSource.getXaDataSourceInstance());
235         }
236     }
237 }