Open YuLimin opened 2 months ago
Why does the connection need to be unwrapped to something other than a java.sql.Connection?
Would the following code work?
Connection connection = as400DataSource.getConnection(); DatabaseMetaData metaDataConnection = connection.getMetaData(); Connection connection 2 = metaDataConnection.getConnection(); if (connection2 instanceof com.ibm.as400.access.AS400JDBCConnection) { AS400JDBCConnection as400JDBCConnection = (com.ibm.as400.access.AS400JDBCConnection) connection2; AS400 as400System = as400JDBCConnection.getSystem(); }
Why does the connection need to be unwrapped to something other than a java.sql.Connection?
Would the following code work?
Connection connection = as400DataSource.getConnection(); DatabaseMetaData metaDataConnection = connection.getMetaData(); Connection connection 2 = metaDataConnection.getConnection(); if (connection2 instanceof com.ibm.as400.access.AS400JDBCConnection) { AS400JDBCConnection as400JDBCConnection = (com.ibm.as400.access.AS400JDBCConnection) connection2; AS400 as400System = as400JDBCConnection.getSystem(); }
Yes, These code work on Tomcat smoothly.
I'm still not sure what change needs to be made. I don't want to change the class hierarchy structure if a sufficient workaround is available.
I'm still not sure what change needs to be made. I don't want to change the class hierarchy structure if a sufficient workaround is available.
I don't find any sufficient workaround until now.
So, what is the code that isn't working? Why doesn't the following code work?
Connection connection = as400DataSource.getConnection(); DatabaseMetaData metaDataConnection = connection.getMetaData(); Connection connection 2 = metaDataConnection.getConnection(); if (connection2 instanceof com.ibm.as400.access.AS400JDBCConnection) { AS400JDBCConnection as400JDBCConnection = (com.ibm.as400.access.AS400JDBCConnection) connection2; AS400 as400System = as400JDBCConnection.getSystem(); }
Here are Exception from Liberty 24.0.0.4
<feature>jndi-1.0</feature>
<feature>jdbc-4.3</feature>
J2CA8050I: An authentication alias should be used instead of defining a user name and password on dataSource[AS400]. CWRLS0010I: Performing recovery processing for local WebSphere server (AS400). CWRLS0012I: All persistent services have been directed to perform recovery processing for this WebSphere server (AS400). WTRN0135I: Transaction service recovering no transactions. YuLimin : DataSource : com.ibm.ws.rsadapter.jdbc.v43.WSJdbc43DataSource@847e2893
DSRA8203I: Database product name : DB2 UDB for AS/400 DSRA8204I: Database product version : 07.04.0000 V7R4m0 DSRA8205I: JDBC driver name : AS/400 Toolbox for Java JDBC Driver DSRA8206I: JDBC driver version : 13.3 Connection : com.ibm.ws.rsadapter.jdbc.v43.WSJdbc43Connection@4ae92124 Connection getClass : class com.ibm.ws.rsadapter.jdbc.v43.WSJdbc43Connection FFDC1015I: An FFDC Incident has been created: "java.sql.SQLException: DSRA9124E: Cannot unwrap object to com.ibm.as400.access.AS400JDBCConnection because com.ibm.as400.access.AS400JDBCConnection is not an interface class. com.ibm.ws.rsadapter.jdbc.v43.WSJdbc43Connection.unwrap 441" at ffdc_24.05.18_12.41.47.0.log java.sql.SQLException: DSRA9124E: Cannot unwrap object to com.ibm.as400.access.AS400JDBCConnection because com.ibm.as400.access.AS400JDBCConnection is not an interface class. at com.ibm.ws.rsadapter.jdbc.WSJdbcWrapper.unwrap(WSJdbcWrapper.java:472) at AS400JDBCDirect.getAS400JNDI(AS400JDBCDirect.java:66) at AS400JndiServlet.doGet(AS400JndiServlet.java:38) at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
What error do you see if you use this code?
Connection connection = as400DataSource.getConnection(); DatabaseMetaData metaDataConnection = connection.getMetaData(); Connection connection 2 = metaDataConnection.getConnection(); if (connection2 instanceof com.ibm.as400.access.AS400JDBCConnection) { AS400JDBCConnection as400JDBCConnection = (com.ibm.as400.access.AS400JDBCConnection) connection2; AS400 as400System = as400JDBCConnection.getSystem(); }
What does the AS400JDBCDirect.java code look like?
I add some log to these code as below
DataSource ds = (DataSource) ctx.lookup("jdbc/AS400");
System.out.println("YuLimin : DataSource : " + ds);
Connection connection1 = ds.getConnection();
DatabaseMetaData metaDataConnection1 = connection1.getMetaData();
System.out.println("YuLimin : metaDataConnection1 : " + metaDataConnection1);
Connection connection2 = metaDataConnection1.getConnection();
**System.out.println("YuLimin : Connection : " + connection2);
if (connection2 instanceof com.ibm.as400.access.AS400JDBCConnection)** {
AS400JDBCConnection as400JDBCConnection = (com.ibm.as400.access.AS400JDBCConnection) connection2;
AS400 as400System = as400JDBCConnection.getSystem();
System.out.println("YuLimin : as400System : " + as400System);
}
else
{
System.out.println("YuLimin : Connection Not instanceof com.ibm.as400.access.AS400JDBCConnection");
}
will get the result as below
YuLimin : DataSource : com.ibm.ws.rsadapter.jdbc.v43.WSJdbc43DataSource@d425249e YuLimin : metaDataConnection1 : com.ibm.ws.rsadapter.jdbc.v43.WSJdbc43DatabaseMet
YuLimin : Connection : com.ibm.ws.rsadapter.jdbc.v43.WSJdbc43Connection@550c23e8 YuLimin : Connection Not instanceof com.ibm.as400.access.AS400JDBCConnection
What kind of object do you get if you unwrap the com.ibm.ws.rsadapter.jdbc.v43.WSJdbc43Connection to a java.sql.Connection?
Can not unwrap to AS400JDBCConnection, only java.sql.Connection can get.
But what object implements the java.sql.Connection that is returned?
There is nothing but the stated class restriction (I'm not sure why it's there in the first place) that prevents unwrapping to a class. A connection object can unwrap itself as seen in the following example.
$ java -jar jt400.jar jdbc:as400:localhost
!setvar CLASS = java.lang.Class.forName('com.ibm.as400.access.AS400JDBCConnection') CLASS=class com.ibm.as400.access.AS400JDBCConnection
!setvar C2=CON.unwrap(CLASS) C2=UT24P87
!callmethod C2.getAS400() Call returned com.ibm.as400.access.AS400ImplRemote@32ac87bf
Perhaps the com.ibm.ws.rsadapter.jdbc.v43.WSJdbc43Connection.unwrap method at com.ibm.ws.rsadapter.jdbc.WSJdbcWrapper.unwrap(WSJdbcWrapper.java:472) shouldn't verify that the class isn't an interface, but try calling the unwrap method on the underlying class.
If not, which methods need to be accessed. We can probably define an interface for just those method.
There is nothing but the stated class restriction (I'm not sure why it's there in the first place) that prevents unwrapping to a class. A connection object can unwrap itself as seen in the following example.
$ java -jar jt400.jar jdbc:as400:localhost
!setvar CLASS = java.lang.Class.forName('com.ibm.as400.access.AS400JDBCConnection') CLASS=class com.ibm.as400.access.AS400JDBCConnection
!setvar C2=CON.unwrap(CLASS) C2=UT24P87
!callmethod C2.getAS400() Call returned com.ibm.as400.access.AS400ImplRemote@32ac87bf
Perhaps the com.ibm.ws.rsadapter.jdbc.v43.WSJdbc43Connection.unwrap method at com.ibm.ws.rsadapter.jdbc.WSJdbcWrapper.unwrap(WSJdbcWrapper.java:472) shouldn't verify that the class isn't an interface, but try calling the unwrap method on the underlying class.
If not, which methods need to be accessed. We can probably define an interface for just those method.
Yes, as code sample in my question, I can unwrap Connection to AS400JDBCConnection via JDBC directly and on Tomcat.
but on Liberty I can't unwrap from WSJdbc43Connection, Maybe Liberty connection pool implementation WSJdbcWrapper do NOT implement for wrap AS400JDBCConnection to WSJdbc43Connection. then we can't unwrap from WSJdbc43Connection to AS400JDBCConnection even AS400JDBCConnection is an interface or NOT.
As I said before..
Perhaps the com.ibm.ws.rsadapter.jdbc.v43.WSJdbc43Connection.unwrap method at com.ibm.ws.rsadapter.jdbc.WSJdbcWrapper.unwrap(WSJdbcWrapper.java:472) shouldn't verify that the class isn't an interface, but try calling the unwrap method on the underlying class.
You should work with the provider of the "com.ibm.ws.rsadapter.jdbc.WSJdbcWrapper" class to see if they can change to not throw an exception when the wrapped target isn't an interface.
java.sql.SQLException: DSRA9124E: Cannot unwrap object to com.ibm.as400.access.AS400JDBCConnection because com.ibm.as400.access.AS400JDBCConnection is not an interface class. at com.ibm.ws.rsadapter.jdbc.WSJdbcWrapper.unwrap(WSJdbcWrapper.java:472) at AS400JDBCDirect.getAS400JNDI(AS400JDBCDirect.java:66) at AS400JndiServlet.doGet(AS400JndiServlet.java:38) at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
Otherwise, what methods of AS400JDBCConnection need to be called. We can probably create an interface for just those methods.
How to unWrap a Connection to AS400JDBCConnection
com.ibm.as400.access.AS400JDBCConnection class is a abstract class Not an Interface
AS400JDBCConnection not like oracle.jdbc.OracleConnection which is an Interface https://www.ibm.com/support/pages/comibmwsrsadapterjdbcwsjdbcconnection-incompatible-oraclejdbcoracleconnection
Here are customer requirement and run on Tomcat smoothly :
How to get AS400JDBCConnection from Liberty datasource? 1.server.xml
2.Java Code
get AS400JDBCConnection directly but I can get via JDBC directly as below:
I use the same code and driver version, I have try call DB on AS400 via Tomat 9.0.60 and Liberty 24.0.0.4, then I found on Tomcat will get: DataSource is org.apache.tomcat.dbcp.dbcp2.BasicDataSource Connection is org.apache.tomcat.dbcp.dbcp2.PoolingDataSource$PoolGuardConnectionWrapper
But on Liberty DataSource : com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource Connection : com.ibm.ws.rsadapter.jdbc.WSJdbcConnection
The driver is JTOpen v20.0.7, jt400-20.0.7-java8.jar download from https://github.com/IBM/JTOpen/releases