当我扩展AbstractComboPooledDataSource时,为什么在尝试连接时会收到CannotAcquireResourceException? [英] Why do I get a CannotAcquireResourceException while trying to connect, when I extend AbstractComboPooledDataSource?

查看:213
本文介绍了当我扩展AbstractComboPooledDataSource时,为什么在尝试连接时会收到CannotAcquireResourceException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用Oracle 11数据库的Tomcat 8.5.15环境中,我想实现一个数据源,该数据源处理 context.xml 中的加密密码。例如,而不是:

In a Tomcat 8.5.15 environment using an Oracle 11 database, I want to implement a data source that handles encrypted passwords in the context.xml. For example, instead of having:

       <Resource 
                  auth="Container"
                  description="MyDataSource"
                  driverClass="oracle.jdbc.OracleDriver" 
                  maxPoolSize="100"  
                  minPoolSize="10"   
                  acquireIncrement="1"  
                  name="jdbc/MyDataSource"
                  user="me"  
                  password="mypassword"
                  factory="org.apache.naming.factory.BeanFactory"
                  type="com.mchange.v2.c3p0.ComboPooledDataSource"
                  jdbcUrl="jdbc:oracle:thin:@mydb:1521:dev12c"
                  />

我想要类似以下内容,其中只有密码类型已更改:

I'd like to have something like the following, where only the password and type have changed:

   <Resource 
              auth="Container"
              description="MyDataSource"
              driverClass="oracle.jdbc.OracleDriver" 
              maxPoolSize="100"  
              minPoolSize="10"   
              acquireIncrement="1"  
              name="jdbc/MyDataSource"
              user="me"  
              password="D364FEC1CBC1DAEB91A1D8997D4A2482B"
              factory="org.apache.naming.factory.BeanFactory"
              type="com.mycompany.EncryptedC3p0WrappingDataSource"
              jdbcUrl="jdbc:oracle:thin:@mydb:1521:dev12c"
              /> 

主要变化是我对 EncryptedC3p0WrappingDataSource 。 C3p0的ComboPooledDataSource是最终版本,因此我无法对其进行扩展。相反,我扩展了它的超类 AbstractComboPooledDataSource ,并实现了一些其他方法。此类包含 ComboPooledDataSource ,即 wrappedDataSource ,用于通过委派进行实际工作。

The main change is my implementation of the EncryptedC3p0WrappingDataSource. C3p0's ComboPooledDataSource is final, so I can't extend it. Instead, I extend it's superclass, AbstractComboPooledDataSource, and implement some additional methods. This class contains a ComboPooledDataSource, which is the wrappedDataSource, and is used for the actual work via delegation.

public class EncryptedC3p0WrappingDataSource
    extends AbstractComboPooledDataSource
        implements PooledDataSource, Serializable, Referenceable
{
    /** The actual C3P0 data source that will be used to connect to the database.     */
    private ComboPooledDataSource wrappedDataSource = new ComboPooledDataSource();
    // TODO Should this be retrieved from a pool?  How?

    /** The object that does the encryting/decrypting. */
    private Encryptor encryptor;

    /**Construct the data source, with the necessary Encryptor. */
    public EncryptedC3p0WrappingDataSource() {
        try {
            encryptor = new Encryptor();
        } catch (InvalidKeyException | NoSuchAlgorithmException
                | NoSuchPaddingException | UnsupportedEncodingException e) {
            log.fatal("Error instantiating decryption class.", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * Set the in-memory password of the wrapped data source to the decrypted password.
     * @param encryptedPassword the encrypted password, as read from a file.
     */
    public void setPassword(String encryptedPassword) {
        try {
            String decryptedPassword
                    = encryptor.decrypt(encryptedPassword, Encryptor.AES_ALGORITHM);
            log.info("***************** Successfully decrypted "
                    + encryptedPassword + " to " + decryptedPassword);
            wrappedDataSource.setPassword(decryptedPassword);
        } catch (Exception e) { e.printStackTrace(); }
    }

    public void setDriverClass(String driverClass) throws PropertyVetoException {
        wrappedDataSource.setDriverClass(driverClass);
    }

    public void setJdbcUrl(String jdbcUrl) {
        wrappedDataSource.setJdbcUrl(jdbcUrl);
    }

    public void setDescription(String description) {
        wrappedDataSource.setDescription(description);
    }

    public void setMaxPoolSize(int maxPoolSize) {
        wrappedDataSource.setMaxPoolSize(maxPoolSize);
    }

    public void setMinPoolSize(int minPoolSize) {
        wrappedDataSource.setMinPoolSize(minPoolSize);
    }

    public void setAcquireIncrement(int acquireIncrement) {
        wrappedDataSource.setAcquireIncrement(acquireIncrement);
    }

    public Connection getConnection() throws SQLException {
        return wrappedDataSource.getConnection();
    }

    public Connection getConnection(String name, String password) throws SQLException {
        return wrappedDataSource.getConnection(name, password);
    }
}

当我使用第一个配置在Tomcat下运行应用程序时( ComboPooledDataSource ),它运行良好。当我尝试第二种配置( EncryptedC3p0WrappingDataSource )时,出现以下异常:

When I run our application under Tomcat with the first configuration (ComboPooledDataSource), it runs fine. When I try the second configuration (EncryptedC3p0WrappingDataSource), I get the following exception:

2017-07-21 07:57:29,962 FATAL [XXX.DataSourceFactory] Connections could not be acquired from the underlying database!
java.sql.SQLException: Connections could not be acquired from the underlying database!
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:690)
    at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140)
    at com.mycompany.EncryptedC3p0WrappingDataSource.getConnection(EncryptedC3p0WrappingDataSource.java:116)
        ...
Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
    at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1463)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:639)
    at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:549)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:756)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:683)
    ... 69 more

我在调试器中对此进行了广泛的研究。加密和解密部分似乎正在正确执行。我的 EncryptedC3p0WrappingDataSource.getConnection()方法导致调用 ComboPooledDataSource.getConnection()方法(继承的 AbstractPoolBackedDataSource.getConnection()方法,为什么我会收到异常?

I have looked at this extensively in the debugger. The encryption and decryption part appears to be happening correctly. My EncryptedC3p0WrappingDataSource.getConnection() method results in a call to the ComboPooledDataSource.getConnection() method (the inherited AbstractPoolBackedDataSource.getConnection() method, so why am I getting the exception?

UPDATE:

如果我将get setPassword 方法修改为也使用 setOverrideDefaultPassword

If I modify my get setPassword method to also use setOverrideDefaultPassword:

    public void setPassword(String encryptedPassword) {
        try {
            String decryptedPassword
                    = encryptor.decrypt(encryptedPassword, Encryptor.AES_ALGORITHM);
            log.info("***************** Successfully decrypted "
                    + encryptedPassword + " to " + decryptedPassword);
            wrappedDataSource.setPassword(decryptedPassword);
            wrappedDataSource.setOverrideDefaultPassword(decryptedPassword);
        } catch (Exception e) { e.printStackTrace(); }
    }

我得到了一个不同的例外:

I get a different exception:

Caused by: java.sql.SQLException: com.mchange.v2.c3p0.impl.NewProxyConnection@7e30531e
[wrapping: oracle.jdbc.driver.T4CConnection@51dba714]
 is not a wrapper for or implementation of oracle.jdbc.OracleConnection
    at com.mchange.v2.c3p0.impl.NewProxyConnection.unwrap(NewProxyConnection.java:1744)
    at org.jaffa.security.JDBCSecurityPlugin.executeStoredProcedure(JDBCSecurityPlugin.java:117)
    ... 67 more

更新2:

我发布了一个密切相关,希望更简单的问题此处

I've posted a closely related, and hopefully simpler, question here.

推荐答案

该错误是由于类加载问题而导致的,该类加载问题是从多个jar(%CATALINA_HOME%\lib\ojd bc7-12.1.0.2.0.jar %CATALINA_HOME%\webapps\my-webapp-1.0.0\WEB-INF\lib\ojdbc7- 12.1.0.2.0.jar )。当我删除%CATALINA_HOME%\webapps\my-webapp-1.0.0\WEB-INF\lib\ojdbc7-12.1.0.2.0.jar ,我的问题就解决了。

The error was a result of a class loading problem, where the Oracle classes were being loaded from multiple jars (%CATALINA_HOME%\lib\ojdbc7-12.1.0.2.0.jar and %CATALINA_HOME%\webapps\my-webapp-1.0.0\WEB-INF\lib\ojdbc7-12.1.0.2.0.jar) by different class loaders. When I deleted %CATALINA_HOME%\webapps\my-webapp-1.0.0\WEB-INF\lib\ojdbc7-12.1.0.2.0.jar, my problem went away.

这些来源( 1 2 3 )对此进行讨论

These sources (1, 2, 3) discuss this in more detail.

这篇关于当我扩展AbstractComboPooledDataSource时,为什么在尝试连接时会收到CannotAcquireResourceException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆