View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.dbcp2.managed;
18  
19  import java.sql.Connection;
20  import java.sql.SQLException;
21  import java.time.Duration;
22  
23  import javax.management.ObjectName;
24  
25  import org.apache.commons.dbcp2.Constants;
26  import org.apache.commons.dbcp2.DelegatingPreparedStatement;
27  import org.apache.commons.dbcp2.PStmtKey;
28  import org.apache.commons.dbcp2.PoolableConnection;
29  import org.apache.commons.dbcp2.PoolableConnectionFactory;
30  import org.apache.commons.dbcp2.PoolingConnection;
31  import org.apache.commons.pool2.KeyedObjectPool;
32  import org.apache.commons.pool2.PooledObject;
33  import org.apache.commons.pool2.impl.DefaultPooledObject;
34  import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
35  import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
36  
37  /**
38   * A {@link PoolableConnectionFactory} that creates {@link PoolableManagedConnection}s.
39   *
40   * @since 2.0
41   */
42  public class PoolableManagedConnectionFactory extends PoolableConnectionFactory {
43  
44      /** Transaction registry associated with connections created by this factory */
45      private final TransactionRegistry transactionRegistry;
46  
47      /**
48       * Creates a PoolableManagedConnectionFactory and attach it to a connection pool.
49       *
50       * @param connFactory
51       *            XAConnectionFactory
52       * @param dataSourceJmxName
53       *            The data source name.
54       */
55      public PoolableManagedConnectionFactory(final XAConnectionFactory connFactory, final ObjectName dataSourceJmxName) {
56          super(connFactory, dataSourceJmxName);
57          this.transactionRegistry = connFactory.getTransactionRegistry();
58      }
59  
60      /**
61       * @return The transaction registry.
62       * @since 2.6.0
63       */
64      public TransactionRegistry getTransactionRegistry() {
65          return transactionRegistry;
66      }
67  
68      /**
69       * Uses the configured XAConnectionFactory to create a {@link PoolableManagedConnection}. Throws
70       * {@code IllegalStateException} if the connection factory returns null. Also initializes the connection using
71       * configured initialization SQL (if provided) and sets up a prepared statement pool associated with the
72       * PoolableManagedConnection if statement pooling is enabled.
73       */
74      @SuppressWarnings("resource") // Connection is released elsewhere.
75      @Override
76      public synchronized PooledObject<PoolableConnection> makeObject() throws SQLException {
77          Connection conn = getConnectionFactory().createConnection();
78          if (conn == null) {
79              throw new IllegalStateException("Connection factory returned null from createConnection");
80          }
81          initializeConnection(conn);
82          if (getPoolStatements()) {
83              conn = new PoolingConnection(conn);
84              final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> config = new GenericKeyedObjectPoolConfig<>();
85              config.setMaxTotalPerKey(-1);
86              config.setBlockWhenExhausted(false);
87              config.setMaxWait(Duration.ZERO);
88              config.setMaxIdlePerKey(1);
89              config.setMaxTotal(getMaxOpenPreparedStatements());
90              final ObjectName dataSourceJmxName = getDataSourceJmxName();
91              final long connIndex = getConnectionIndex().getAndIncrement();
92              if (dataSourceJmxName != null) {
93                  final StringBuilder base = new StringBuilder(dataSourceJmxName.toString());
94                  base.append(Constants.JMX_CONNECTION_BASE_EXT);
95                  base.append(connIndex);
96                  config.setJmxNameBase(base.toString());
97                  config.setJmxNamePrefix(Constants.JMX_STATEMENT_POOL_PREFIX);
98              } else {
99                  config.setJmxEnabled(false);
100             }
101             final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> stmtPool = new GenericKeyedObjectPool<>(
102                     (PoolingConnection) conn, config);
103             ((PoolingConnection) conn).setStatementPool(stmtPool);
104             ((PoolingConnection) conn).setCacheState(getCacheState());
105         }
106         final PoolableManagedConnection pmc = new PoolableManagedConnection(transactionRegistry, conn, getPool(),
107                 getDisconnectionSqlCodes(), isFastFailValidation());
108         pmc.setCacheState(getCacheState());
109         return new DefaultPooledObject<>(pmc);
110     }
111 }