Why java.sql.Connection cannot be cast to oracle.jdbc.OracleConnection in code below?
My main goal is to pass to Oracle connection new user name and save it in 'SESSION' table in for example 'osuser' column because I want to trace in DB user changes and display it in the table.
#Repository
public class AuditLogDAOImpl implements AuditLogDAO {
#PersistenceContext(unitName="myUnitName")
EntityManager em;
#Resource(name = "dataSource")
DataSource dataSource;
public void init() {
try {
Connection connection = DataSourceUtils.getConnection(dataSource);
OracleConnection oracleConnection = (OracleConnection) connection; //Here I got cast exception!
String metrics[] = new String[OracleConnection.END_TO_END_STATE_INDEX_MAX];
metrics[OracleConnection.END_TO_END_CLIENTID_INDEX] = "my_new_username";
oracleConnection.setEndToEndMetrics(metrics, (short) 0);
java.util.Properties props = new java.util.Properties();
props.put("osuser", "newValue");
oracleConnection.setClientInfo(props);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Here is error log:
10:42:29,251 INFO [STDOUT] org.jboss.resource.adapter.jdbc.jdk6.WrappedConnectionJDK6#bcc8cb
10:42:51,701 ERROR [STDERR] java.lang.ClassCastException: $Proxy286 cannot be cast to oracle.jdbc.OracleConnection
Generally I have 2 problem in this case:
why cast from Connection to OracleConnection fails and
what is the best way to implement my intend (I mean set the new user name to v$session.osuser in Oracle DB?
I work with Oracle 11g, Hibernate (using entity manager), data source via jndi.
Please help, thanks!
EDIT:
After some improvement the problem with casting still exists.
Improvement:
Connection connection = DataSourceUtils.getConnection(dataSource);
connection = ((org.jboss.resource.adapter.jdbc.WrappedConnection)connection).getUnderlyingConnection();
OracleConnection oracleConnection = (OracleConnection) connection;
Error:
java.lang.ClassCastException: $Proxy287 cannot be cast to org.jboss.resource.adapter.jdbc.WrappedConnection
The connection you are retrieving is probably a wrapped connection.
If you really need to get the underlying Oracle connection you should use:
if (connection.isWrapperFor(OracleConnection.class)){
OracleConnection oracleConnection= connection.unwrap(OracleConnection.class);
}else{
// recover, not an oracle connection
}
The isWrapperFor and unwrap methods are available since Java 1.6, and should be meaningfully implemented by the A/S connection wrappers.
The connection pool usually has a wrapper around the real connection instance, that's why your cast fails.
What you are doing wouldn't work anyway, because the parameters in the properties instance are only checked when the connection is established. As you have a connection that is already active, it won't change anything.
You need tou use DBMS_APPLICATION_INFO.SET_CLIENT_INFO() in order to change this for an existing connection.
This is just for people who come here via search on how to set metrics in OracleConnection, I spend great deal of time on this, so might help someone.
After you get your "connection" this should work:
DatabaseMetaData dmd = connection.getMetaData();
Connection metaDataConnection = null;
if(dmd != null)
{
metaDataConnection = dmd.getConnection();
}
if(!(metaDataConnection instanceof OracleConnection))
{
log.error("Connection is not instance of OracleConnection, returning");
return; /* Not connection u want */
}
OracleConnection oraConnection = (OracleConnection)metaDataConnection;
String[] metrics = new String[END_TO_END_STATE_INDEX_MAX]; // Do the rest below...
It works for me for OracleConnection, but I face diff issue when setting metrics:
short zero = 0;
oraConnection.setEndToEndMetrics(metrics, zero);
After proxying connection via my method where I set metrics few times, I get:
java.sql.SQLRecoverableException: No more data to read from socket
But I think it has to do with some Spring wiring inits or connection pool.
i had faced this issue when using spring to get connections. Typically , each layer adds a wrapper over the basic classes. i had just done connection.getClass().getName() to see the runtime type of the connection being retuned. It will be a Wrapper/proxy over which you can easily find the method to get the base OracleConnection type.
Try the following
I had encountered the same issue. We were using spring and it has a class called
NativeJdbcExtractor. It has many implementations and the following one works for TomCat. There is a specific implementation for Jboss called the JBossNativeJdbcExtractor
<bean id="jdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"></bean>
In your DAO you can inject the bean and use the following method
protected NativeJdbcExtractor jdbcExtractor;
Connection conn=jdbcExtractor.getNativeConnection(oracleConnection);
You can access the inner OracleObject inside a Wrapper, in this case the wrapper
type is NewProxyConnection:
( I've used it in my project, it Worked ...no mistery, just use reflection)
Field[] fieldsConn= connection.getClass().getDeclaredFields();
Object innerConnObject = getFieldByName(fieldsConn,"inner").get(connection);
if(innerConnObject instanceof OracleConnection ){
OracleConnection oracleConn = (OracleConnection)innerConnObject;
//OracleConnection unwrap = ((OracleConnection)innerConnObject).unwrap();
// now you have the OracleObject that the Wrapper
}
//Method: Set properties of the ooject accessible.
public static Field getFieldByName(Field[] campos, String name) {
Field f = null;
for (Field campo : campos) {
campo.setAccessible(true);
if (campo.getName().equals(name)) {
f = campo;
break;
}
}
return f;
}
Not sure if my situation is related, but with my project, simply changing a database configuration setting actually causes unwrap to fail!
I'm using the Play framework with Scala; this works for me only when logSql=false:
db.withConnection { implicit c =>
val oracleConnection = c.unwrap(classOf[OracleConnection])
}
(this is just the Scala version of unwrapping an OracleConnection)
When I set logSql=true, I get:
com.sun.proxy.$Proxy17 cannot be cast to oracle.jdbc.OracleConnection
java.lang.ClassCastException: com.sun.proxy.$Proxy17 cannot be cast to
oracle.jdbc.OracleConnection
So something about the logSql configuration can actually cause unwrap to fail. No idea why.
With either configuration, my connection object is:
HikariProxyConnection#1880261898 wrapping
oracle.jdbc.driver.T4CConnection#6b28f065
isWrapperFor(OracleConnection) is true in both cases
This happens with Hikari Connection Pool and Bone CP. Maybe it's a bug in Oracle JDBC?
Oracle JDBC Driver version according to MANIFEST.MF
Implementation-Version: 11.2.0.3.0
Repository-Id: JAVAVM_11.2.0.4.0_LINUX.X64_130711
After trial and error.
This way works:
DelegatingConnection delConnection = new DelegatingConnection(dbcpConnection);
oraConnection = (oracle.jdbc.OracleConnection)delConnection.getInnermostDelegate();
But this way returned a null pointer for oraConnection:
DelegatingConnection delConnection = (DelegatingConnection) dbcpConnection;
oraConnection = (oracle.jdbc.OracleConnection)delConnection.getInnermostDelegate();
The following worked to get around AQ's TopicConnection.getTopicSession => JMS-112
//DEBUG: Native DataSource : weblogic.jdbc.common.internal.RmiDataSource
con = DataSource.getConnection();
debug("Generic SQL Connection: " + con.toString());
//DEBUG: Generic Connection: weblogic.jdbc.wrapper.PoolConnection_oracle_jdbc_driver_T4CConnection
if (con != null && con.isWrapperFor(OracleConnection.class)) {
WebLogicNativeJdbcExtractor wlne = new WebLogicNativeJdbcExtractor();//org.springframework to the rescue!!
java.sql.Connection nativeCon = wlne.getNativeConnection(con);
this.oraConnection = (OracleConnection) nativeCon;
debug("Unwrapp SQL Connection: " + this.oraConnection.toString());
}
//DEBUG: Native Connection: oracle.jdbc.driver.T4CConnection è
Now I could use this in the AQ-Factory w/o JMS-112
try casting like below
WrappedConnectionJDK6 wc = (WrappedConnectionJDK6) connection;
connection = wc.getUnderlyingConnection();
Related
While my issue sounds same to this one Snowflake JDBC driver internal error: Fail to retrieve row count for first arrow chunk: null -- only occurs on SELECT statements, but actually it is not.
I am able to connect to Snowflake data warehouse from java:
public static Connection getConnection()
throws SQLException
{
String user = Optional.ofNullable(System.getenv("USER"))
.or(() -> Optional.ofNullable(System.getenv("USERNAME")))
.orElseThrow();
try
{
Class.forName("net.snowflake.client.jdbc.SnowflakeDriver");
}
catch (ClassNotFoundException ex)
{
System.err.println("Driver not found");
}
// build connection properties
Properties properties = new Properties();
properties.put("authenticator", "xxx");
properties.put("user", user);
String connStr = Optional.ofNullable(System.getenv("SF_JDBC_CONNECT_STRING")).orElse("jdbc:snowflake://xxx.xxx.com");
return DriverManager.getConnection(connStr, properties);
}
but when I try to run a very simple select statement from below code:
try {
Connection conn = Helper.getConnection();
Statement sqlStm = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
ResultSet sqlOutput = sqlStm.executeQuery("select getdate();");
while (sqlOutput.next()) {
System.out.println(sqlOutput.getInt(1));
}
}
catch (SQLException e){
e.printStackTrace();
}
I am getting below error:
net.snowflake.client.jdbc.SnowflakeSQLLoggedException: JDBC driver internal error: Fail to retrieve row count for first arrow chunk: sun.misc.Unsafe or java.nio.DirectByteBuffer.<init>(long, int) not available.
at net.snowflake.client.jdbc.SnowflakeResultSetSerializableV1.setFirstChunkRowCountForArrow(SnowflakeResultSetSerializableV1.java:1066)
at net.snowflake.client.jdbc.SnowflakeResultSetSerializableV1.create(SnowflakeResultSetSerializableV1.java:550)
at net.snowflake.client.jdbc.SnowflakeResultSetSerializableV1.create(SnowflakeResultSetSerializableV1.java:467)
at net.snowflake.client.core.SFResultSetFactory.getResultSet(SFResultSetFactory.java:29)
at net.snowflake.client.core.SFStatement.executeQueryInternal(SFStatement.java:220)
at net.snowflake.client.core.SFStatement.executeQuery(SFStatement.java:135)
at net.snowflake.client.core.SFStatement.execute(SFStatement.java:781)
at net.snowflake.client.core.SFStatement.execute(SFStatement.java:677)
at net.snowflake.client.jdbc.SnowflakeStatementV1.executeQueryInternal(SnowflakeStatementV1.java:238)
at net.snowflake.client.jdbc.SnowflakeStatementV1.executeQuery(SnowflakeStatementV1.java:133)
at com.marqeta.Main.main(Main.java:42)
I found on github that people had the same issue on this thread: https://github.com/snowflakedb/snowflake-jdbc/issues/484. I had set the VM options as per below, but still have the same error, did I set the VM options wrongly or what could be the issues please.
I added --add-opens java.base/java.nio=ALL-UNNAMED as VM argument for the tests and they are passing.
Please refer to this comment. Also, there is a good explanation of why this is happening. Passing the VM argument should be considered as a temporary solution.
I am trying to read an Oracle stored procedure returning a ref_cursor using vertx3. The same procedure is working if I edit it to return clob and use JDBCType.CLOB but for some reason I have to use ref_cursor. Can someone please help me?
JDBCClient client = JDBCClient.createShared(vertx, new JsonObject()
.put("url", "jdbc:oracle:thin:#localhost:8787:TEST")
.put("driver_class", "oracle.jdbc.OracleDriver")
.put("user", "user")
.put("password", "****"));
client.getConnection( connection -> {
if (connection.succeeded()) {
SQLConnection con = connection.result();
JsonObject params = new JsonObject()
.put("query", "{ call ? := package.procedure(?) }")
.put("paramsIn", new JsonArray().addNull().add(89))
.put("paramsOut", new JsonArray().add(JDBCType.REF_CURSOR));
con.callWithParams(params.getString("query"), params.getJsonArray("paramsIn"), params.getJsonArray("paramsOut"), query -> {
if(query.succeeded()){
ResultSet rs = query.result();
System.out.println(rs.toJson().toString())
}else{
System.out.println(req.body() + query.cause().toString());
}
});
} else {
System.out.println(connection.cause().toString())
}
});
and I get the error :
{ call ? := package.procedure(?) } java.sql.SQLException: Type de
colonne non valide: 2012
As of Vert.x 3.4.1, cursors are not supported. As a workaround, you could create your own javax.sql.DataSource and use it with Vertx.executeBlocking to invoke a JDBC java.sql.CallableStatement.
For the rest of your queries you can still use Vert.x APIs by creating a JDBCClient instance from your javax.sql.DataSource. This will avoid to maintain two different connection pools.
Have you tried using oracle.jdbc.OracleTypes.CURSOR from com.oracle:ojdbc8:12.2.0.1 instead of JDBCType.REF_CURSOR?
Since ConnectionCaching ist deprecated in ojdbc now, i would like to use the Oracle Universal Connection Pool.
The Problem here is that i need to to obtain a oracle.jdbc.OracleConnection from it. I tried casting and unwrapping but i does not work. How do i get one?
I need the OracleConnection.createARRAY() Method to call a stored Procedure.
From the api docs, if you are getting an instance of UniversalPooledConnection the underlying connection can be obtained from getPhysicalConnection:
getPhysicalConnection
java.lang.Object getPhysicalConnection()
Gets the physical connection
that this UniversalPooledConnection decorates.
Returns: The physical
connection. Never null.
Thanks #6ton. I made it like this:
/* missing all error handling and resource management*/
universalConnectionPoolManager = UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager();
poolDataSource = PoolDataSourceFactory.getPoolDataSource();
// setting up dataSource ....
poolDataSource.setConnectionPoolName(NAME);
universalConnectionPoolManager.createConnectionPool((UniversalConnectionPoolAdapter) poolDataSource);
universalConnectionPoolManager.startConnectionPool(NAME);
universalConnectionPool = universalConnectionPoolManager.getConnectionPool(NAME);
universalPooledConnection = universalConnectionPool.borrowConnection(universalConnectionPool.getConnectionRetrievalInfo());
physicalConnection = universalPooledConnection.getPhysicalConnection();
oracleConn = (OracleConnection) physicalConnection;
// ... query stuff
universalPooledConnection.heartbeat();
universalConnectionPool.returnConnection(universalPooledConnection);
universalConnectionPoolManager.destroyConnectionPool(NAME);
You can get the OracleConnection by using the unwrap method as shown below.
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
pds.setURL("jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(HOST=localhost)(PORT=1521)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=myorcldbservice)))");
pds.setUser("hr");
pds.setPassword("hr");
pds.setConnectionPoolName("JDBC_UCP_POOL");
pds.setInitialPoolSize(5);
pds.setMinPoolSize(5);
pds.setMaxPoolSize(10);
try (Connection conn = pds.getConnection()) {
OracleConnection oc = conn.unwrap(OracleConnection.class);
} catch (SQLException e) {
System.out.println("UCPSample - SQLException occurred : " + e.getMessage());
}
please tell me if I have to provide more information/code, becasue I am a newbie in java and maybe don't know which informations you need.
I have to add a functionality to an existing Eclipse RCP application. In this I need to register an OracleDatabaseChangeListenet to my database connection.
The problem is, the connection already exists and is of the self-designed class Connection (is designed the way, that connections to other databases except Oracle are possible) that implements self-designed interface IConnection, but basically this connection is to an Oracle 11g database.
So I need to cast this connection to OracleConnection, but get an CastExceptionError. How can I manage to cast the connection?
public void openConnection( IConnection connection) throws JeffException {
URI conURI = connection.getUri();
String con_System = conURI.getPath().split( "/")[1]; //$NON-NLS-1$
String jdbcUrl = "jdbc:oracle:thin:#//" + conURI.getHost() + ":" + conURI.getPort() + "/" + con_System; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
String Jeff_user = connection.getProperty( DatabaseConstants.JEFF_USERNAME);
String Jeff_password = connection.getProperty( DatabaseConstants.JEFF_PASSWORD);
//derby-embedded
// jdbcUrl="jdbc:derby:embeddedDB1;create=true";
String Jeff_proxy_password = connection.getProperty( DatabaseConstants.JEFF_PROXY_PASSWORD);
String Jeff_proxy_username = connection.getProperty( DatabaseConstants.JEFF_PROXY_USERNAME);
OracleConnection conn=(OracleConnection) connection;
The error I get is
java.lang.ClassCastException: mapackage.projectmanager.model.Connection cannot be cast to oracle.jdbc.OracleConnection
Thanks,
Jeff
I am facing an issue with using Mongo DB on a Java servlet.
My servlet has many methods(~20) of accessing the database for retrieving and adding data. A very brief example of one :
public static String getSomething(String s) {
String json = "[]";
JSONArray jsonArray = new JSONArray();
DBCollection table;
try {
Mongo mongo = new Mongo("localhost", 27017);
DB db = mongo.getDB( "myDb" );
BasicDBObject quoteQuery = new BasicDBObject("abc", abc);
DBCursor cursor = table.find(quoteQuery);
try {
while(cursor.hasNext()) {
jsonArray.put(cursor.next());
}
} finally {
cursor.close();
}
// ...
Now the problem is when this Java servlet is deployed in the linux server, it works fine for 10 days or so.
After that it crashes.
When I go to mongodb.log in my var/log directory I get the following repetitive output:
"connection refused because too many open connections"
I am not sure on where to edit things now or how to deal with this. I have tried to grow the limit of open connections in the server but still have the same results.
Any suggestions?
from the API doc : http://api.mongodb.org/java/2.11.3/
public class Mongo extends Object
A database connection with internal connection pooling. For most applications, you should have one Mongo instance for the entire JVM.
You should create Mongo objects very sparingly, ideally even only one per classloader at any time. To reduce the number of Mongo objects you could create it in the servlet's init method and re-use that instance on every call.
EDIT: just had a look at our code, we manage the Mongo instance using a classic singleton class (and always fetch a Mongo using that class's getInstance() method) because if you have multiple servlets / entrypoints in your app just using init() will still generate one instance per servlet, and still won't satisfy the manual section cited by #FredClose
You may create the mongo object for once instead of creating it on each getSomething call.
public SomeClass{
static Mongo mongo = new Mongo("localhost", 27017);
static DB db = mongo.getDB( "myDb" );
public static String getSomething(String s) {
String json = "[]";
JSONArray jsonArray = new JSONArray();
DBCollection table;
try {
BasicDBObject quoteQuery = new BasicDBObject("abc", abc);
DBCursor cursor = table.find(quoteQuery);
while(cursor.hasNext()) {
jsonArray.put(cursor.next());
}
}
Actually the ideal case is not using static access at all and inject DB object from a central controller.
Your are creating connections in MongoDB, but you are not closing connections. For any database, it is very very important to close a connection, otherwise it will reach to its maximum limit and you wont be able to execute your program properly. Following code will be helpful i hope:
public static String getSomething(String s) {
String json = "[]";
JSONArray jsonArray = new JSONArray();
try {
MongoClient mongoClient = new MongoClient("localhost", 27017);
DB db = mongoClient.getDB("myDb");
DBCollection collection = db.getCollection("NAME OF YOUR COLLECTION");
BasicDBObject quoteQuery = new BasicDBObject("abc", "VARIABLE THAT YOU WANT TO FIND");
DBCursor cursor = collection.find(quoteQuery);
try {
while (cursor.hasNext()) {
jsonArray.put(cursor.next());
}
} finally {
cursor.close();
}
mongoClient.close();
} catch (Exception e) {
}
return jsonArray.toString();
}
In this code, 'MongoClient' is closed after its purpose is over.
Arun Gupta #arungupta
New sample shows how to use Mongo within a #JavaEE7 app: New sample to show basic usage of Mongo in a Java EE application
As per above mentioned issue, its like you are creating the Mongo Object for every request.I will suggest to use the single Object through out your application.FOr this you can find the "MongoClient and connection pooling".
MongoClient will handle connection pooling for you automatically.
mongoClient = new MongoClient(URI, connectionOptions);
Here the mongoClient object holds your connection pool, and will give your app connections as needed. You should strive to create this object once as your application initializes and re-use this object throughout your application to talk to your database. The most common connection pooling problem we see results from applications that create a MongoClient object way too often, sometimes on each database request. If you do this you will not be using your connection pool as each MongoClient object maintains a separate pool that is not being reused by your application.