We are migrating a legacy application from IBM WebSphere to OpenLiberty. Some functionalities use Oracle XSU to perform operations with the database.
I have managed to obtain the Oracle-specific connection by performing an unwrap operation over the java.sql.Connection
.
The error is raised when trying to insert data through XSU:
oracle.xml.sql.OracleXMLSQLException:
com.ibm.ws.rsadapter.jdbc.v42.WSJdbc42PreparedStatement cannot be cast to oracle.jdbc.OraclePreparedStatement
My server.xml:
<library id="jdbcLib">
<fileset dir="C:\Users\uC260112\.m2\repository\com\oracle\ojdbc6\11.2.0.1.0"/>
</library>
<dataSource id="gcmsXAWIPDS" jndiName="jdbc/gcmsXAWIPDS" type="javax.sql.XADataSource">
<jdbcDriver javax.sql.XADataSource="oracle.jdbc.xa.client.OracleXADataSource" libraryRef="jdbcLib"/>
<properties.oracle URL="jdbc:oracle:thin:@c588cwegcmd03.int.xxxx.com:1521/xxxxx.int.xxxxx.com" password="xxxxxx" user="xxxxxx"/>
<connectionManager maxPoolSize="100" minPoolSize="1"/>
</dataSource>
<enterpriseApplication id="xxxxx" location="xxxxx-1.0.ear" name="xxxxx">
<classloader commonLibraryRef="jdbcLib"/>
</enterpriseApplication>
Obtain and unwrap the connection:
conId = myXAPool.obtainConnection(null, null);
Connection connection = myXAPool.getConnection(conId);
OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
Try to insert using XSU:
OracleXMLSave sav = null;
try {
sav = getNewOracleXMLSave(oracleConnection, tableName);
sav.setRowTag(rowDelimiter);
sav.setDateFormat("dd/MM/yyyy HH:mm:ss");
sav.insertXML(xsuXml); //Exception here
} catch (Exception ex) {
Does anyone have an idea how to solve it?
Assuming the problem is that Oracle's XSU library is not unwrapping the PreparedStatements (thanks @njr), I have found a solution that works.
Build a proxy over the oracleConnection, and pass it to the XSU library instead of the actual oracleConnection:
OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
OracleConnection proxy = (OracleConnection) Proxy.newProxyInstance(
OracleConnection.class.getClassLoader(),
new Class<?>[]{OracleConnection.class},
new OracleConnectionInvocationHandler(oracleConnection));
OracleXMLSave sav = null;
try {
sav = getNewOracleXMLSave(proxy, tableName);
sav.setRowTag(rowDelimiter);
sav.setDateFormat("dd/MM/yyyy HH:mm:ss");
sav.insertXML(xsuXml);
That way, I can intercept the calls that the XSU library makes to the prepareStatement method, and do the unwrap before returning the object to the library. This is the proxy handler:
public class OracleConnectionInvocationHandler implements InvocationHandler {
private final OracleConnection target;
private SPELogger systemLog = null;
public OracleConnectionInvocationHandler(OracleConnection target) {
systemLog = AppLogger.getInstance();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("prepareStatement".equals(method.getName())) {
PreparedStatement preparedStatement = (PreparedStatement) method.invoke(target, args);
systemLog.logInfo(this, "Making PreparedStatement unwrap through OracleConnectionInvocationHandler");
return preparedStatement.unwrap(oracle.jdbc.OraclePreparedStatement.class);
}
return method.invoke(target, args);
}
}
In the meantime, I'm still in contact with Oracle to see if there is an XSU library that handles this properly. But the solution with the proxy works perfectly.