how to cast dbcp connection to oracle connection? - java

I need cast PoolableConnection to OracleConnection in runtime but I don't know how to do it.
becasuse i got classCastException and if all classes extends Connection, can I do it ?

You should just be able to cast to the DBCP specific Connection class and from there retrieve the inner Oracle connection:
import org.apache.commons.dbcp.DelegatingConnection;
DelegatingConnection dc = (DelegatingConnection)conn;
OracleConnection oc = (OracleConnection)pc.getInnermostDelegate();
If you are using Tomcat's built-in copy of DBCP then the import you will need is:
import org.apache.tomcat.dbcp.dbcp.DelegatingConnection;
Or you can use the connection pooling built into the Oracle JDBC driver implementation. This returns an Oracle connection. A simple setup would be:
<Resource auth="Container"
connectionCacheName="CXCACHE"
connectionCacheProperties="{MaxStatementsLimit=5,MinLimit=1, MaxLimit=1, ValidateConnection=true}"
connectionCachingEnabled="true"
description="Oracle Datasource"
factory="oracle.jdbc.pool.OracleDataSourceFactory"
name="jdbc/TestDB"
user="default_user"
password="password"
type="oracle.jdbc.pool.OracleDataSource"
url="jdbc:oracle:thin:#//localhost:1521/orcl"
/>

You can cast only if the object you're casting actually is an instance of the class you're casting it to. If you're getting a ClassCastException that's not the case.
All classes that extend Connection can be cast to a Connection, but not necessarily to each other.

Related

How does JDBC DataSource works?

I wondered how works method getConnection() at DataSource? I assume that DataSource calling DriverManager.getConnection every time when we call DataSource.getConnection with our properties that we setting in DataSource. Is that true?
The answers to your question can be deduced from the DataSource javadoc.
"The DataSource interface is implemented by a driver vendor. There are three types of implementations:
Basic implementation -- produces a standard Connection object
Connection pooling implementation -- produces a Connection object that will automatically participate in connection pooling. This
implementation works with a middle-tier connection pooling manager.
Distributed transaction implementation -- produces a Connection object that may be used for distributed transactions and almost always
participates in connection pooling. This implementation works with a
middle-tier transaction manager and almost always with a connection
pooling manager."
Thus:
I wondered how works method getConnection() at DataSource?
It is vendor specific, and depends on the type of implementation that the vendor provides.
I assume that DataSource calling DriverManager.getConnection every time when we call DataSource.getConnection with our properties that we setting in DataSource. Is that true?
Not necessarily. For example, DataSource.getConnection() could return the same Connection object each time it is called. Or more plausibly, it could return a new Connection proxy for an underlying database pool connection that has been recycled. Furthermore, that DriverManager method is not necessarily called to get the connection.
If you want to know how a specific DataSource works, you would need to look at the vendor documentation ... or alternatively its source code.

I get the `DSRA9122E: com.ibm.ws.rsadapter.jdbc.WSJdbcConnection#d3t7e556 does not wrap any objects of type oracle.jdbc.OracleConnection

Am using Websphere 18 Liberty Version. When am trying to unwrap java.sql.connection to oracle.jdbc.OracleConnection I get the
`DSRA9122E: com.ibm.ws.rsadapter.jdbc.WSJdbcConnection#d3t7e556 does
not wrap any objects of type oracle.jdbc.OracleConnection
In sever.xml file am using ojdbc7.jar for datasource, also in application I added same jar from the same location. Still am facing the issue. I referred all links
WSJDBCConnection does not wrap objects of type oracle.jdbc.OracleConnection like this. Still am facing the same issue.
In order for Connection.unwrap to work properly, the Liberty DataSource and the Application must both load the vendor implementation class (oracle.jdbc.OracleConnection) from the same class loader.
Here is a simple example of how to configure both the dataSource and your application to use the same class loader to load from a single library that contains the Oracle JDBC driver,
<library id="OracleLib">
<fileset dir="${server.config.dir}/oracle"/>
</library>
<application location="myApp.war" >
<classloader commonLibraryRef="OracleLib"/>
</application>
<dataSource jndiName="jdbc/oracleDataSource">
<jdbcDriver libraryRef="OracleLib"/>
<properties.oracle .../>
</dataSource>
You don't need to unwrap to OracleConnection. You can use Connection object to establish the connection to the DB.
// Get a context for the JNDI look up
DataSource ds = getDataSource();
try (Connection connection = ds.getConnection()) {
{
executeBusinessLogicOnDatabase(connection));
......
}
connection.close();
}

Pattern for JDNI datasource

I'm using a JNDI ressource in Tomcat8 for connecting to a MS-SQL database (Azure). Randomly I experience Connection closed exception, eventually preceeded by Connection peer reset events. When this happens, the service is dead (running into Connection closed for every request) and restarting the tomcat (redploying) is the only chance to get it up again.
On my way trying to solve this I double(triple)-checked every method for unclosed connections, I assure that every connection is opened as try-with-ressource.
Currently I'm trying to get a better understanding about JNDI ressources and the connection pooling, I'm asking what is the preferred pattern to implement a service class which is injected into other services. E.g. questions are
Where should the DataSource be allocated by calling ctx.lookup()? On method level or class scope? E.g. when using the hk2 #Service annotation it seems that a service is instantiated only once and not per request. Currently ctx.lookup() is invoced once (in the constructor) and the DataSource is stored in a class field and later on accessed by the methods using this.dataSource. Does this make sense ? Or should the DataSource be retrieved on every request (=method call)
How can I verify the execution of several options of the DataSource, e.g. testOnBorrow and removeAbandoned (see complete configuration below) are executed correctly? There is an option logAbandoned but I can not see anything in my logs. Where should this appear anyhow? Can I somehow specifiy a certain log level for the pool? I only found org.apache.tomcat.jdbc.pool, but this class seems only to be called when creating the pool (at least this is the only moment when logs appear, even on level FINEST).
Are there general patterns which I'm not aware of?
Here my current configuration:
<Resource name="jdbc/mssql"
auth="Container"
type="javax.sql.XADataSource"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
username="***"
password="***"
url="jdbc:sqlserver://***.database.windows.net:1433;database=***;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
removeAbandonedOnBorrow="true"
removeAbandonedTimeout="55"
removeAbandonedOnMaintenance="true"
timeBetweenEvictionRunsMillis="34000"
minEvictableIdleTimeMillis="55000"
logAbandoned="true"
validationQuery="SELECT 1"
validationInterval="34000"
/>
Thx, gapvision
Gapvision, you can check this link - What is the good design pattern for connection pooling?
Probably, you would want to go with the object pool pattern.
Hope this helps !!
I'm asking what is the preferred pattern to implement a service class which is injected into other services.
Try spring data. It is very helpful in organizing resources to access data.
Without spring, without tomcat built-in features, you indeed need create your own singletons to allocate DataSource or ConnectionPool.
Without spring(assuming you build web app for tomcat), you can add to web.xml:
<resource-ref>
<description>H2DB</description>
<res-ref-name>jdbc/project1</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
And in context.xml of tomcat:
<Resource name="jdbc/project1" auth="Container" type="javax.sql.DataSource" driverClassName="org.h2.Driver" url="jdbc:h2:tcp://localhost/~/project1" username="sa" password="" maxActive="20" maxIdle="10" maxWait="-1"/>
And then you can lookup data source in each request:
Context ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/project1");
Connection conn = null;
try {
conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("INSERT INTO USERS (NAME) VALUES (?)");
ps.setString(1,name);
ps.executeUpdate();
response.getWriter().write("added user "+name);
response.getWriter().write("\n");
} finally {
if (conn!=null) { conn.close(); }
}
Or you can create a singleton class and lookup DataSource once , on start or lazy, as singletons do.
But better try spring data.

Does Cassandra JDBC provide a DataSource?

I have a large amount of legacy code that relies on being able to pass around a DataSource instead of a Connection object. I can see sample code for making a connection, ie:
Class.forName("org.apache.cassandra.cql.jdbc.CassandraDriver");
con = DriverManager.getConnection("jdbc:cassandra:root/root#localhost:9160/MyKeyspace");
However I can't see from the documentation any way to create a DataSource. Am I going to have to write my own DataSource to wrap the above code?
You can use BasicDataSource class of Apache Commons DBCP http://commons.apache.org/proper/commons-dbcp/ which is a DataSource implementation that can work with any JDBC driver. See usage example here http://www.kodejava.org/how-do-i-create-a-basicdatasource-object/
You can use the CassandraDataSource class.
https://code.google.com/a/apache-extras.org/p/cassandra-jdbc/source/browse/src/main/java/org/apache/cassandra/cql/jdbc/CassandraDataSource.java

Using special JDBC driver features with dynamic proxy connection pools

We are evaluating a JTA transaction manager for a legacy Oracle JDBC project and have looked at Bitronix and Atomikos so far.
The java.sql.DataSource implementations of both the Bitronix and Atomikos connection pools are making heavy use of dynamic proxy objects for the JDBC interface instances they return.
The PreparedStatements of the Bitronix PoolingDataSource connections are themselfs dynamic proxy objects, casting them to oracle.jdbc.OraclePreparedStatement results in a ClassCastException.
The Atomikos dynamic connection proxy objects on the other hand return actual OraclePreparedStatement instances - casting possible.
The legacy code uses Oracle JDBC update batching and hence casts java.sql.PreparedStatements to oracle.jdbc.OraclePreparedStatement for calling OraclePreparedStatement.setExecuteBatch(batchSize).
Switching to standard JDBC batching is not an option.
How are we supposed to use special JDBC driver features that require access to the actual driver classes/interfaces in the given situation?
If the connection pools support the java.sql.Wrapper interface properly, you can get access to the wrapped object using the unwrap method.
Thanks, that indeed worked for both Bitronix 2.1.2 and Atomikos 3.7.0 - assuming the JDK6 Oracle driver of cause.
I had tested unwrap(oracle.jdbc.OraclePreparedStatement.class) before, since oracle.jdbc.OraclePreparedStatement is the interface for the driver's PreparedStatement classes. I got a "bitronix.tm.resource.jdbc.JdbcUncachedPreparedStatementHandle is not a wrapper for interface oracle.jdbc.driver.OraclePreparedStatement" SQLException though.
Looking at the source of the Bitronix proxy class (JdbcUncachedPreparedStatementHandle) I found:
public Object unwrap(Class iface) throws SQLException {
if (PreparedStatement.class.equals(iface)) {
return delegate;
}
throw new SQLException(getClass().getName() + " is not a wrapper for interface " + iface.getName());
}
Wouldn't that rather have to be
public Object unwrap(Class iface) throws SQLException {
if (iface.isAssignableFrom(delegate.getClass()) {
return delegate;
}
throw new SQLException(getClass().getName() + " is not a wrapper for interface " + iface.getName());
}
?
Anyway - when I use this code it works for both Bitronix and Atomikos - Atomikos not being an issue anyway since the returned PreparedStatement is not a proxy object as mentioned above.
((OraclePreparedStatement)pstmt.unwrap(PreparedStatement.class)).setExecuteBatch(100);

Categories