Développer des scripts personnalisés pour les tables d'application de base de données (MySQL) à l'aide de Groovy

Aperçu des scripts personnalisés pour les tables d'application de base de données (MySQL)

Lorsque vous provisionnez des comptes à partir d'Oracle Access Governance à l'aide de l'intégration des tables d'application de base de données, des opérations telles que la création, la mise à jour et la suppression sont mises en oeuvre à l'aide du code fourni par défaut. Dans les cas où vous souhaitez modifier les opérations fournies par défaut, vous pouvez éventuellement fournir vos propres scripts personnalisés qui mettent en œuvre vos propres exigences d'opération de provisionnement spécifiques. Cette étape est complètement facultative. Vous n'avez pas besoin de créer des scripts personnalisés si les opérations par défaut vous fournissent ce dont vous avez besoin. Vous pouvez ajouter des scripts personnalisés à toutes les opérations prises en charge. Si vous choisissez des scripts personnalisés, vous n'avez qu'à les ajouter lorsque vous avez besoin de modifier l'opération par défaut, vous pouvez avoir une combinaison de scripts personnalisés et de scripts par défaut pour les opérations prises en charge, bien que vous ne puissiez avoir qu'une seule option ou l'autre pour chaque opération spécifique. Par exemple, l'opération de création peut être mise en oeuvre à l'aide d'un script personnalisé qui ajoute certaines fonctionnalités propres à votre organisation, tandis que l'opération de suppression est inchangée et utilise la fonctionnalité par défaut.

Une fois que vous avez implémenté et configuré vos tables d'application de base de données pour utiliser un script personnalisé, ce script sera utilisé lors de la prochaine opération de provisionnement ou de chargement de données.
Note

Tout script personnalisé doit être mis en oeuvre au format Groovy. Les autres formats de script ne sont pas pris en charge.
Lorsque vous créez un système orchestré de tables d'application de base de données, vous pouvez identifier les scripts à exécuter pour un certain nombre d'opérations de provisionnement sur l'application de base de données contenant les données de compte. Ces opérations sont les suivantes :
  • Créer
  • Mise à jour
  • Suppression
  • Chargement de données
  • Ajouter des données de relation
  • Supprimer les données de relation
Ces scripts doivent être situés sur l'hôte de l'agent, dans le répertoire d'installation de l'agent, par exemple /app/<custom script> . Vous configurez l'agent en indiquant l'emplacement des scripts dans les paramètres d'intégration de votre système orchestré. Vous devez vous assurer que l'utilisateur du système d'exploitation qui exécute l'agent dispose des autorisations de lecture/écriture pour tous les scripts personnalisés.
Lorsque vous effectuez une tâche de provisionnement, votre script est exécuté en remplacement du traitement standard associé à la tâche. Le script doit gérer la tâche de provisionnement par défaut, telle que la création ou la mise à jour, et peut également comporter des tâches personnalisées au-delà du processus de provisionnement par défaut, telles que :
  • Effectuer des mises à jour de table personnalisée
  • Audit personnalisé
  • Envoyer des avis personnalisés
Cela signifie que vous disposez de deux options pour provisionner le traitement à l'aide de l'intégration des tables d'application de base de données :
  1. Utiliser la logique par défaut fournie avec le connecteur Database Application Tables
  2. Utiliser la logique personnalisée mise en oeuvre dans les scripts
Les scripts personnalisés ne sont utilisés que lorsqu'ils sont configurés dans votre système orchestré. Ainsi, si vous avez spécifié un script de création lors de la création de votre système orchestré, mais aucun script pour la mise à jour, le script personnalisé sera utilisé pour la tâche de provisionnement de création, tandis que la tâche de mise à jour sera mise en oeuvre à l'aide du traitement de connecteur par défaut.

Vous devez également noter que tous les types de script personnalisés sont pris en charge pour un système orchestré configuré pour le mode système géré. Le seul type de script pris en charge pour le mode source faisant autorité est le type de chargement de données, qui est pris en charge pour les deux modes.

Exemple de schéma de base de données

Les exemples fournis dans les sections suivantes sont basés sur les tables de base de données décrites dans cette section.

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)
);
Note

Une contrainte de clé primaire doit être définie pour les tables enfants telles que mydbat_roles, mydbat_groups et mydbat_country. Si aucune clé primaire n'est définie pour les tables enfants, l'opération de validation échoue et une erreur s'affiche : La clé de la table <nom_table> n'est pas définie.

Arguments de script Groovy

Les arguments suivants peuvent être utilisés dans vos scripts Groovy :

Arguments de script
Argument Description
connecteur Objet de connecteur Database Application Tables.
synchronisation

Lorsque le script Groovy est appelé. L'attribut timing explique également le type d'opération en cours. Par exemple, s'il s'agit d'une opération de recherche, la classe d'objet recherchée est également retournée.

Voici le format de l'argument de synchronisation pour la synchronisation des champs de consultation :
executeQuery:OBJECT_CLASS
Dans ce format, OBJECT_CLASS est remplacé par le type d'objet en cours de rapprochement.
Par exemple, pour une tâche programmée de synchronisation de champ de consultation qui contient le type d'objet Rôle, la valeur de l'argument de temporisation sera la suivante :
executeQuery:Role
attributs Tous les attributs.
trace Logger en tant que pont de trace de script vers l'application
Chaîne où la condition d'exécution de l'interrogation est nulle.
programme de traitement resultSetHandler ou SyncResultsHandler pour les objets de connecteur produits par l'interrogation d'exécution, l'opération de synchronisation ou le retour nul.
citation Type de guillemet de nom de table à utiliser dans SQL. La valeur par défaut est une chaîne vide. La valeur de cet argument est obtenue à partir des paramètres d'intégration.
nativeTimestamps Spécifie si le script extrait les données d'horodatage des colonnes en tant que type java.sql.Timestamp de la table de base de données. Ces informations sont obtenues à partir des paramètres d'intégration.
allNative Indique si le script doit extraire du tableau de base de données le type de données des colonnes dans un format natif. La valeur de cet argument est obtenue à partir des paramètres d'intégration. La valeur de cet argument spécifie si le script doit générer des exceptions lorsqu'un code d'erreur zéro (0x00) est détecté.
enableEmptyString Indique si la prise en charge de l'écriture d'une chaîne vide au lieu d'une valeur NULL doit être activée. La valeur de cet argument est obtenue à partir des paramètres d'intégration.
filterString Condition de filtre de chaîne pour exécuter l'interrogation, ou nulle.
filterParams Liste des paramètres de filtre. Chaque paramètre est présent dans le format COLUMN_NAME:VALUE. Par exemple, FIRSTNAME:test.
syncattribute Nom de la colonne de base de données configurée pour le rapprochement incrémentiel. Cet argument est disponible dans le script de synchronisation, appelé lors d'une exécution de rapprochement incrémentiel.
synctoken Valeur de l'attribut de synchronisation. Cet argument est disponible dans le script de synchronisation.

Exemple de script de chargement de données

Le script de chargement des données lit les données de toutes les tables pour toutes les entités définies. Dans ce scénario, le chargement des données du terme fait référence au chargement complet des données et au chargement des données de consultation.

Cet exemple de script lit les données d'utilisateur de la table MYDBAT_PERSON et les données de relation des utilisateurs des tables MYDABAT_PERSON_ROLE et MYDBAT_PERSON_GROUP. Les données de droits sont lues à partir de la table MYDBAT_GROUPS et les données de consultation sont lues à partir de la table MYDBAT_COUNTRY. Il prend également en charge une recherche de filtre de base sur la table MYDBAT_PERSON. Toutes ces lectures de données sont effectuées à l'aide de procédures stockées.

Script de chargement de données

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();
}

Procédure stockée : Charger les utilisateurs

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 ;

Procédure stockée : Recherche d'utilisateur filtrée

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 ;
Il s'agit d'un exemple très basique de recherche de filtre avec une seule condition de filtre, par exemple MYDBAT_PERSON.USERID :21. Utilisé spécifiquement pour le traitement writeBack après l'opération de création

Procédure stockée : Obtenir les rôles

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

Procédure stockée : Obtenir les rôles d'utilisateur

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 ;

Procédure stockée : Obtenir des groupes

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

Procédure stockée : Obtenir les groupes d'utilisateurs

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

Procédure stockée : Obtenir les consultations (pays)

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

Exemple de script de création

Ce script est appelé lors du provisionnement d'un nouveau compte à partir d'Oracle Access Governance. Ici, nous insérons des données dans la table MYDBAT_PERSON.

Script de création

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();
    }
}

Procédure de création de compte stocké

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 ;

Cette procédure stockée est un exemple d'implémentation permettant de créer un utilisateur dans la base de données. Le script vérifie si la colonne USERID de la table MYDBAT_PERSON a un jeu d'incréments automatiques, ce qui signifie que l'ID utilisateur est alimenté automatiquement. Si l'incrément automatique est défini, l'utilisateur est créé à l'aide d'une instruction SQL sans l'ID utilisateur, car il est défini automatiquement par la base de données. Si l'incrément automatique n'est pas défini, l'utilisateur est créé à l'aide d'un énoncé SQL qui génère l'ID utilisateur et l'insère dans la table MYDBAT_PERSON. Comme l'implémentation de USERID peut varier dans différentes implémentations, cette procédure stockée doit répondre à vos besoins spécifiques.

Exemple de script d'ajout enfant

Ce script est appelé lors du provisionnement des droits/autorisations aux utilisateurs à partir d'Oracle Access Governance. Ici, nous insérons des données dans les tables MYDBAT_PERSON_GROUP et MYDBAT_PERSON_ROLE.

Ajouter un script enfant

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()
}

Exemple de suppression de script enfant

Ce script est appelé lors du déprovisionnement des droits/autorisations des utilisateurs à partir d'Oracle Access Governance. Ici, nous supprimons les données des tables MYDBAT_PERSON_GROUP et MYDBAT_PERSON_ROLE à l'aide de procédures stockées.

Supprimer le script enfant

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()
}

Procédure stockée : Supprimer l'enfant

Supprimer le rôle d'utilisateur
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 ;
Supprimer le groupe d'utilisateurs
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 ;

Exemple de script de suppression

Ce script est appelé lors de la révocation d'un compte d'Oracle Access Governance. Ici, nous supprimons les tables de relation d'utilisateur de données, MYDBAT_PERSON_ROLE et MYDBAT_PERSON_GROUP, ainsi que les données de la table MYDBAT_PERSON

Supprimer le 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);

Exemple de script de mise à jour

Ce script est appelé lors des opérations de provisionnement lorsque le compte est mis à jour à partir d'Oracle Access Governance. Ici, nous mettons à jour les données dans le tableau MYDBAT_PERSON

Script de mise à jour

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);