/**
* Copyright (C) 2010 Orbeon, Inc.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
*/
package org.orbeon.oxf.processor.sql;
import oracle.jdbc.*;
import oracle.sql.*;
import oracle.xdb.XMLType;
import org.orbeon.oxf.common.OXFException;
import org.orbeon.oxf.util.NetUtils;
import org.orbeon.oxf.xml.XMLParsing;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import java.io.*;
import java.sql.*;
/**
* Base class for Oracle delegates.
*
* NOTE: Check whether this works with WebLogic 8.1 and the thin driver, or if for example
* weblogic.jdbc.vendor.oracle.OracleThinBlob must be used. Would this work with createTemporary()
* anyway?
*/
public abstract class SQLProcessorOracleDelegateBase implements DatabaseDelegate {
// public SQLProcessorOracleTomcat4Delegate() {
// // Load the Oracle JDBC driver
// try {
// DriverManager.registerDriver
// (new oracle.jdbc.driver.OracleDriver());
// Connection conn = DriverManager.getConnection("jdbc:oracle:oci:@rosaura","scott","tiger");
//
// // Create Oracle DatabaseMetaData object
// DatabaseMetaData meta = conn.getMetaData();
//
// // gets driver info:
// System.out.println("JDBC driver version is " + meta.getDriverVersion());
// System.out.println("JDBC driver nameis " + meta.getDriverName());
// } catch (SQLException e) {
// e.printStackTrace();
// }
// }
public void setClob(PreparedStatement stmt, int index, String value) throws SQLException {
// Get an OraclePreparedStatement
final OraclePreparedStatement oracleStmt = getOraclePreparedStatement(stmt);
// Get an OracleConnection to prevent ClassCastException in oracle.sql.CLOB
// - see this post from 2004 https://forums.oracle.com/thread/281238
// - this still seems to be the case with Oracle 12c Release 1 (12.1.0.1) ojdbc6_g.jar
// - we only observed OraclePreparedStatement.getConnection() returning a wrapped
// connection when getting the OraclePreparedStatement through JDBC 4, so
// unwrapping the connection with JDBC 4's unwrap should be fine
final Connection connection = oracleStmt.getConnection();
final OracleConnection oracleConnection = connection instanceof OracleConnection
? (OracleConnection) connection
: connection.unwrap(OracleConnection.class);
// Create a temporary CLOB
final CLOB clob = CLOB.createTemporary(oracleConnection, true, CLOB.DURATION_SESSION);
// Write to the CLOB
final Writer writer = clob.getCharacterOutputStream();
try {
NetUtils.copyStream(new StringReader(value), writer);
writer.flush();
} catch (IOException e) {
throw new OXFException(e);
}
// Set the CLOB on the statement
oracleStmt.setClob(index, clob);
}
public void setBlob(PreparedStatement stmt, int index, byte[] value) throws SQLException {
final OutputStream os = getBlobOutputStream(stmt, index);
try {
NetUtils.copyStream(new ByteArrayInputStream(value), os);
os.close();
} catch (IOException e) {
throw new OXFException(e);
}
}
public OutputStream getBlobOutputStream(PreparedStatement stmt, final int index) throws SQLException {
// Get an OraclePreparedStatement
final OraclePreparedStatement oracleStmt = getOraclePreparedStatement(stmt);
// Create a temporary BLOB
final BLOB blob = BLOB.createTemporary(oracleStmt.getConnection(), true, BLOB.DURATION_SESSION);
// Get the output stream
final OutputStream os = blob.getBinaryOutputStream();
// Return a special OutputStream that will *have* to be closed for anything to happen
return new BufferedOutputStream(new OutputStream() {
private boolean closed = false;
public void close() throws IOException {
if (!closed) {
os.flush();
os.close();
// Set the BLOB on the statement
try {
oracleStmt.setBlob(index, blob);
} catch (SQLException e) {
throw new OXFException(e);
}
closed = true;
}
}
public void flush() throws IOException {
os.flush();
}
public void write(byte b[]) throws IOException {
os.write(b);
}
public void write(byte b[], int off, int len) throws IOException {
os.write(b, off, len);
}
public void write(int b) throws IOException {
os.write(b);
}
});
}
public boolean isXMLType(int columnType, String columnTypeName) throws SQLException {
// This according to Oracle documentation
return columnTypeName != null && OracleTypes.OPAQUE == columnType && columnTypeName.compareTo("SYS.XMLTYPE") == 0;
}
public Node getDOM(ResultSet resultSet, String columnName) throws SQLException {
final OracleResultSet oracleResultSet = getOracleResultSet(resultSet);
// XMLType xmlType = (XMLType) oracleResultSet.getObject(columnName);
final OPAQUE opaque = oracleResultSet.getOPAQUE(columnName);
final XMLType xmlType = XMLType.createXML(opaque);
final Node doc;
if(false && xmlType.isFragment()) {
// TODO: Handle XML fragment correctly
// doc = XMLUtils.parseDocumentFragment(xmlType.getStringVal());
doc = null;
} else {
// FIXME: Xerces throws when walking the tree if we return the DOM directly!!!
// doc = xmlType.getDOM();
doc = XMLParsing.stringToDOM(xmlType.getStringVal());
}
return doc;
}
public void setDOM(PreparedStatement stmt, int index, String document) throws SQLException {
// Get an OraclePreparedStatement
final OraclePreparedStatement oracleStmt = getOraclePreparedStatement(stmt);
final XMLType xmlType = XMLType.createXML(oracleStmt.getConnection(), document);
oracleStmt.setObject(index, xmlType);
}
public void setDOM(PreparedStatement stmt, int index, Document document) throws SQLException {
// Get an OraclePreparedStatement
OraclePreparedStatement oracleStmt = getOraclePreparedStatement(stmt);
// FIXME: XMLType.createXML(oracleStmt.getConnection(), doc) returns null!!!
XMLType xmlType = XMLType.createXML(oracleStmt.getConnection(), document);
oracleStmt.setObject(index, xmlType);
}
/**
* Derived classes must implement this to return a native OraclePreparedStatement.
*/
protected abstract OraclePreparedStatement getOraclePreparedStatement(PreparedStatement stmt);
/**
* Derived classes must implement this to return a native OracleResultSet.
*/
protected abstract OracleResultSet getOracleResultSet(ResultSet resultSet);
}