/**
*
*/
package org.identityconnectors.oracle;
import static org.identityconnectors.oracle.OracleMessages.ORACLE_CANNOT_CREATE_TEST_USER;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Set;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.dbcommon.FilterWhereBuilder;
import org.identityconnectors.dbcommon.SQLUtil;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.ResultsHandler;
import org.identityconnectors.framework.common.objects.Schema;
import org.identityconnectors.framework.common.objects.Uid;
import org.identityconnectors.framework.common.objects.filter.FilterTranslator;
import org.identityconnectors.framework.spi.AttributeNormalizer;
import org.identityconnectors.framework.spi.Configuration;
import org.identityconnectors.framework.spi.ConnectorClass;
import org.identityconnectors.framework.spi.PoolableConnector;
import org.identityconnectors.framework.spi.operations.AuthenticateOp;
import org.identityconnectors.framework.spi.operations.CreateOp;
import org.identityconnectors.framework.spi.operations.DeleteOp;
import org.identityconnectors.framework.spi.operations.SPIOperation;
import org.identityconnectors.framework.spi.operations.SchemaOp;
import org.identityconnectors.framework.spi.operations.SearchOp;
import org.identityconnectors.framework.spi.operations.TestOp;
import org.identityconnectors.framework.spi.operations.UpdateAttributeValuesOp;
import org.identityconnectors.framework.spi.operations.UpdateOp;
import org.identityconnectors.oracle.OracleConfiguration.ConnectionType;
/**
* Implementation of Oracle connector. It just delegates SPI calls to
* {@link AbstractOracleOperation} subclasses. This connector implementation
* does not normalize attributes.
*
* @author kitko
*
*/
@ConnectorClass(configurationClass = OracleConfiguration.class,
displayNameKey = OracleMessages.MSG_CONNECTOR_DISPLAY, messageCatalogPaths = {
"org/identityconnectors/dbcommon/Messages", "org/identityconnectors/oracle/Messages" })
public final class OracleConnector implements PoolableConnector, AuthenticateOp, CreateOp,
DeleteOp, UpdateOp, UpdateAttributeValuesOp, SearchOp<Pair<String, FilterWhereBuilder>>,
SchemaOp, TestOp, AttributeNormalizer {
private Connection adminConn;
private OracleConfiguration cfg;
private Schema schema;
private OracleAttributeNormalizer normalizer;
public void checkAlive() {
testInitialized();
if (adminConn == null) {
// Here we test we are still able to get new connection
adminConn = createAdminConnection();
try {
// Test that connection is ok, even the datasource pool can do
// the same
OracleSpecifics.testConnection(adminConn);
} finally {
if (ConnectionType.DATASOURCE.equals(cfg.getConnType())) {
SQLUtil.closeQuietly(adminConn);
adminConn = null;
}
}
} else {
OracleSpecifics.testConnection(adminConn);
}
}
public void dispose() {
SQLUtil.closeQuietly(adminConn);
adminConn = null;
cfg = null;
schema = null;
}
public OracleConfiguration getConfiguration() {
return cfg;
}
public void init(Configuration cfg) {
this.cfg = (OracleConfiguration) cfg;
cfg.validate();
}
/**
* Test of configuration and validity of connection.
*/
public void test() {
testInitialized();
cfg.validate();
startSPI(TestOp.class);
try {
OracleSpecifics.testConnection(adminConn);
testUseDriverForAuthentication();
} finally {
finsishSPI(TestOp.class);
}
}
private void testUseDriverForAuthentication() {
if (cfg.isUseDriverForAuthentication()) {
// Ok, here it means we are using datasource
// So try to get OracleDriverConnectionInfo and create connection
OracleDriverConnectionInfo connInfo =
OracleSpecifics.parseConnectionInfo(adminConn, cfg.getConnectorMessages());
// Here we need some dummy user/password to test authenticate. Can
// these fail because of some resource configuration ?
// Create the user
String userName = "test" + System.currentTimeMillis();
try {
SQLUtil.executeUpdateStatement(adminConn, "create user " + userName
+ " identified by " + userName);
SQLUtil.executeUpdateStatement(adminConn, "grant create session to " + userName);
OracleDriverConnectionInfo newInfo =
new OracleDriverConnectionInfo.Builder().setvalues(connInfo).setUser(
userName).setPassword(new GuardedString(userName.toCharArray()))
.build();
Connection conn =
OracleSpecifics.createDriverConnection(newInfo, cfg.getConnectorMessages());
conn.close();
} catch (SQLException e) {
throw new ConnectorException(ORACLE_CANNOT_CREATE_TEST_USER, e);
} finally {
try {
SQLUtil.executeUpdateStatement(adminConn, "drop user " + userName);
} catch (SQLException e) {
// Should not happen
throw new ConnectorException("Cannot drop testuser", e);
}
}
}
}
public Uid authenticate(ObjectClass objectClass, String username, GuardedString password,
OperationOptions options) {
startSPI(AuthenticateOp.class);
try {
Pair<String, GuardedString> pair =
createOracleAttributeNormalizer()
.normalizeAuthenticateEntry(username, password);
username = pair.getFirst();
password = pair.getSecond();
return new OracleOperationAuthenticate(cfg, adminConn).authenticate(objectClass,
username, password, options);
} finally {
finsishSPI(AuthenticateOp.class);
}
}
public void delete(ObjectClass objClass, Uid uid, OperationOptions options) {
startSPI(DeleteOp.class);
try {
new OracleOperationDelete(cfg, adminConn).delete(objClass, uid, options);
} finally {
finsishSPI(DeleteOp.class);
}
}
public Uid create(ObjectClass oclass, Set<Attribute> attrs, OperationOptions options) {
startSPI(CreateOp.class);
try {
attrs =
createOracleAttributeNormalizer().normalizeAttributes(oclass, CreateOp.class,
attrs);
return new OracleOperationCreate(cfg, adminConn).create(oclass, attrs, options);
} finally {
finsishSPI(CreateOp.class);
}
}
public Uid update(ObjectClass objclass, Uid uid, Set<Attribute> attrs, OperationOptions options) {
startSPI(UpdateOp.class);
try {
attrs =
createOracleAttributeNormalizer().normalizeAttributes(objclass, UpdateOp.class,
attrs);
return new OracleOperationUpdate(cfg, adminConn).update(objclass, uid, attrs, options);
} finally {
finsishSPI(UpdateOp.class);
}
}
public Uid addAttributeValues(ObjectClass objclass, Uid uid, Set<Attribute> valuesToAdd,
OperationOptions options) {
startSPI(UpdateAttributeValuesOp.class);
try {
valuesToAdd =
createOracleAttributeNormalizer().normalizeAttributes(objclass, UpdateOp.class,
valuesToAdd);
return new OracleOperationUpdate(cfg, adminConn).addAttributeValues(objclass, uid,
valuesToAdd, options);
} finally {
finsishSPI(UpdateAttributeValuesOp.class);
}
}
public Uid removeAttributeValues(ObjectClass objclass, Uid uid, Set<Attribute> valuesToRemove,
OperationOptions options) {
startSPI(UpdateAttributeValuesOp.class);
try {
valuesToRemove =
createOracleAttributeNormalizer().normalizeAttributes(objclass, UpdateOp.class,
valuesToRemove);
return new OracleOperationUpdate(cfg, adminConn).removeAttributeValues(objclass, uid,
valuesToRemove, options);
} finally {
finsishSPI(UpdateAttributeValuesOp.class);
}
}
public FilterTranslator<Pair<String, FilterWhereBuilder>> createFilterTranslator(
ObjectClass oclass, OperationOptions options) {
startSPI(SearchOp.class);
try {
return new OracleOperationSearch(cfg, adminConn)
.createFilterTranslator(oclass, options);
} finally {
finsishSPI(SearchOp.class);
}
}
public void executeQuery(ObjectClass oclass, Pair<String, FilterWhereBuilder> pair,
ResultsHandler handler, OperationOptions options) {
startSPI(SearchOp.class);
try {
new OracleOperationSearch(cfg, adminConn).executeQuery(oclass, pair, handler, options);
} finally {
finsishSPI(SearchOp.class);
}
}
public Schema schema() {
if (schema != null) {
return schema;
}
startSPI(SearchOp.class);
try {
schema = new OracleOperationSchema(cfg, adminConn).schema();
} finally {
finsishSPI(SearchOp.class);
}
return schema;
}
private void testInitialized() {
if (cfg == null) {
throw new ConnectorException("Connector is not yet initialized");
}
}
private Connection createAdminConnection() {
return cfg.createAdminConnection();
}
/**
* This method is just for tests to have direct access to connection used in
* Connector.
*/
Connection getOrCreateAdminConnection() {
// Now we create connection lazy
if (adminConn == null) {
adminConn = createAdminConnection();
}
return adminConn;
}
/** Just for tests to check state of connection. */
Connection getAdminConnection() {
return adminConn;
}
private void startSPI(Class<? extends SPIOperation> op) {
if (adminConn == null) {
adminConn = createAdminConnection();
// Here we also test the connection, because in checkAlive we might
// test other connection
OracleSpecifics.testConnection(adminConn);
}
}
private void finsishSPI(Class<? extends SPIOperation> op) {
if (ConnectionType.DATASOURCE.equals(cfg.getConnType())) {
SQLUtil.closeQuietly(adminConn);
adminConn = null;
}
}
public Attribute normalizeAttribute(ObjectClass oclass, Attribute attribute) {
return createOracleAttributeNormalizer().normalizeAttribute(oclass, attribute);
}
private OracleAttributeNormalizer createOracleAttributeNormalizer() {
if (normalizer == null) {
normalizer = cfg.getNormalizerName().createNormalizer(cfg.getCSSetup());
}
return normalizer;
}
}