001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.dbcp2.managed; 018 019import java.sql.Connection; 020import java.sql.SQLException; 021import java.time.Duration; 022 023import javax.management.ObjectName; 024 025import org.apache.commons.dbcp2.Constants; 026import org.apache.commons.dbcp2.DelegatingPreparedStatement; 027import org.apache.commons.dbcp2.PStmtKey; 028import org.apache.commons.dbcp2.PoolableConnection; 029import org.apache.commons.dbcp2.PoolableConnectionFactory; 030import org.apache.commons.dbcp2.PoolingConnection; 031import org.apache.commons.pool2.KeyedObjectPool; 032import org.apache.commons.pool2.PooledObject; 033import org.apache.commons.pool2.impl.DefaultPooledObject; 034import org.apache.commons.pool2.impl.GenericKeyedObjectPool; 035import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; 036 037/** 038 * A {@link PoolableConnectionFactory} that creates {@link PoolableManagedConnection}s. 039 * 040 * @since 2.0 041 */ 042public class PoolableManagedConnectionFactory extends PoolableConnectionFactory { 043 044 /** Transaction registry associated with connections created by this factory */ 045 private final TransactionRegistry transactionRegistry; 046 047 /** 048 * Creates a PoolableManagedConnectionFactory and attach it to a connection pool. 049 * 050 * @param connFactory 051 * XAConnectionFactory 052 * @param dataSourceJmxName 053 * The data source name. 054 */ 055 public PoolableManagedConnectionFactory(final XAConnectionFactory connFactory, final ObjectName dataSourceJmxName) { 056 super(connFactory, dataSourceJmxName); 057 this.transactionRegistry = connFactory.getTransactionRegistry(); 058 } 059 060 /** 061 * Gets the transaction registry. 062 * 063 * @return The transaction registry. 064 * @since 2.6.0 065 */ 066 public TransactionRegistry getTransactionRegistry() { 067 return transactionRegistry; 068 } 069 070 /** 071 * Uses the configured XAConnectionFactory to create a {@link PoolableManagedConnection}. Throws 072 * {@code IllegalStateException} if the connection factory returns null. Also initializes the connection using 073 * configured initialization SQL (if provided) and sets up a prepared statement pool associated with the 074 * PoolableManagedConnection if statement pooling is enabled. 075 */ 076 @SuppressWarnings("resource") // Connection is released elsewhere. 077 @Override 078 public synchronized PooledObject<PoolableConnection> makeObject() throws SQLException { 079 Connection conn = getConnectionFactory().createConnection(); 080 if (conn == null) { 081 throw new IllegalStateException("Connection factory returned null from createConnection"); 082 } 083 initializeConnection(conn); 084 if (getPoolStatements()) { 085 conn = new PoolingConnection(conn); 086 final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> config = new GenericKeyedObjectPoolConfig<>(); 087 config.setMaxTotalPerKey(-1); 088 config.setBlockWhenExhausted(false); 089 config.setMaxWait(Duration.ZERO); 090 config.setMaxIdlePerKey(1); 091 config.setMaxTotal(getMaxOpenPreparedStatements()); 092 final ObjectName dataSourceJmxName = getDataSourceJmxName(); 093 final long connIndex = getConnectionIndex().getAndIncrement(); 094 if (dataSourceJmxName != null) { 095 final StringBuilder base = new StringBuilder(dataSourceJmxName.toString()); 096 base.append(Constants.JMX_CONNECTION_BASE_EXT); 097 base.append(connIndex); 098 config.setJmxNameBase(base.toString()); 099 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}