/*
* ====================
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License("CDDL") (the "License"). You may not use this file
* except in compliance with the License.
*
* You can obtain a copy of the License at
* http://opensource.org/licenses/cddl1.php
* See the License for the specific language governing permissions and limitations
* under the License.
*
* When distributing the Covered Code, include this CDDL Header Notice in each file
* and include the License file at http://opensource.org/licenses/cddl1.php.
* If applicable, add the following below this CDDL Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
* ====================
*/
package org.identityconnectors.oracleerp;
import static org.identityconnectors.oracleerp.OracleERPUtil.MSG_PASSWORD_BLANK;
import static org.identityconnectors.oracleerp.OracleERPUtil.MSG_USER_BLANK;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.List;
import oracle.jdbc.OracleConnection;
import org.identityconnectors.common.StringUtil;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.dbcommon.DatabaseConnection;
import org.identityconnectors.dbcommon.DatabaseQueryBuilder;
import org.identityconnectors.dbcommon.JNDIUtil;
import org.identityconnectors.dbcommon.SQLParam;
import org.identityconnectors.dbcommon.SQLUtil;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
import org.identityconnectors.framework.common.objects.ConnectorMessages;
import org.identityconnectors.framework.spi.Configuration;
/**
* Class to represent a OracleErp Connection.
*
* @author petr
* @version 1.0
* @since 1.0
*/
final class OracleERPConnection extends DatabaseConnection {
/**
* The default row prefetch used in Oracle statements.
*/
private static final int DEFAULT_ROW_PREFETCH = 10;
static final Log LOG = Log.getLog(OracleERPConnector.class);
/**
* Create connection the instance creation method.
*
* @param config
* @return a new {@link OracleERPConnection} connection wrapper
*/
static OracleERPConnection createConnection(OracleERPConfiguration config) {
final Connection connection = getNativeConnection(config);
return new OracleERPConnection(connection, config);
}
/**
* @param config
* @return native {@link Connection} connection
*/
static Connection getNativeConnection(OracleERPConfiguration config) {
Connection connection;
final String user = config.getUser();
final GuardedString password = config.getPassword();
final String datasource = config.getDataSource();
if (StringUtil.isNotBlank(datasource)) {
LOG.ok("Create datasource connection {0}", datasource);
final String[] jndiProperties = config.getJndiProperties();
final ConnectorMessages connectorMessages = config.getConnectorMessages();
final Hashtable<String, String> prop =
JNDIUtil.arrayToHashtable(jndiProperties, connectorMessages);
if (StringUtil.isNotBlank(user) && password != null) {
connection = SQLUtil.getDatasourceConnection(datasource, user, password, prop);
} else {
connection = SQLUtil.getDatasourceConnection(datasource, prop);
}
} else {
connection = getDriverMangerConnection(config);
}
if (connection instanceof OracleConnection) {
final OracleConnection oracleConn = (OracleConnection) connection;
/* On Oracle enable the synonyms */
try {
if (!oracleConn.getIncludeSynonyms()) {
LOG.ok("setIncludeSynonyms on ORACLE");
oracleConn.setIncludeSynonyms(true);
LOG.ok("setIncludeSynonyms success");
}
} catch (Exception e) {
LOG.error(e, "setIncludeSynonyms on ORACLE exception");
}
// Set default row Prefetch
try {
if (oracleConn.getDefaultRowPrefetch() != DEFAULT_ROW_PREFETCH) {
LOG.ok("setDefaultRowPrefetch on ORACLE");
oracleConn.setDefaultRowPrefetch(DEFAULT_ROW_PREFETCH);
LOG.ok("setDefaultRowPrefetch success");
}
} catch (SQLException expected) {
// expected
LOG.error(expected, "setDefaultRowPrefetch exception");
}
}
// Disable auto-commit mode
try {
if (connection.getAutoCommit()) {
LOG.ok("setAutoCommit(false)");
connection.setAutoCommit(false);
}
} catch (SQLException expected) {
// expected
LOG.error(expected, "setAutoCommit(false) exception");
}
return connection;
}
private OracleERPConfiguration config = null;
/**
* Use the {@link Configuration} passed in to immediately connect to a
* database. If the {@link Connection} fails a {@link RuntimeException} will
* be thrown.
*
* @param conn
* Real connection.
* @param config
* the Oracle ERP configuration
* @throws RuntimeException
* if there is a problem creating a {@link java.sql.Connection}.
*/
private OracleERPConnection(Connection conn, OracleERPConfiguration config) {
super(conn);
this.config = config;
}
/**
* Close connection if pooled.
*/
public void closeConnection() {
if (getConnection() != null && StringUtil.isNotBlank(config.getDataSource())
/*&& this.conn.getConnection() instanceof PooledConnection */) {
LOG.ok("Close the pooled connection");
dispose();
}
}
/**
* Create new connection if pooled and taken from the datasource.
*
* @throws SQLException
*/
public void openConnection() throws SQLException {
if (getConnection() == null || getConnection().isClosed()) {
LOG.ok("Get new connection, it is closed");
setConnection(getNativeConnection(config));
}
}
/**
* OracleERP prepareCall statement with mapped callable statement parameters.
*
* @param sql
* a <CODE>String</CODE> sql statement definition
* @return return a callable statement
* @throws SQLException
* an exception in statement
*/
public CallableStatement prepareCall(final String sql) throws SQLException {
LOG.ok("prepareCall sql: {0}", sql);
final CallableStatement cs = getConnection().prepareCall(sql);
cs.setQueryTimeout(OracleERPUtil.ORACLE_TIMEOUT);
return cs;
}
/**
* OracleERP prepareCall statement with mapped callable statement parameters.
*
* @param sql
* a <CODE>String</CODE> sql statement definition
* @param params
* the bind parameter values
* @return return a callable statement
* @throws SQLException
* an exception in statement
*/
@Override
public CallableStatement prepareCall(final String sql, final List<SQLParam> params)
throws SQLException {
LOG.ok("prepareCall sql: {0}", sql);
final CallableStatement cs = super.prepareCall(sql, params);
cs.setQueryTimeout(OracleERPUtil.ORACLE_TIMEOUT);
return cs;
}
/**
* OracleERP prepare statement using the query builder object.
*
* @param query
* DatabaseQueryBuilder query
* @return return a prepared statement
* @throws SQLException
* an exception in statement
*/
@Override
public PreparedStatement prepareStatement(DatabaseQueryBuilder query) throws SQLException {
final PreparedStatement ps = super.prepareStatement(query);
ps.setQueryTimeout(OracleERPUtil.ORACLE_TIMEOUT);
return ps;
}
/**
* OracleERP prepare statement.
*
* @param sql
* @return the prepared statement
* @throws SQLException
*/
public PreparedStatement prepareStatement(String sql) throws SQLException {
LOG.ok("prepareStatement sql: {0}", sql);
PreparedStatement ps = getConnection().prepareStatement(sql);
ps.setQueryTimeout(OracleERPUtil.ORACLE_TIMEOUT);
return ps;
}
/**
* OracleERP prepare statement with mapped prepare statement parameters.
*
* @param sql
* a <CODE>String</CODE> sql statement definition
* @param params
* the bind parameter values
* @return return a prepared statement
* @throws SQLException
* an exception in statement
*/
@Override
public PreparedStatement prepareStatement(final String sql, final List<SQLParam> params)
throws SQLException {
LOG.ok("prepareStatement sql: {0}", sql);
final PreparedStatement ps = super.prepareStatement(sql, params);
ps.setQueryTimeout(OracleERPUtil.ORACLE_TIMEOUT);
return ps;
}
/**
* Return the driver manager connection.
*
* @param config
* parameters
* @return
*/
private static Connection getDriverMangerConnection(final OracleERPConfiguration config) {
final String connectionUrl = config.getConnectionUrl();
LOG.ok("getDriverMangerConnection connectionUrl {0}", connectionUrl);
// create the connection base on the configuration..
final Connection[] ret = new Connection[1];
try {
// load the driver class..
Class.forName(config.getDriver());
// get the database URL..
if (config.getPassword() == null) {
throw new IllegalStateException(config.getMessage(MSG_PASSWORD_BLANK));
}
if (StringUtil.isBlank(config.getUser())) {
throw new IllegalStateException(config.getMessage(MSG_USER_BLANK));
}
// check if there is authentication involved.
config.getPassword().access(new GuardedString.Accessor() {
public void access(char[] clearChars) {
try {
java.util.Properties info = new java.util.Properties();
info.put("user", config.getUser());
info.put("password", new String(clearChars));
if (StringUtil.isNotBlank(config.getClientEncryptionType())) {
LOG.ok("getDriverMangerConnection set oracle.net.encryption_types_client {0}",
config.getClientEncryptionType());
info.put("oracle.net.encryption_types_client", config
.getClientEncryptionType());
}
if (StringUtil.isNotBlank(config.getClientEncryptionLevel())) {
LOG.ok("getDriverMangerConnection set oracle.net.encryption_client {0}",
config.getClientEncryptionLevel());
info.put("oracle.net.encryption_client", config
.getClientEncryptionLevel());
}
ret[0] = DriverManager.getConnection(connectionUrl, info);
} catch (SQLException e) {
// checked exception are not allowed in the access
// method
// Lets use the exception softening pattern
throw new RuntimeException(e);
}
}
});
// turn off auto-commit
} catch (Exception e) {
throw ConnectorException.wrap(e);
}
return ret[0];
}
}