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       * Gets the transaction registry.
62       *
63       * @return The transaction registry.
64       * @since 2.6.0
65       */
66      public TransactionRegistry getTransactionRegistry() {
67          return transactionRegistry;
68      }
69  
70      /**
71       * Uses the configured XAConnectionFactory to create a {@link PoolableManagedConnection}. Throws
72       * {@code IllegalStateException} if the connection factory returns null. Also initializes the connection using
73       * configured initialization SQL (if provided) and sets up a prepared statement pool associated with the
74       * PoolableManagedConnection if statement pooling is enabled.
75       */
76      @SuppressWarnings("resource") // Connection is released elsewhere.
77      @Override
78      public synchronized PooledObject<PoolableConnection> makeObject() throws SQLException {
79          Connection conn = getConnectionFactory().createConnection();
80          if (conn == null) {
81              throw new IllegalStateException("Connection factory returned null from createConnection");
82          }
83          initializeConnection(conn);
84          if (getPoolStatements()) {
85              conn = new PoolingConnection(conn);
86              final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> config = new GenericKeyedObjectPoolConfig<>();
87              config.setMaxTotalPerKey(-1);
88              config.setBlockWhenExhausted(false);
89              config.setMaxWait(Duration.ZERO);
90              config.setMaxIdlePerKey(1);
91              config.setMaxTotal(getMaxOpenPreparedStatements());
92              final ObjectName dataSourceJmxName = getDataSourceJmxName();
93              final long connIndex = getConnectionIndex().getAndIncrement();
94              if (dataSourceJmxName != null) {
95                  final StringBuilder base = new StringBuilder(dataSourceJmxName.toString());
96                  base.append(Constants.JMX_CONNECTION_BASE_EXT);
97                  base.append(connIndex);
98                  config.setJmxNameBase(base.toString());
99                  config.setJmxNamePrefix(Constants.JMX_STATEMENT_POOL_PREFIX);
100             } else {
101                 config.setJmxEnabled(false);
102             }
103             final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> stmtPool = new GenericKeyedObjectPool<>(
104                     (PoolingConnection) conn, config);
105             ((PoolingConnection) conn).setStatementPool(stmtPool);
106             ((PoolingConnection) conn).setCacheState(getCacheState());
107         }
108         final PoolableManagedConnection pmc = new PoolableManagedConnection(transactionRegistry, conn, getPool(),
109                 getDisconnectionSqlCodes(), getDisconnectionIgnoreSqlCodes(), isFastFailValidation());
110         pmc.setCacheState(getCacheState());
111         return new DefaultPooledObject<>(pmc);
112     }
113 }