Desarrollo de scripts personalizados para tablas de aplicación de base de datos (MySQL) mediante Groovy

Visión general de scripts personalizados para tablas de aplicación de base de datos (MySQL)

Al aprovisionar cuentas desde Oracle Access Governance mediante la integración de tablas de aplicación de base de datos, las operaciones como crear, actualizar y suprimir se implantan mediante el código proporcionado por defecto. En las ocasiones en las que desee modificar las operaciones proporcionadas por defecto, puede proporcionar opcionalmente sus propios scripts personalizados que implanten sus propios requisitos de operación de aprovisionamiento específicos. Este paso es completamente opcional, no tiene que crear scripts personalizados si las operaciones por defecto le proporcionan lo que necesita. Puede agregar scripts personalizados a cualquier operación admitida. Si selecciona scripts personalizados, solo tendrá que agregarlos cuando necesite que se modifique la operación por defecto, puede tener una combinación de scripts personalizados y por defecto para las operaciones soportadas, aunque solo puede tener una u otra opción para cada operación específica. Por ejemplo, la operación de creación se puede implantar con un script personalizado que agrega alguna funcionalidad específica a su organización, mientras que la operación de supresión no cambia y utiliza la funcionalidad por defecto.

Una vez que haya implantado y configurado las tablas de aplicación de base de datos para que utilicen un script personalizado, ese script se utilizará la siguiente vez que realice una operación de aprovisionamiento o carga de datos.
Nota

Cualquier script personalizado se debe implantar con formato Groovy. No se admiten otros formatos de secuencias de comandos.
Al crear un sistema orquestado de tablas de aplicación de base de datos, puede identificar los scripts que se van a ejecutar para una serie de operaciones de aprovisionamiento en la aplicación de base de datos que contienen datos de cuenta. Estas operaciones son:
  • Crear
  • Actualizar
  • Suprimir
  • Carga de datos
  • Agregar Datos de Relación
  • Eliminar Datos de Relación
Estos scripts se deben ubicar en el host del agente, en el directorio de instalación del agente, por ejemplo, /app/<custom script> . El agente se configura con la ubicación de los scripts en los valores de integración del sistema orquestado. Debe asegurarse de que el usuario del sistema operativo que ejecuta el agente tenga permisos de lectura/escritura para cualquier script personalizado.
Al realizar una tarea de aprovisionamiento, el script se ejecutará como una sustitución del procesamiento estándar asociado a la tarea. El script debe manejar la tarea de aprovisionamiento por defecto, como crear o actualizar, y también puede tener tareas personalizadas más allá del proceso de aprovisionamiento por defecto, como:
  • Realizar actualizaciones de tablas personalizadas
  • Auditoría personalizada
  • Enviar notificaciones personalizadas
Esto significa que tiene dos opciones para el procesamiento de aprovisionamiento mediante la integración de tablas de aplicación de base de datos:
  1. Utilizar la lógica por defecto proporcionada con el conector de tablas de aplicación de base de datos
  2. Utilizar la lógica personalizada implantada en los scripts
Los scripts personalizados solo se utilizan cuando se configuran en el sistema orquestado. Por lo tanto, si ha especificado un script de creación al crear el sistema orquestado, pero no hay ningún script para la actualización, el script personalizado se utilizará para la tarea de creación de aprovisionamiento, mientras que la tarea de actualización se implementará mediante el procesamiento del conector por defecto.

También debe tener en cuenta que todos los tipos de scripts personalizados son compatibles con un sistema orquestado configurado para el modo de sistema gestionado. El único tipo de secuencia de comandos admitido para el modo de origen autorizado es el tipo de carga de datos, que se admite para ambos modos.

Esquema de base de datos de ejemplo

Los ejemplos proporcionados en las siguientes secciones se basan en las tablas de base de datos que se describen en esta sección.

MYDBAT_PERSON

USE {dataBase};
 
CREATE TABLE MYDBAT_PERSON (
    USERID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    USERNAME VARCHAR(50) NOT NULL,
    FIRSTNAME VARCHAR(50),
    LASTNAME VARCHAR(50),
    EMAIL VARCHAR(50) NOT NULL,
    COUNTRYCODE VARCHAR(20),
    DESCRIPTION VARCHAR(50),
    SALARY DECIMAL(10, 2),
    JOININGDATE DATE,
    STATUS VARCHAR(50),
    LASTUPDATED TIMESTAMP(6),
    PASSWORD VARCHAR(50));

MYDBAT_GROUPS

USE {dataBase};
 
CREATE TABLE MYDBAT_GROUPS (
    GROUPID VARCHAR(20) NOT NULL,
    GROUPNAME VARCHAR(20) NOT NULL,
    PRIMARY KEY (GROUPID));

MYDBAT_ROLES

USE {dataBase};
 
CREATE TABLE MYDBAT_ROLES (
    ROLEID VARCHAR(50) NOT NULL PRIMARY KEY,
    ROLENAME VARCHAR(50) NOT NULL);

MYDBAT_PERSON_GROUP

USE {dataBase};
 
CREATE TABLE MYDBAT_PERSON_GROUP(
    USERID INT NOT NULL,
    GROUPID VARCHAR(20) NOT NULL,
    PRIMARY KEY (USERID,GROUPID));

ALTER TABLE DBAT_PERSON_GROUP
ADD CONSTRAINT FK_USERID
FOREIGN KEY (USERID) REFERENCES DBAT_PERSON(USERID);

MYDBAT_PERSON_ROLE

USE {dataBase};
 
CREATE TABLE MYDBAT_PERSON_ROLE(
    USERID INT NOT NULL,
    ROLEID VARCHAR(20) NOT NULL,
    PRIMARY KEY (USERID,ROLEID));

ALTER TABLE MYDBAT_PERSON_ROLE
ADD CONSTRAINT FK_USERIDROLE
FOREIGN KEY (USERID) REFERENCES DBAT_PERSON(USERID);

MYDBAT_COUNTRY

USE {dataBase};
 
CREATE TABLE MYDBAT_COUNTRY(
    COUNTRYCODE VARCHAR(20) NOT NULL,
    COUNTRYNAME VARCHAR(20) NOT NULL,
    PRIMARY KEY (COUNTRYCODE)
);
Nota

Las tablas secundarias, como mydbat_roles, mydbat_groups y mydbat_country, deben tener definida una restricción de clave primaria. Si no se define ninguna clave primaria para las tablas secundarias, la operación de validación fallará y verá el error Key for table <tablename> are not defined.

Argumentos de script Groovy

Los siguientes argumentos se pueden utilizar en los scripts de Groovy:

Argumentos de Script
Argumento Descripción
conector Objeto de conector de tablas de aplicación de base de datos.
tiempo

Cuando se llama al guión de Groovy. El atributo de tiempo también explica el tipo de operación que se está realizando. Por ejemplo, si se trata de una operación de búsqueda, también se devuelve la clase de objeto que se está buscando.

A continuación se muestra el formato del argumento de tiempo para la sincronización de campos de consulta:
executeQuery:OBJECT_CLASS
En este formato, OBJECT_CLASS se sustituye por el tipo de objeto que se está conciliando.
Por ejemplo, para un trabajo programado de sincronización de campo de consulta que contiene el tipo de objeto Rol, el valor del argumento de tiempo será el siguiente:
executeQuery:Role
atributos Todos los atributos.
rastreo Registrador como puente de rastreo de script a la aplicación
donde Cadena en la que la condición para ejecutar la consulta o es nula.
manejador resultSetHandler o SyncResultsHandler para los objetos de conector producidos por la consulta de ejecución, la operación de sincronización o la devolución nula.
ofertas Tipo de oferta de nombre de tabla que se va a utilizar en SQL. El valor por defecto es una cadena vacía. El valor de este argumento se obtiene de la configuración de integración.
nativeTimestamps Especifica si el script recupera los datos de registro de hora de las columnas como tipo java.sql.Timestamp de la tabla de base de datos. Esta información se obtiene de la configuración de integración.
allNative Especifica si el script debe recuperar el tipo de dato de las columnas en un formato nativo de la tabla de base de datos. El valor de este argumento se obtiene de la configuración de integración. El valor de este argumento especifica si el script debe devolver excepciones cuando se encuentra un código de error cero (0x00).
enableEmptyString Especifica si se debe activar la compatibilidad para escribir una cadena vacía en lugar de un valor NULL. El valor de este argumento se obtiene de la configuración de integración.
filterString Condición de filtro de cadena para la consulta de ejecución o nula.
filterParams Lista de parámetros de filtro. Cada parámetro está presente en el formato COLUMN_NAME:VALUE. Por ejemplo, FIRSTNAME:test.
sincronizar Nombre de la columna de base de datos configurada para la conciliación incremental. Este argumento está disponible en el script de sincronización, que se llama durante una ejecución de conciliación incremental.
sincronizado Valor del atributo de sincronización. Este argumento está disponible en el script de sincronización.

Ejemplo de script de carga de datos

El script de carga de datos lee los datos de todas las tablas de todas las entidades definidas. En este escenario, la carga de datos de término hace referencia a la carga de datos completa y a la carga de datos de consulta.

Este script de ejemplo lee los datos de usuario de la tabla MYDBAT_PERSON y los datos de relación de los usuarios de las tablas MYDABAT_PERSON_ROLE y MYDBAT_PERSON_GROUP. Los datos de derechos se leen en la tabla MYDBAT_GROUPS y los datos de consulta se leen en la tabla MYDBAT_COUNTRY. También soporta una búsqueda de filtros básica en la tabla MYDBAT_PERSON. Todas estas lecturas de datos se realizan mediante procedimientos almacenados.

Script de carga de datos

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.identityconnectors.framework.common.objects.*;
import org.identityconnectors.common.security.GuardedString;
 
ResultSet rs = null;
CallableStatement st = null;
 
try {
    String ocName = "";
    if (timing != "") {
        trace.info("[Execute Query] timing attribute value: " + timing);
        ocName = timing.split(":")[1];
    }
 
    trace.info("[Execute Query] for objectClass: " + ocName);
 
    if (ocName.equals("ACCOUNT") || ocName.equals("TARGETACCOUNT")) {
        if (filterString != "") {
            trace.info("[Execute Query] Performing Recon with Filter. Filter is: " + filterString + " And Filter Params are: " + filterParams);
            // Example: Filter is MYDBAT_PERSON.USERID = ? And Filter Params are [MYDBAT_PERSON.USERID:21]
            String[] filter = filterParams.get(0).split(":");
            st = conn.prepareCall("{call EXECUTE_QUERY_WITH_FILTER(?, ?)}");
            st.setString(1, filter[0]); // Column name (e.g., MYDBAT_PERSON.USERID)
            st.setInt(2, Integer.parseInt(filter[1])); // Value to filter (e.g., 21)
        } else {
            trace.info("[Execute Query] Performing Full Recon.");
            st = conn.prepareCall("{call EXECUTE_QUERY_PERSON()}");
        }
 
        // Execute the procedure and get the ResultSet
        rs = st.executeQuery(); // No need to register OUT parameter
        SimpleDateFormat targetFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss z");
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
 
        while (rs.next()) {
            ConnectorObjectBuilder cob = new ConnectorObjectBuilder();
            cob.setObjectClass(ObjectClass.ACCOUNT);
 
            Attribute fname = AttributeBuilder.build("FIRSTNAME", rs.getString("FIRSTNAME"));
            Attribute lname = AttributeBuilder.build("LASTNAME", rs.getString("LASTNAME"));
            Attribute uid = AttributeBuilder.build("__UID__", rs.getString("USERID"));
            Attribute name = AttributeBuilder.build("__NAME__", rs.getString("USERNAME"));
            Attribute email = AttributeBuilder.build("EMAIL", rs.getString("EMAIL"));
            Attribute description = AttributeBuilder.build("DESCRIPTION", rs.getString("DESCRIPTION"));
 
            Date dbDate = rs.getDate("JOININGDATE");
            String joinDateStr = null;
            Long joinDate = null;
            if (dbDate != null) {
                java.util.Date date = df.parse(dbDate.toString());
                joinDateStr = targetFormat.format(date);
                joinDate = date.getTime();
                trace.info("date: " + date + " ---- joinDate: " + joinDate);
            }
 
            if (joinDate != null) {
                trace.info("Setting joinDate: " + joinDate);
                Attribute joindate = AttributeBuilder.build("JOININGDATE", joinDate);
                cob.addAttribute(joindate);
            }
 
            Attribute status = AttributeBuilder.build("STATUS", rs.getString("STATUS"));
            Attribute countryCode = AttributeBuilder.build("COUNTRYCODE", rs.getString("COUNTRYCODE"));
 
            cob.addAttribute(fname);
            cob.addAttribute(lname);
            cob.addAttribute(uid);
            cob.addAttribute(name);
            cob.addAttribute(email);
            cob.addAttribute(description);
            cob.addAttribute(status);
            cob.addAttribute(countryCode);
 
            if (!handler.handle(cob.build())) return;
        }
    } else if (ocName.equals("DBAT_COUNTRY")) {
        trace.info("[Execute Query] for Lookup: " + ocName);
        CallableStatement countryStmt = conn.prepareCall("{call GET_COUNTRIES()}");
        rs = countryStmt.executeQuery();
 
        while (rs.next()) {
            ConnectorObjectBuilder cob = new ConnectorObjectBuilder();
            cob.setObjectClass(new ObjectClass("DBAT_COUNTRY"));
            Attribute groupId = AttributeBuilder.build("__UID__", rs.getString(1));
            Attribute groupName = AttributeBuilder.build("__NAME__", rs.getString(2));
            cob.addAttribute(groupId);
            cob.addAttribute(groupName);
            if (!handler.handle(cob.build())) return;
        }
 
        rs.close();
        countryStmt.close();
    } else if (ocName.equals("DBAT_GROUPS")) {
        trace.info("[Execute Query] for Entitlement: " + ocName);
        CallableStatement groupStmt = conn.prepareCall("{call GET_GROUPS()}");
        rs = groupStmt.executeQuery();
 
        while (rs.next()) {
            ConnectorObjectBuilder cob = new ConnectorObjectBuilder();
            cob.setObjectClass(new ObjectClass("DBAT_GROUPS"));
            Attribute groupId = AttributeBuilder.build("__UID__", rs.getString(1));
            Attribute groupName = AttributeBuilder.build("__NAME__", rs.getString(2));
            cob.addAttribute(groupId);
            cob.addAttribute(groupName);
            if (!handler.handle(cob.build())) return;
        }
 
        rs.close();
        groupStmt.close();
    }else if (ocName.equals("DBAT_ROLES")) {
        trace.info("[Execute Query] for Entitlement: " + ocName);
        CallableStatement groupStmt = conn.prepareCall("{call GET_ROLES()}");
        rs = groupStmt.executeQuery();
 
        while (rs.next()) {
            ConnectorObjectBuilder cob = new ConnectorObjectBuilder();
            cob.setObjectClass(new ObjectClass("DBAT_ROLESS"));
            Attribute groupId = AttributeBuilder.build("__UID__", rs.getString(1));
            Attribute groupName = AttributeBuilder.build("__NAME__", rs.getString(2));
            cob.addAttribute(groupId);
            cob.addAttribute(groupName);
            if (!handler.handle(cob.build())) return;
        }
 
        rs.close();
        groupStmt.close();
    }
} finally {
    if (rs != null) rs.close();
    if (st != null) st.close();
}

Procedimiento Almacenado: Cargar Usuarios

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE EXECUTE_QUERY_PERSON()
BEGIN
  SELECT USERID,
         FIRSTNAME,
         LASTNAME,
         EMAIL,
         DESCRIPTION,
         SALARY,
         JOININGDATE,
         STATUS,
         COUNTRYCODE,
         USERNAME
  FROM MYDBAT_PERSON;
END //
DELIMITER ;

Procedimiento almacenado: búsqueda de usuarios filtrados

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE EXECUTE_QUERY_WITH_FILTER(
  IN filter VARCHAR(255),
  IN filterValue int
)
BEGIN
  SET @sql_query = CONCAT(
    'SELECT USERID,
            FIRSTNAME,
            LASTNAME,
            EMAIL,
            DESCRIPTION,
            SALARY,
            JOININGDATE,
            STATUS,
            COUNTRYCODE,
            USERNAME ',
    'FROM MYDBAT_PERSON WHERE ', filter, ' = ?'
  );
 
  PREPARE stmt FROM @sql_query;
  SET @filter_value = filterValue;
   
  EXECUTE stmt USING @filter_value;
   
  DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
Este es un ejemplo muy básico de búsqueda de filtros con una sola condición de filtro, por ejemplo, MYDBAT_PERSON.USERID:21. Se utiliza específicamente para el procesamiento de writeBack después de la operación de creación

Procedimiento Almacenado: Obtener Roles

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE GET_ROLES()
BEGIN
  SELECT ROLEID,
         ROLENAME
  FROM MYDBAT_ROLES;
END //
DELIMITER ;

Procedimiento Almacenado: Obtener Roles de Usuario

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE GET_USERROLE(
  IN userin int
)
BEGIN
  SELECT USERID,
         ROLEID,
         FROMDATE,
         TODATE
  FROM MYDBAT_PERSON_ROLE
  WHERE USERID = userin;
END //
DELIMITER ;

Procedimiento Almacenado: Obtener Grupos

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE GET_GROUPS()
BEGIN
  SELECT GROUPID,
         GROUPNAME
  FROM MYDBAT_GROUPS;
END //
DELIMITER ;

Procedimiento Almacenado: Obtener Grupos de Usuarios

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE GET_USERGROUP(
  IN userin int
)
BEGIN
  SELECT USERID,
         GROUPID
  FROM MYDBAT_PERSON_GROUP
  WHERE USERID = userin;
END //
DELIMITER ;

Procedimiento Almacenado: Obtener Consultas (País)

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE GET_COUNTRIES()
BEGIN
  SELECT COUNTRYCODE,
         COUNTRYNAME
  FROM MYDBAT_COUNTRY;
END //
DELIMITER ;

Script de creación de muestra

Este script se llama durante el aprovisionamiento de una nueva cuenta desde Oracle Access Governance. Aquí estamos insertando datos en la tabla MYDBAT_PERSON.

Crear script

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.CallableStatement;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.common.objects.*;
 
trace.info("[Create-Groovy] Attributes::" + attributes);
 
// Get all the attributes from script argument
GuardedString pass = attributes.get("__PASSWORD__") != null ? attributes.get("__PASSWORD__").getValue().get(0) : null;
String uname = attributes.get("__NAME__") != null ? attributes.get("__NAME__").getValue().get(0) : null;
boolean enableValue = attributes.get("__ENABLE__") != null ? attributes.get("__ENABLE__").getValue().get(0) : true;
String email = attributes.get("EMAIL") != null ? attributes.get("EMAIL").getValue().get(0) : null;
String first = attributes.get("FIRSTNAME") != null ? attributes.get("FIRSTNAME").getValue().get(0) : null;
String last = attributes.get("LASTNAME") != null ? attributes.get("LASTNAME").getValue().get(0) : null;
String desc = attributes.get("DESCRIPTION") != null ? attributes.get("DESCRIPTION").getValue().get(0) : null;
Object salary = attributes.get("SALARY") != null ? attributes.get("SALARY").getValue().get(0) : null; // Changed to Object
String countryCode = attributes.get("COUNTRYCODE") != null ? attributes.get("COUNTRYCODE").getValue().get(0) : null;
Object joiningdate = attributes.get("JOININGDATE") != null ? attributes.get("JOININGDATE").getValue().get(0) : null; // Changed to Object
 
// Prepare callable statement for the stored procedure
CallableStatement createStmt = null;
 
try {
    // Prepare the SQL statement to call the stored procedure
    createStmt = conn.prepareCall("{CALL ADD_PERSON(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}");
 
    // Set the input parameters for the stored procedure
    createStmt.setString(1, uname);    // USERNAME
    createStmt.setString(2, first);    // FIRSTNAME
    createStmt.setString(3, last);     // LASTNAME
    createStmt.setString(4, email);    // EMAIL
    createStmt.setString(5, countryCode); // COUNTRYCODE
    createStmt.setString(6, desc);     // DESCRIPTION
 
    // Handling SALARY: Ensure it's numeric or set as NULL
    if (salary != null && salary instanceof String) {
        try {
            createStmt.setBigDecimal(9, new BigDecimal((String) salary)); // Parse to BigDecimal
        } catch (NumberFormatException e) {
            trace.error("[Create-Groovy] Invalid SALARY format: " + salary);
            createStmt.setNull(9, java.sql.Types.DECIMAL); // Set NULL if invalid
        }
    } else {
        createStmt.setNull(9, java.sql.Types.DECIMAL); // NULL for SALARY if not provided
    }
 
    // Handling JOININGDATE: Convert from long to MySQL DATE format
    if (joiningdate != null) {
        if (joiningdate instanceof Long) {
            // Convert long to java.util.Date
            Date dateObj = new Date((Long) joiningdate);
            // Format the date to 'yyyy-MM-dd'
            SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
            String formattedDate = dateFormatter.format(dateObj);
            createStmt.setString(8, formattedDate); // Set the formatted date
        } else {
            trace.error("[Create-Groovy] Invalid JOININGDATE format: Expected Long but got " + joiningdate.getClass());
            createStmt.setNull(8, java.sql.Types.DATE); // Set NULL if the format is invalid
        }
    } else {
        createStmt.setNull(8, java.sql.Types.DATE); // NULL for JOININGDATE if not provided
    }
 
    // STATUS: ACTIVE or INACTIVE
    if (enableValue) {
        createStmt.setString(7, "ACTIVE"); // STATUS
    } else {
        createStmt.setString(7, "INACTIVE"); // STATUS
    }
 
    // PASSWORD Handling
    if (pass != null) {
        pass.access(new GuardedString.Accessor() {
            public void access(char[] clearChars) {
                createStmt.setString(10, new String(clearChars)); // PASSWORD
            }
        });
    } else {
        createStmt.setString(10, null); // NULL for PASSWORD if not provided
    }
 
    // The output parameter for USERID (generated by the stored procedure)
    createStmt.registerOutParameter(11, java.sql.Types.VARCHAR);
 
    // Execute the stored procedure
    createStmt.executeUpdate();
 
    // Retrieve the generated USERID (either auto-increment or UUID)
    String generatedUserId = createStmt.getString(11); // Get the output parameter (USERID)
    trace.info("[Create] Created User with USERID::" + generatedUserId);
 
    // Return the generated USERID as Uid
    return new Uid(generatedUserId);
 
} catch (Exception e) {
    trace.error("[Create-Groovy] Error during user creation: " + e.getMessage());
    throw e;  // Re-throw exception to signal failure
} finally {
    // Clean up resources
    if (createStmt != null) {
        createStmt.close();
    }
}

Crear procedimiento almacenado de cuenta

DELIMITER $$
  
CREATE PROCEDURE ADD_PERSON (
    IN USERNAME VARCHAR(50),
    IN FIRSTNAME VARCHAR(50),
    IN LASTNAME VARCHAR(50),
    IN EMAIL VARCHAR(50),
    IN COUNTRYCODE VARCHAR(20),
    IN DESCRIPTION VARCHAR(50),
    IN STATUS VARCHAR(50),
    IN JOININGDATE DATE,
    IN SALARY DECIMAL(10,2),
    IN PASSWORD VARCHAR(50),
    OUT USERID VARCHAR(50)
)
BEGIN
    DECLARE generated_user_id VARCHAR(50);
    DECLARE is_auto_increment VARCHAR(50);  -- Change to VARCHAR to hold string values like 'auto_increment'
  
    -- Check if USERID column has the 'auto_increment' flag in the EXTRA column
    SELECT EXTRA
    INTO is_auto_increment
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = 'MYDBAT_PERSON'
      AND COLUMN_NAME = 'USERID'
      AND TABLE_SCHEMA = DATABASE();
  
    -- Check if 'auto_increment' is present in the EXTRA column
    IF is_auto_increment LIKE '%auto_increment%' THEN
        -- If USERID is auto-increment
        INSERT INTO MYDBAT_PERSON (
            USERNAME, FIRSTNAME, LASTNAME, EMAIL, COUNTRYCODE, DESCRIPTION, STATUS, JOININGDATE, SALARY, PASSWORD
        )
        VALUES (
            USERNAME, FIRSTNAME, LASTNAME, EMAIL, COUNTRYCODE, DESCRIPTION, STATUS, JOININGDATE, SALARY, PASSWORD
        );
        -- Retrieve the auto-generated USERID and cast it to VARCHAR
        SET USERID = CAST(LAST_INSERT_ID() AS CHAR);
    ELSE
        -- If USERID is NOT auto-increment, generate a UUID for USERID
        SET generated_user_id = UUID();
        -- Insert the record with the generated UUID
        INSERT INTO MYDBAT_PERSON (
            USERID, USERNAME, FIRSTNAME, LASTNAME, EMAIL, COUNTRYCODE, DESCRIPTION, STATUS, JOININGDATE, SALARY, PASSWORD
        )
        VALUES (
            generated_user_id, USERNAME, FIRSTNAME, LASTNAME, EMAIL, COUNTRYCODE, DESCRIPTION, STATUS, JOININGDATE, SALARY, PASSWORD
        );
        -- Set the generated UUID in the output, as a VARCHAR
        SET USERID = generated_user_id;
    END IF;
END$$
  
DELIMITER ;

Este procedimiento almacenado es una implementación de ejemplo para crear un usuario en la base de datos. El script comprueba si la columna USERID de la tabla MYDBAT_PERSON tiene un juego de incrementos automáticos, lo que significa que el identificador de usuario se rellena automáticamente. Si se define el aumento automático, el usuario se crea mediante una sentencia SQL sin el identificador de usuario, ya que la base de datos lo define automáticamente. Si no se define el aumento automático, el usuario se crea mediante una sentencia SQL que genera el identificador de usuario y lo inserta en la tabla MYDBAT_PERSON. Dado que la implementación de USERID puede variar en diferentes implementaciones, este procedimiento almacenado debe ajustarse a sus requisitos específicos.

Script secundario de adición de muestra

Este script se llama durante el aprovisionamiento de derechos/permisos a usuarios de Oracle Access Governance. Aquí estamos insertando datos en las tablas MYDBAT_PERSON_GROUP y MYDBAT_PERSON_ROLE.

Agregar script secundario

import org.identityconnectors.framework.common.objects.*
import java.text.*
 
trace.info("[addMultiValuedAttributeScript-Groovy] Adding Child data::" + attributes)
childst = null
try {
    // Adding Group data
    childDataEOSet = null
     
    // Logic for handling simple multi-valued attributes
    if (attributes.get("MYDBAT_PERSON_GROUP") != null) {
        childDataEOSet = attributes.get("MYDBAT_PERSON_GROUP").getValue()
        childst = conn.prepareStatement("INSERT INTO dbat.MYDBAT_PERSON_GROUP (USERID, GROUPID) VALUES (?, ?)")
        int id = attributes.get("__UID__").getValue().get(0).toInteger()
         
        if (childDataEOSet != null) {
            trace.info("[addMultiValuedAttributeScript] Adding Group data.")
            // Iterate through child data and insert into table
            for (iterator = childDataEOSet.iterator(); iterator.hasNext(); ) {
                eo = iterator.next()
                attrsSet = eo.getAttributes()
                grpattr = AttributeUtil.find("GROUPID", attrsSet)
                 
                if (grpattr != null) {
                    // Extract group ID and insert record
                    groupid = grpattr.getValue().get(0)
                    childst.setInt(1, id)
                    childst.setString(2, groupid)
                    childst.executeUpdate()
                    childst.clearParameters()
                }
            }
        }
    }
} finally {
    if (childst != null)
        childst.close()
}
 
try {
    childDataEOSet = null
    // Logic for handling complex multi-valued attributes
    if (attributes.get("MYDBAT_PERSON_ROLE") != null) {
        childDataEOSet = attributes.get("MYDBAT_PERSON_ROLE").getValue()
        childst = conn.prepareStatement("INSERT INTO dbat.MYDBAT_PERSON_ROLE (USERID, ROLEID) VALUES (?, ?)")
         
        int id = attributes.get("__UID__").getValue().get(0).toInteger()
         
        if (childDataEOSet != null) {
            trace.info("[addMultiValuedAttributeScript] Adding Role data.")
            for (iterator = childDataEOSet.iterator(); iterator.hasNext(); ) {
                eo = iterator.next()
                attrsSet = eo.getAttributes()
                roleattr = AttributeUtil.find("ROLEID", attrsSet)
                 
                if (roleattr != null) {
                    // Extract role ID and insert record
                    roleid = roleattr.getValue().get(0)
                    childst.setInt(1, id)
                    childst.setString(2, roleid)
                     
                    childst.executeUpdate()
                    childst.clearParameters()
                }
            }
        }
    }
} finally {
    if (childst != null)
        childst.close()
}

Script secundario de eliminación de muestra

Este script se llama al anular el aprovisionamiento de derechos/permisos de los usuarios de Oracle Access Governance. Aquí eliminamos datos de las tablas MYDBAT_PERSON_GROUP y MYDBAT_PERSON_ROLE mediante procedimientos almacenados.

Eliminar script secundario

import org.identityconnectors.framework.common.objects.*
 
trace.info("[removeMultiValuedAttributeScript] Removing Child data::" + attributes)
 
try {
    childDataEOSet = null
    delSt = null
    // Get UID and convert to int
    int id = Integer.parseInt(attributes.get("__UID__").getValue().get(0))
     
    // Handle removal of person group data
    if (attributes.get("MYDBAT_PERSON_GROUP") != null) {
        childDataEOSet = attributes.get("MYDBAT_PERSON_GROUP").getValue()
         
        // Call the MySQL stored procedure
        delSt = conn.prepareCall("{CALL DELETE_USERGROUP(?, ?)}")
         
        if (childDataEOSet != null) {
            trace.info("[removeMultiValuedAttributeScript] Removing Group data.")
            // Iterate through child data and delete
            for (iterator = childDataEOSet.iterator(); iterator.hasNext(); ) {
                eo = iterator.next()
                attrsSet = eo.getAttributes()
                grpattr = AttributeUtil.find("GROUPID", attrsSet)
                 
                if (grpattr != null) {
                    groupid = grpattr.getValue().get(0)
                    delSt.setInt(1, id) // Use setInt for integer ID
                    delSt.setString(2, groupid)
                    delSt.executeUpdate()
                    trace.info("[removeMultiValuedAttributeScript] Deleted Group::" + groupid)
                }
            }
        }
    }
} finally {
    if (delSt != null)
        delSt.close()
}
 
try {
    childDataEOSet = null
    delSt = null
    // Get UID and convert to int
    int id = Integer.parseInt(attributes.get("__UID__").getValue().get(0))
     
    // Handle removal of person role data
    if (attributes.get("MYDBAT_PERSON_ROLE") != null) {
        childDataEOSet = attributes.get("MYDBAT_PERSON_ROLE").getValue()
         
        // Call the MySQL stored procedure
        delSt = conn.prepareCall("{CALL DELETE_USERROLE(?, ?)}")
         
        if (childDataEOSet != null) {
            trace.info("[removeMultiValuedAttributeScript] Removing Role data.")
            for (iterator = childDataEOSet.iterator(); iterator.hasNext(); ) {
                eo = iterator.next()
                attrsSet = eo.getAttributes()
                roleattr = AttributeUtil.find("ROLEID", attrsSet)
                 
                if (roleattr != null) {
                    rolename = roleattr.getValue().get(0)
                    delSt.setInt(1, id) // Use setInt for integer ID
                    delSt.setString(2, rolename)
                    delSt.executeUpdate()
                    trace.info("[removeMultiValuedAttributeScript] Deleted Role::" + rolename)
                }
            }
        }
    }
} finally {
    if (delSt != null)
        delSt.close()
}

Procedimiento almacenado: Eliminar secundario

Suprimir rol de usuario
DELIMITER $$
  
CREATE PROCEDURE DELETE_USERROLE (
    IN input_userid INT,
    IN input_roleid VARCHAR(20)
)
BEGIN
    -- Check if the record exists before attempting deletion
    IF EXISTS (
        SELECT 1
        FROM MYDBAT_PERSON_ROLE
        WHERE USERID = input_userid AND ROLEID = input_roleid
    ) THEN
        -- Perform the deletion
        DELETE FROM MYDBAT_PERSON_ROLE
        WHERE USERID = input_userid AND ROLEID = input_roleid;
    ELSE
        -- If no record exists, signal an error or do nothing
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'The specified USERID and ROLEID combination does not exist in MYDBAT_PERSON_ROLE.';
    END IF;
END$$
  
DELIMITER ;
Suprimir grupo de usuarios
DELIMITER $$
  
CREATE PROCEDURE DELETE_USERGROUP (
    IN input_userid INT,
    IN input_groupid VARCHAR(20)
)
BEGIN
    -- Check if the record exists before attempting deletion
    IF EXISTS (
        SELECT 1
        FROM MYDBAT_PERSON_GROUP
        WHERE USERID = input_userid AND GROUPID = input_groupid
    ) THEN
        -- Perform the deletion
        DELETE FROM MYDBAT_PERSON_GROUP
        WHERE USERID = input_userid AND GROUPID = input_groupid;
    ELSE
        -- If no record exists, signal an error or do nothing
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'The specified USERID and GROUPID combination does not exist in MYDBAT_PERSON_GROUP.';
    END IF;
END$$
  
DELIMITER ;

Ejemplo de script de supresión

Este script se llama durante la revocación de una cuenta de Oracle Access Governance. Aquí se suprimen las tablas de relación de usuario de datos, MYDBAT_PERSON_ROLE y MYDBAT_PERSON_GROUP, así como los datos de la tabla MYDBAT_PERSON

Suprimir script

import java.sql.PreparedStatement;
import org.identityconnectors.framework.common.objects.*;
 
// Get the UID from the input map 'attributes'
String uid = attributes.get("__UID__").getValue().get(0);
trace.info("[Delete-Groovy] Deleting user:: " + uid);
 
try {
    // Delete data from child tables and then, main table
    // Delete user roles
    st = conn.prepareStatement("DELETE FROM dbat.MYDBAT_PERSON_ROLE WHERE userid=?");
    st.setString(1, uid);
    st.executeUpdate();
    st.close();
 
    // Delete user groups
    st = conn.prepareStatement("DELETE FROM dbat.MYDBAT_PERSON_GROUP WHERE userid=?");
    st.setString(1, uid);
    st.executeUpdate();
    st.close();
 
    // Delete user account
    st = conn.prepareStatement("DELETE FROM dbat.MYDBAT_PERSON WHERE userid=?");
    st.setString(1, uid);
    st.executeUpdate();
} finally {
    if (st != null)
        st.close();
};
 
trace.info("Deleted user:: " + uid);

Script de actualización de muestra

Este script se llama durante las operaciones de aprovisionamiento cuando la cuenta se actualiza desde Oracle Access Governance. Aquí estamos actualizando los datos de la tabla MYDBAT_PERSON

Actualizar script

import org.identityconnectors.framework.common.objects.*;
import java.text.*;
import org.identityconnectors.framework.common.exceptions.*;
import java.sql.*;
 
trace.info("[Update-Groovy] Attributes::" + attributes);
 
/** During an Update operation, AGCS sends the UID attribute along with updated attributes. Get all the values of attributes **/
String id = attributes.get("__UID__") != null ? attributes.get("__UID__").getValue().get(0) : null;
String firstName = attributes.get("FIRSTNAME") != null ? attributes.get("FIRSTNAME").getValue().get(0) : null;
String lastName = attributes.get("LASTNAME") != null ? attributes.get("LASTNAME").getValue().get(0) : null;
String email = attributes.get("EMAIL") != null ? attributes.get("EMAIL").getValue().get(0) : null;
String description = attributes.get("DESCRIPTION") != null ? attributes.get("DESCRIPTION").getValue().get(0) : null;
String salary = attributes.get("SALARY") != null ? attributes.get("SALARY").getValue().get(0) : null;
String joindate = attributes.get("JOININGDATE") != null ? attributes.get("JOININGDATE").getValue().get(0) : null;
Boolean enableValue = attributes.get("__ENABLE__") != null ? attributes.get("__ENABLE__").getValue().get(0) : true;
 
// Throw exception if uid is null
if (id == null) throw new ConnectorException("UID Cannot be Null");
 
PreparedStatement stmt = null;
try {
    // Create prepared statement to update the MYDBAT_PERSON table
    stmt = conn.prepareStatement("UPDATE dbat.MYDBAT_PERSON SET FIRSTNAME=IFNULL(?, FIRSTNAME), LASTNAME=IFNULL(?, LASTNAME), EMAIL=IFNULL(?, EMAIL), SALARY=IFNULL(?, SALARY), JOININGDATE=IFNULL(?, JOININGDATE), STATUS=IFNULL(?, STATUS) WHERE USERID =?");
 
    // Set SQL input parameters
    stmt.setString(1, firstName); // First name
    stmt.setString(2, lastName); // Last name
    stmt.setString(3, email);    // Email
 
    // Handle salary: Convert to BigDecimal if not null, otherwise set SQL NULL
    if (salary != null) {
        stmt.setBigDecimal(4, new BigDecimal(salary));
    } else {
        stmt.setNull(4, java.sql.Types.DECIMAL); // Set SQL NULL for salary
    }
 
    // Handle joindate: Convert to MySQL date format if not null
    String dateStr = null;
    if (joindate != null) {
        Date date = new Date(joindate);
        DateFormat targetFormat = new SimpleDateFormat("yyyy-MM-dd"); // MySQL date format
        dateStr = targetFormat.format(date);
    }
    stmt.setString(5, dateStr); // Joining date
 
    // Handle enable/disable status
    if (enableValue) {
        stmt.setString(6, "Enabled");
    } else {
        stmt.setString(6, "Disabled");
    }
 
    // Set UID for the WHERE condition
    stmt.setString(7, id);
 
    // Execute the update
    stmt.executeUpdate();
} finally {
    // Ensure the statement is closed to release resources
    if (stmt != null) stmt.close();
}
 
trace.info("[Update] Updated user::" + id);
return new Uid(id);