开发者

How to extend c3p0 ComboPooledDataSource

Ok I have a resource in Tomcat 5.5 in server.xml for database connection like开发者_如何转开发 this:

<Resource name="jdbc/MyApp" auth="Container" type="com.mchange.v2.c3p0.ComboPooledDataSource" driverClass="com.microsoft.sqlserver.jdbc.SQLServerDriver"  maxPoolSize="100"  minPoolSize="5"   
acquireIncrement="5"    
 user="username" 
password="password"
factory="org.apache.naming.factory.BeanFactory"  
jdbcUrl="jdbc:sqlserver://localhost:1433;databaseName=myDatabase;autoReconnect=true" />

Has anyone tried to extend the above ComboPooledDataSource? Problem is that database password is in clear text. Idea is to first encrypt the password and place the encrypted key in the server.xml. I have a decrypting utility so I can decrypt the key before trying to connect to database.

I found an example solution for my problem for org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory, but I'm not using this connection pool. I'm using C3P0. Anyone tried this before with C3P0?


Yes, you can't extend com.mchange.v2.c3p0.ComboPooledDataSource because it is public. Here is the workaround by which I have achieved this.

I have extended org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy and passed the com.mchange.v2.c3p0.ComboPooledDataSource datasource as a constructor argument.

Here is my hibernate.cfg.xml configuration of above datasource:

<bean id="dataSource" class="MyDataSource"> 
        <constructor-arg ref="c3p0DataSource" />
    </bean>

    <bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <property name="driverClass" value="${jdbc.driver.className}" />
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="user" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="acquireIncrement" value="${dataSource.acquireIncrement}" />
        <property name="acquireRetryAttempts" value="${dataSource.acquireRetryAttempts}" />
        <property name="acquireRetryDelay" value="${dataSource.acquireRetryDelay}" />
        <property name="autoCommitOnClose" value="${dataSource.autoCommitOnClose}" />
        <property name="breakAfterAcquireFailure" value="${dataSource.breakAfterAcquireFailure}" />
        <property name="checkoutTimeout" value="${dataSource.checkoutTimeout}" />
        <property name="debugUnreturnedConnectionStackTraces"
            value="${dataSource.debugUnreturnedConnectionStackTraces}" />
        <property name="forceIgnoreUnresolvedTransactions"
            value="${dataSource.forceIgnoreUnresolvedTransactions}" />
        <property name="idleConnectionTestPeriod" value="${dataSource.idleConnectionTestPeriod}" />
        <property name="initialPoolSize" value="${dataSource.initialPoolSize}" />
        <property name="maxAdministrativeTaskTime" value="${dataSource.maxAdministrativeTaskTime}" />
        <property name="maxConnectionAge" value="${dataSource.maxConnectionAge}" />
        <property name="maxIdleTime" value="${dataSource.maxIdleTime}" />
        <property name="maxIdleTimeExcessConnections" value="${dataSource.maxIdleTimeExcessConnections}" />
        <property name="maxPoolSize" value="${dataSource.maxPoolSize}" />
        <property name="maxStatements" value="${dataSource.maxStatements}" />
        <property name="maxStatementsPerConnection" value="${dataSource.maxStatementsPerConnection}" />
        <property name="minPoolSize" value="${dataSource.minPoolSize}" />
        <property name="numHelperThreads" value="${dataSource.numHelperThreads}" />
        <property name="propertyCycle" value="${dataSource.propertyCycle}" />
        <property name="testConnectionOnCheckin" value="${dataSource.testConnectionOnCheckin}" />
        <property name="testConnectionOnCheckout" value="${dataSource.testConnectionOnCheckout}" />
        <property name="unreturnedConnectionTimeout" value="${dataSource.unreturnedConnectionTimeout}" />
    </bean>

Mine jdbc.properties file:


jdbc.driver.className=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc.url=xxxxx
jdbc.username=xxx
jdbc.password=xxxxxxxxx #Encrytped password here
jdbc.hibernate.dialect=org.hibernate.dialect.SQLServerDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=update

dataSource.acquireIncrement=3
dataSource.acquireRetryAttempts=30
dataSource.acquireRetryDelay=60000
dataSource.autoCommitOnClose=false
dataSource.breakAfterAcquireFailure=false
dataSource.checkoutTimeout=0
dataSource.debugUnreturnedConnectionStackTraces=false
dataSource.forceIgnoreUnresolvedTransactions=false
dataSource.idleConnectionTestPeriod=0
dataSource.initialPoolSize=10
dataSource.maxAdministrativeTaskTime=0
dataSource.maxConnectionAge=0
dataSource.maxIdleTime=0
dataSource.maxIdleTimeExcessConnections=0
dataSource.maxPoolSize=10
dataSource.maxStatements=0
dataSource.maxStatementsPerConnection=0
dataSource.minPoolSize=10
dataSource.numHelperThreads=3
dataSource.propertyCycle=0
dataSource.testConnectionOnCheckin=false
dataSource.testConnectionOnCheckout=false
dataSource.unreturnedConnectionTimeout=0


Mine extended class where I decrypt the password before passing the datasource to transaction Proxy wrapper.

import javax.sql.DataSource;

import org.jasypt.util.text.BasicTextEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;

import com.csc.emms.common.EMMSConstraints;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class MyDataSource extends TransactionAwareDataSourceProxy
{
    private static char[] appName =
    {
            'B', 'I', 'N', 'G', 'O', 'D', 'I', 'N', 'G', 'O'
    };

    @Autowired
    // Inject your class by constructor
    MyDataSource(ComboPooledDataSource dataSource)
    {
        super.setTargetDataSource(decryptPassword(dataSource));
    }

    private DataSource decryptPassword(ComboPooledDataSource dataSource)
    {
        dataSource.setPassword(decode(dataSource.getPassword()));
        return dataSource;
    }

    private String decode(String encodedPassword)
    {
        BasicTextEncryptor decoder = new BasicTextEncryptor();
        decoder.setPasswordCharArray(appName);
        return decoder.decrypt(encodedPassword);
    }

    private String encode(String password)
    {
        BasicTextEncryptor encoder = new BasicTextEncryptor();
        encoder.setPasswordCharArray(appName);
        return encoder.encrypt(password);
    }
}
Hope this resolved your issue.


You can't extend ComboPooledDataSource, but you can basically duplicate it by extending its parent class, AbstractComboPooledDataSource. You can really, really get close to duplicating it by either getting the source from Github, or by decompiling the class file. The result will look something like this:

import com.mchange.v2.c3p0.AbstractComboPooledDataSource;

public final class YourC3p0DataSource extends AbstractComboPooledDataSource
        implements Serializable, Referenceable {

    public void setPassword(String encryptedPassword) {
        try {
            String decryptedPassword
                    = yourDecryption(encryptedPassword);
            super.setPassword(decryptedPassword);
        } catch (Exception e) { /* ... */ }
    }
    /* Increment a few other methods found in ComboPooledDataSource. */
}


you can using jasypt to encrypt properties file and then used encrypted properties in datasource bean.

jasypt also support spring and it is very easy to use. read this for more details.


Since com.mchange.v2.c3p0.ComboPooledDataSource is public final class, you can't extend it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜