/* * ==================== * 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_ACCOUNT_UID_REQUIRED; import static org.identityconnectors.oracleerp.OracleERPUtil.MSG_INVALID_ACCOUNT_INCLUDED; import static org.identityconnectors.oracleerp.OracleERPUtil.MSG_UNKNOWN_OPERATION_TYPE; import static org.identityconnectors.oracleerp.OracleERPUtil.MSG_UNSUPPORTED_OPERATION; import static org.identityconnectors.oracleerp.OracleERPUtil.RESP_NAMES; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.identityconnectors.common.Assertions; import org.identityconnectors.common.StringUtil; import org.identityconnectors.common.logging.Log; import org.identityconnectors.common.script.Script; import org.identityconnectors.common.script.ScriptExecutorFactory; import org.identityconnectors.common.security.GuardedString; import org.identityconnectors.dbcommon.FilterWhereBuilder; import org.identityconnectors.dbcommon.SQLParam; 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.ScriptContext; 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.ResolveUsernameOp; import org.identityconnectors.framework.spi.operations.SchemaOp; import org.identityconnectors.framework.spi.operations.ScriptOnConnectorOp; import org.identityconnectors.framework.spi.operations.SearchOp; import org.identityconnectors.framework.spi.operations.TestOp; import org.identityconnectors.framework.spi.operations.UpdateOp; /** * Main implementation of the OracleErp Connector. * * @author petr * @version 1.0 * @since 1.0 */ @ConnectorClass(displayNameKey = "oracleerp.connector.display", configurationClass = OracleERPConfiguration.class) public class OracleERPConnector implements PoolableConnector, AuthenticateOp, DeleteOp, SearchOp<FilterWhereBuilder>, UpdateOp, CreateOp, TestOp, SchemaOp, ScriptOnConnectorOp, AttributeNormalizer, ResolveUsernameOp { private static final Log LOG = Log.getLog(OracleERPConnector.class); /** * Place holder for the {@link Configuration} passed into the init() method * {@link OracleERPConnector#init}. */ private OracleERPConfiguration cfg; /** * Gets the Configuration context for this connector. * * {@inheritDoc} */ public Configuration getConfiguration() { return this.cfg; } /** * getter method. * * @return OracleERPConfiguration */ OracleERPConfiguration getCfg() { return cfg; } /** * The OrecleERP connection wrapper. */ private OracleERPConnection conn; OracleERPConnection getConn() { return conn; } /** * {@inheritDoc} */ public Uid authenticate(ObjectClass objectClass, final String username, final GuardedString password, final OperationOptions options) { LOG.ok("authenticate"); Assertions.nullCheck(objectClass, "objectClass"); Assertions.nullCheck(username, "username"); Assertions.nullCheck(password, "password"); if (objectClass.is(ObjectClass.ACCOUNT_NAME)) { return new AccountOperationAutenticate(getConn(), getCfg()).authenticate(objectClass, username, password, options); } else if (objectClass.is(RESP_NAMES)) { throw new IllegalArgumentException(getCfg().getMessage(MSG_UNSUPPORTED_OPERATION, "authenticate", objectClass.toString())); } throw new IllegalArgumentException(getCfg().getMessage(MSG_UNKNOWN_OPERATION_TYPE, objectClass.toString())); } /** * {@inheritDoc} */ public Uid resolveUsername(ObjectClass objectClass, String username, OperationOptions options) { LOG.ok("resolveUsername"); Assertions.nullCheck(objectClass, "objectClass"); Assertions.nullCheck(username, "username"); if (objectClass.is(ObjectClass.ACCOUNT_NAME)) { return new AccountOperationAutenticate(getConn(), getCfg()).resolveUsername( objectClass, username, options); } else if (objectClass.is(RESP_NAMES)) { throw new IllegalArgumentException(getCfg().getMessage(MSG_UNSUPPORTED_OPERATION, "resolveUsername", objectClass.toString())); } throw new IllegalArgumentException(getCfg().getMessage(MSG_UNKNOWN_OPERATION_TYPE, objectClass.toString())); } /****************** * SPI Operations * * Implement the following operations using the contract and description * found in the Javadoc for these methods. ******************/ /** * {@inheritDoc} */ public Uid create(ObjectClass oclass, Set<Attribute> attrs, OperationOptions options) { LOG.ok("create"); Assertions.nullCheck(oclass, "oclass"); Assertions.nullCheck(attrs, "attrs"); if (oclass.is(ObjectClass.ACCOUNT_NAME)) { return new AccountOperationCreate(getConn(), getCfg()).create(oclass, attrs, options); } else if (oclass.is(RESP_NAMES)) { throw new IllegalArgumentException(getCfg().getMessage(MSG_UNSUPPORTED_OPERATION, "create", oclass.toString())); } throw new IllegalArgumentException(getCfg().getMessage(MSG_UNKNOWN_OPERATION_TYPE, oclass.toString())); } /** * {@inheritDoc} */ public FilterTranslator<FilterWhereBuilder> createFilterTranslator(ObjectClass oclass, OperationOptions options) { LOG.ok("createFilterTranslator"); Assertions.nullCheck(oclass, "oclass"); if (oclass.is(ObjectClass.ACCOUNT_NAME)) { return new AccountOperationSearch(getConn(), getCfg()).createFilterTranslator(oclass, options); } else if (oclass.is(OracleERPUtil.RESP_NAMES)) { return new RespNamesOperationSearch(getConn(), getCfg()).createFilterTranslator(oclass, options); } else if (oclass.is(OracleERPUtil.RESP_NAMES)) { return new ResponsibilitiesOperationSearch(getConn(), getCfg()).createFilterTranslator( oclass, options); } else if (oclass.is(OracleERPUtil.DIRECT_RESPS)) { return new ResponsibilitiesOperationSearch(getConn(), getCfg()).createFilterTranslator( oclass, options); } else if (oclass.is(OracleERPUtil.INDIRECT_RESPS)) { return new ResponsibilitiesOperationSearch(getConn(), getCfg()).createFilterTranslator( oclass, options); } else if (oclass.is(OracleERPUtil.APPS)) { return new ApplicationOperationSearch(getConn(), getCfg()).createFilterTranslator( oclass, options); } else if (oclass.is(OracleERPUtil.AUDITOR_RESPS)) { return new AuditorOperationSearch(getConn(), getCfg()).createFilterTranslator(oclass, options); } else if (oclass.is(OracleERPUtil.SEC_GROUPS)) { return new SecuringGroupsOperationSearch(getConn(), getCfg()).createFilterTranslator( oclass, options); } else if (oclass.is(OracleERPUtil.SEC_ATTRS)) { return new SecuringAttributesOperationSearch(getConn(), getCfg()) .createFilterTranslator(oclass, options); } throw new IllegalArgumentException(getCfg().getMessage(MSG_UNKNOWN_OPERATION_TYPE, oclass.toString())); } /** * {@inheritDoc} */ public void delete(ObjectClass objClass, Uid uid, OperationOptions options) { LOG.ok("delete"); Assertions.nullCheck(objClass, "oclass"); Assertions.nullCheck(uid, "uid"); if (uid == null || uid.getUidValue() == null) { throw new IllegalArgumentException(getCfg().getMessage(MSG_ACCOUNT_UID_REQUIRED)); } if (objClass.is(ObjectClass.ACCOUNT_NAME)) { new AccountOperationDelete(getConn(), getCfg()).delete(objClass, uid, options); return; } else if (objClass.is(RESP_NAMES)) { throw new IllegalArgumentException(getCfg().getMessage(MSG_UNSUPPORTED_OPERATION, "delete", objClass.toString())); } throw new IllegalArgumentException(getCfg().getMessage(MSG_UNKNOWN_OPERATION_TYPE, objClass.toString())); } /** * {@inheritDoc} */ public void dispose() { LOG.ok("dispose"); if (getConn() != null) { getConn().dispose(); } cfg = null; conn = null; } /** * {@inheritDoc} */ public void executeQuery(ObjectClass oclass, FilterWhereBuilder where, ResultsHandler handler, OperationOptions options) { LOG.ok("executeQuery"); Assertions.nullCheck(oclass, "oclass"); Assertions.nullCheck(handler, "handler"); if (oclass.is(ObjectClass.ACCOUNT_NAME)) { new AccountOperationSearch(getConn(), getCfg()).executeQuery(oclass, where, handler, options); return; } else if (oclass.is(OracleERPUtil.RESP_NAMES)) { new RespNamesOperationSearch(getConn(), getCfg()).executeQuery(oclass, where, handler, options); return; } else if (oclass.is(OracleERPUtil.RESPS)) { new ResponsibilitiesOperationSearch(getConn(), getCfg()).executeQuery(oclass, where, handler, options); return; } else if (oclass.is(OracleERPUtil.DIRECT_RESPS)) { new ResponsibilitiesOperationSearch(getConn(), getCfg()).executeQuery(oclass, where, handler, options); return; } else if (oclass.is(OracleERPUtil.INDIRECT_RESPS)) { new ResponsibilitiesOperationSearch(getConn(), getCfg()).executeQuery(oclass, where, handler, options); return; } else if (oclass.is(OracleERPUtil.APPS)) { new ApplicationOperationSearch(getConn(), getCfg()).executeQuery(oclass, where, handler, options); return; } else if (oclass.is(OracleERPUtil.AUDITOR_RESPS)) { new AuditorOperationSearch(getConn(), getCfg()).executeQuery(oclass, where, handler, options); return; } else if (oclass.is(OracleERPUtil.SEC_GROUPS)) { new SecuringGroupsOperationSearch(getConn(), getCfg()).executeQuery(oclass, where, handler, options); return; } else if (oclass.is(OracleERPUtil.SEC_ATTRS)) { new SecuringAttributesOperationSearch(getConn(), getCfg()).executeQuery(oclass, where, handler, options); return; } throw new IllegalArgumentException(getCfg().getMessage(MSG_UNKNOWN_OPERATION_TYPE, oclass.toString())); } /** * {@inheritDoc} */ public Attribute normalizeAttribute(ObjectClass oclass, Attribute attribute) { Assertions.nullCheck(oclass, "oclass"); Assertions.nullCheck(attribute, "attribute"); if (oclass.is(ObjectClass.ACCOUNT_NAME)) { return new AccountNameResolver().normalizeAttribute(oclass, attribute); } else if (oclass.is(OracleERPUtil.RESP_NAMES)) { return new BasicNameResolver().normalizeAttribute(oclass, attribute); } else if (oclass.is(OracleERPUtil.RESPS)) { return new BasicNameResolver().normalizeAttribute(oclass, attribute); } else if (oclass.is(OracleERPUtil.DIRECT_RESPS)) { return new BasicNameResolver().normalizeAttribute(oclass, attribute); } else if (oclass.is(OracleERPUtil.INDIRECT_RESPS)) { return new BasicNameResolver().normalizeAttribute(oclass, attribute); } else if (oclass.is(OracleERPUtil.APPS)) { return new BasicNameResolver().normalizeAttribute(oclass, attribute); } else if (oclass.is(OracleERPUtil.AUDITOR_RESPS)) { return new BasicNameResolver().normalizeAttribute(oclass, attribute); } else if (oclass.is(OracleERPUtil.SEC_GROUPS)) { return new BasicNameResolver().normalizeAttribute(oclass, attribute); } else if (oclass.is(OracleERPUtil.SEC_ATTRS)) { return new BasicNameResolver().normalizeAttribute(oclass, attribute); } throw new IllegalArgumentException(getCfg().getMessage(MSG_UNKNOWN_OPERATION_TYPE, oclass.toString())); } /* * (non-Javadoc) */ public Object runScriptOnConnector(ScriptContext request, OperationOptions options) { LOG.ok("runScriptOnConnector"); Assertions.nullCheck(request, "request"); return new OracleERPOperationRunScriptOnConnector(getConn(), getCfg()) .runScriptOnConnector(request, options); } /** * {@inheritDoc} */ public Schema schema() { LOG.ok("schema"); if (null == getCfg()) { return new OracleERPOperationSchema(new OracleERPConfiguration()).schema(); } else if (getCfg().getSchema() == null) { getCfg().setSchema(new OracleERPOperationSchema(getCfg()).schema()); } return getCfg().getSchema(); } /* * (non-Javadoc) */ public void test() { LOG.ok("test"); getConn().test(); validateAccountsIncluded(); // Validate Get User After script by compiling it validateGetUserAfterActionScript(getCfg().getUserAfterActionScript()); } /* * (non-Javadoc) */ public Uid update(ObjectClass objClass, Uid uid, Set<Attribute> attrs, OperationOptions options) { LOG.ok("update"); Assertions.nullCheck(objClass, "oclass"); Assertions.nullCheck(uid, "uid"); Assertions.nullCheck(attrs, "replaceAttributes"); if (uid == null || uid.getUidValue() == null) { throw new IllegalArgumentException(getCfg().getMessage(MSG_ACCOUNT_UID_REQUIRED)); } if (attrs.isEmpty()) { // Nothing to update return uid; } if (objClass.is(ObjectClass.ACCOUNT_NAME)) { return new AccountOperationUpdate(getConn(), getCfg()).update(objClass, uid, attrs, options); } else if (objClass.is(RESP_NAMES)) { throw new IllegalArgumentException(getCfg().getMessage(MSG_UNSUPPORTED_OPERATION, "update", objClass.toString())); } throw new IllegalArgumentException(getCfg().getMessage(MSG_UNKNOWN_OPERATION_TYPE, objClass.toString())); } /** * {@inheritDoc} */ public void init(Configuration configuration) { LOG.ok("init"); this.cfg = (OracleERPConfiguration) configuration; this.conn = OracleERPConnection.createConnection(getCfg()); LOG.ok("createOracleERPConnection"); getCfg().setUserId( new SecuringAttributesOperations(getConn(), getCfg()).getUserId(getCfg() .getOraUserName())); LOG.info("Init: for user {0} the configUserId is {1}", getCfg().getUser(), getCfg() .getUserId()); initResponsibilities(); initFndGlobal(); schema(); LOG.ok("init done"); } /** * Init connector`s call. */ private void initFndGlobal() { final String respId = getCfg().getRespId(); final String respApplId = getCfg().getRespApplId(); LOG.ok("Init global respId={0}, respApplId={1}", respId, respApplId); // Real initialize call if (StringUtil.isNotBlank(getCfg().getUserId()) && StringUtil.isNotBlank(respId) && StringUtil.isNotBlank(respApplId)) { CallableStatement cs = null; try { final String sql = "call " + getCfg().app() + "FND_GLOBAL.APPS_INITIALIZE(?,?,?)"; final String msg = "Oracle ERP: {0}FND_GLOBAL.APPS_INITIALIZE({1}, {2}, {3}) called."; LOG.info(msg, getCfg().app(), getCfg().getUserId(), respId, respApplId); List<SQLParam> pars = new ArrayList<SQLParam>(); pars.add(new SQLParam("userId", getCfg().getUserId(), Types.VARCHAR)); pars.add(new SQLParam("respId", respId, Types.VARCHAR)); pars.add(new SQLParam("respAppId", respApplId, Types.VARCHAR)); cs = getConn().prepareCall(sql, pars); cs.execute(); // Result ? // cstmt1 closed in finally below getConn().commit(); } catch (SQLException e) { final String msg = "Oracle ERP: Failed to call {0}FND_GLOBAL.APPS_INITIALIZE()"; LOG.error(e, msg, getCfg().app()); } finally { // close everything in case we had an exception in the middle of // something SQLUtil.closeQuietly(cs); cs = null; } } else { LOG.info("Oracle ERP: {0}FND_GLOBAL.APPS_INITIALIZE() NOT called.", getCfg().app()); } } /** * Init the responsibilities. * */ private void initResponsibilities() { LOG.ok("initResponsibilities"); getCfg().setNewResponsibilityViews(getNewResponsibilityViews()); if (getCfg().isNewResponsibilityViews()) { getCfg().setDescrExists(getDescriptionExiests()); } // three pieces of data need for apps_initialize() final String auditResponsibility = getCfg().getAuditResponsibility(); LOG.ok("auditResponsibility = {0}", auditResponsibility); if (StringUtil.isNotBlank(auditResponsibility) && StringUtil.isNotBlank(getCfg().getUserId())) { final String view = getCfg().app() + ((getCfg().isNewResponsibilityViews()) ? OracleERPUtil.RESPS_ALL_VIEW : OracleERPUtil.RESPS_TABLE); final String sql = "select responsibility_id, responsibility_application_id from " + view + " where user_id = ? and " + "(responsibility_id,responsibility_application_id) = (select responsibility_id,application_id from " + getCfg().app() + "fnd_responsibility_vl where responsibility_name = ?)"; final String msg = "Oracle ERP SQL: RESP_ID = {0}, RESP_APPL_ID = {1}"; ArrayList<SQLParam> params = new ArrayList<SQLParam>(); params.add(new SQLParam("userId", getCfg().getUserId())); params.add(new SQLParam("responsibilityName", auditResponsibility)); PreparedStatement ps = null; ResultSet rs = null; try { LOG.ok("Select responsibility for user_id: {0}, and audit responsibility {1}", getCfg().getUserId(), auditResponsibility); ps = getConn().prepareStatement(sql, params); rs = ps.executeQuery(); if (rs != null) { if (rs.next()) { getCfg().setRespId(rs.getString(1)); getCfg().setRespApplId(rs.getString(2)); } } getConn().commit(); LOG.ok(msg, getCfg().getRespId(), getCfg().getRespApplId()); } catch (SQLException e) { SQLUtil.rollbackQuietly(getConn()); LOG.error(e, msg, getCfg().getRespId(), getCfg().getRespApplId()); } finally { // close everything in case we had an exception in the middle of // something SQLUtil.closeQuietly(rs); rs = null; SQLUtil.closeQuietly(ps); ps = null; } } LOG.ok("initResponsibilities done"); } /** * @return the boolean value */ private boolean getDescriptionExiests() { final String sql = "select user_id, description from " + getCfg().app() + "fnd_user_resp_groups_direct where USER_ID = '9999999999'"; PreparedStatement ps = null; ResultSet res = null; try { ps = getConn().prepareStatement(sql); res = ps.executeQuery(); getConn().commit(); LOG.ok("description exists"); return true; } catch (SQLException e) { // LOG.error(e, sql); LOG.ok("description does not exists"); } finally { SQLUtil.closeQuietly(res); res = null; SQLUtil.closeQuietly(ps); ps = null; } return false; } /** * We double check that the AccountsIncluded clause is valid. */ private void validateAccountsIncluded() { final String sql = "SELECT 1 FROM " + getCfg().app() + "fnd_user"; String testSql = OracleERPUtil.whereAnd(sql, getCfg().getAccountsIncluded()); PreparedStatement ps = null; ResultSet res = null; try { ps = getConn().prepareStatement(testSql); res = ps.executeQuery(); getConn().commit(); LOG.ok("accountsIncluded are ok"); } catch (SQLException e) { LOG.error(e, testSql); throw new IllegalArgumentException(getCfg().getMessage(MSG_INVALID_ACCOUNT_INCLUDED, getCfg().getAccountsIncluded())); } finally { SQLUtil.closeQuietly(res); SQLUtil.closeQuietly(ps); } } /** * The New responsibility format there. */ private boolean getNewResponsibilityViews() { final String sql = "select * from " + getCfg().app() + "fnd_views where VIEW_NAME = 'FND_USER_RESP_GROUPS_DIRECT' and APPLICATION_ID = '0'"; PreparedStatement ps = null; ResultSet res = null; try { ps = getConn().prepareStatement(sql); res = ps.executeQuery(); if (res != null && res.next()) { getConn().commit(); LOG.ok("newResponsibilityViews: true"); return true; } getConn().commit(); } catch (SQLException e) { LOG.error(e, sql); SQLUtil.rollbackQuietly(getConn()); throw ConnectorException.wrap(e); } finally { SQLUtil.closeQuietly(res); res = null; SQLUtil.closeQuietly(ps); ps = null; } LOG.ok("newResponsibilityViews: false"); return false; } /** * Check alive method. */ public void checkAlive() { LOG.ok("checkAlive"); getConn().test(); } /** * Validate the get user after script. * * @param userAfterAction * the script */ private void validateGetUserAfterActionScript(Script userAfterAction) { if (userAfterAction == null || StringUtil.isBlank(userAfterAction.getScriptLanguage()) || StringUtil.isBlank(userAfterAction.getScriptText())) { return; } try { final String scriptText = userAfterAction.getScriptText(); final ClassLoader loader = getClass().getClassLoader(); final String scriptLanguage = userAfterAction.getScriptLanguage(); LOG.ok("validateGetUserAfterActionScript: {0}", scriptText); final ScriptExecutorFactory scriptExFact = ScriptExecutorFactory.newInstance(scriptLanguage); // Compile the script scriptExFact.newScriptExecutor(loader, scriptText, true); } catch (Exception e) { LOG.error(e, "error in script"); throw ConnectorException.wrap(e); } } }