Question marks '?' in JDBC rule after an account provisioning (Create Account)

I tried to implement this solution from ‘JDBC Provisioning rule to read the nativeIdentity that gets generated in the Database - #2 by AnamicaShroti’ to remove the ‘???’ signs after creating an account in a JDBC rule. The problem is that IDN gives me an error when trying to execute the code because the constructor doesn’t accept the parameters I’m sending to it. I’m not sure if the solution in that discussion still works or if I’m doing something wrong in the code. According to the documentation in SailPoint, the constructor is empty and shouldn’t accept parameters.

@lherrera can you share us your exact jdbc provisioning rule here, so that we can help?

It would definitely be easy to help you with the issue @lherrera if you can share the JDBC provisioning rule (Please do replace items which are sensitive within the code).

Additionally as a pre-check can you confirm on the following items:
i. Are you leveraging stored procedures?
ii. If yes does your stored procedure generates the nativeIdentity and is it returning the said nativeIdentity so that you can map it with the user?
iii. Correlation configuration; is it been taken care of when you have configured the source?


I modified and removed some unnecessary things, maybe some "if"s are not aligned, but the code for account creation would be this:

import sailpoint.object.ResourceObject;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import sailpoint.api.SailPointContext;
import sailpoint.connector.JDBCConnector;
import java.util.HashMap;
import java.util.Map;
import java.sql.ResultSet;
import sailpoint.object.Application;
import sailpoint.object.Identity;
import sailpoint.object.ProvisioningPlan;
import sailpoint.object.ProvisioningPlan.AccountRequest;
import sailpoint.object.ProvisioningPlan.AttributeRequest;
import sailpoint.object.ProvisioningPlan.PermissionRequest;
import sailpoint.object.ProvisioningResult;
import sailpoint.object.Schema;
import java.sql.CallableStatement;
import java.math.BigDecimal;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;

public Object getAttributeRequestValue(AccountRequest acctReq, String attribute) {
	    	if ( acctReq != null ) {
	    	  AttributeRequest attrReq = acctReq.getAttributeRequest(attribute);
	    	  if ( attrReq != null ) {
	    	    return attrReq.getValue();
	    	return null;

ProvisioningResult result = new ProvisioningResult();
CallableStatement callableStatement = null;
PreparedStatement statement = null;
String posibleError = "";

if (plan != null) {
    log.error("Inicio de la regla");
    List accounts = plan.getAccountRequests();

    if ((accounts != null) && (accounts.size() > 0)) {
        for (AccountRequest account : accounts) {
            try {
                //Comprueba si el account request es un CREATE
                if (AccountRequest.Operation.Create.equals(account.getOperation())) {
                    log.error("Entrando al create");
                    //Verificar con el if si ya existe esa cuenta
                    String USU_RUTUSUARIO = (String) account.getNativeIdentity();
                    //Llamo a la funcion verificarNumeroCuentas para ver si existen mas cuentas
                    int cantidadDeCuentas = verificarNumeroCuentas(USU_RUTUSUARIO);
                    //En caso que no cuente con mas cuentas se procede a la creacion
                    if(cantidadDeCuentas == 0){
                            //** */
                            //Traigo todo lo necesario para la creacion del usuario
                            String USU_USERNAME = getAttributeRequestValue(account,"USU_USERNAME");
                            String USU_NOMBRE = getAttributeRequestValue(account,"USU_NOMBRE");
                            String tipoDeEmpleado = getAttributeRequestValue(account,"tipoDeEmpleado");
                            log.error("PRUEBA INTERNOS: tipoDeEmpleado: "+tipoDeEmpleado+" " + USU_RUTUSUARIO + " " + USU_USERNAME + " " + USU_NOMBRE);
                            //Seteo en nulo el apellido materno y paterno, hay que considerar de que fuente autoritativa viene
                            String USU_APEPATERNO = null;
                            String USU_APEMATERNO = null;
                            //Segun la fuente autoritativa es el atributo de los apellidos
                                USU_APEPATERNO = getAttributeRequestValue(account,"APELLIDO_PATERNO_SSFF");
                                USU_APEMATERNO = getAttributeRequestValue(account,"APELLIDO_MATERNO_SSFF");
                                USU_APEPATERNO = getAttributeRequestValue(account,"APELLIDO_PATERNO_SAIP");
                                USU_APEMATERNO = getAttributeRequestValue(account,"APELLIDO_MATERNO_SAIP");
                            //Traigo mas atributos, existenteAD y LCS son estaticos
                            String USU_EMAIL = getAttributeRequestValue(account,"USU_EMAIL");
                            String existenteAD = getAttributeRequestValue(account,"existenteAD");
                            String cloudLifecycleState = getAttributeRequestValue(account,"cloudLifecycleState");
                            log.error("Creating account: {}"+ account.getNativeIdentity());
                            //Validacion de los atributos que traemos

                            if (USU_RUTUSUARIO != null && USU_USERNAME != null && USU_NOMBRE != null && USU_APEPATERNO != null && USU_APEMATERNO != null && USU_EMAIL != null && cantidadDeCuentas == 0 ) {
                                //Validacion de la cuenta de AD y LCS
                                if ("true".equals(existenteAD) && ("desuso".equals(cloudLifecycleState) || "active".equals(cloudLifecycleState))){
                                    boolean success = false;
                                        // Llamada al procedimiento almacenado con parámetros
                                        CallableStatement callableStatement = connection.prepareCall("{call Stored Procedure (?, ?, ?, ?, ?, ?, ?, ?, ?)}");

                                        // Configuración de los parámetros del procedimiento almacenado
                                        callableStatement.setString(1, USU_RUTUSUARIO);
                                        callableStatement.setString(2, USU_USERNAME);
                                        callableStatement.setString(3, USU_NOMBRE);
                                        callableStatement.setString(4, USU_APEPATERNO);
                                        callableStatement.setString(5, USU_APEMATERNO);
                                        callableStatement.setString(6, "ADMIN"); // @CodigoCargo - Ajusta según tus necesidades //Preguntar
                                        callableStatement.setString(7, USU_EMAIL);
                                        callableStatement.registerOutParameter(8, Types.NUMERIC); // NUMERROR$
                                        callableStatement.registerOutParameter(9, Types.VARCHAR); // MSJERROR$


                                        // Obtener los resultados de los parámetros de salida
                                        int numError = callableStatement.getInt(8);
                                        String msjError = callableStatement.getString(9);

                                        // Manejar los resultados según sea necesario
                                        if (numError != 0) {
                                            log.error("Error al crear la cuenta: Codigo Resultado: " + numError.intValue() + ", Descripcion Resultado: " + msjError);
                                            result.addError("Error al crear la cuenta: " + msjError);
                                        } else {
                                  "Cuenta creada correctamente");
                                            success = true;

                                    } catch (SQLException e){
                                        log.error("No se pudo crear la cuenta debido a una excepcion " + e.getMessage());
                                        result.addError("No se pudo crear la cuenta debido a una excepcion " + e.getMessage());
                                    log.error("Success: "+success);
                                    //Busca el numero de la tabla
                                         //aggregation of entitlements (I think it is not necessary to add it)

                                                String USU_RUTUSUARIO = (String) account.getNativeIdentity();
                                                String USU_USERNAME = getAttributeRequestValue(account,"USU_USERNAME");

                                                // Holds all the account attributes;
                                                Map attributesMap = new HashMap(); 
                                                String newID = USU_RUTUSUARIO;
                                                String usrNm = USU_USERNAME;
                                                // Add account attributes
                                                attributesMap.put("USU_RUTUSUARIO", newID);
                                                attributesMap.put("USU_USERNAME", usrNm);

                                                ResourceObject ro = new ResourceObject( 
                                                                newID,   // accountID just created
                                                                usrNm,   // accountDisplayName
                                                                Connector.TYPE_ACCOUNT,   //Object Type
                                                                attributesMap );

                                                result.setObject( ro );
                                                //HACER COMMIT
                                                log.error("Cuenta modificada correctamente");

                                            }catch(SQLException e){
                                                // En caso de error, realizar rollback de la transacción
                                                log.error("Error al modificar la cuenta: " + e.getMessage());
                                                result.addError("Error al modificar la cuenta: " + e.getMessage());
                                            } finally{
                                                // Restaurar el modo de autocommit

                                            log.error("numUsuarioValue vacio");
                                            result.addError("Error en la creación de cuenta: numUsuarioValue vacio");

                                        log.error("No se pudo obtener el valor de USU_NUMUSUARIO");
                                        result.addError("Error en la creación de cuenta: error interno de la BBDD");

                                    //Comprobaciones del AD
                                }else if ("false".equals(existenteAD)) {
                                    log.error("NO EXISTENTE EN AD");
                                    result.addError("La cuenta no existe en AD");
                                }else {
                                    log.error("No se pudo determinar si existe en AD");
                                    result.addError("No se pudo determinar si existe en AD");
                            } else {
                                log.error("Uno o más campos son nulos");
                                result.addError("Uno o más campos son nulos");
                        log.error("El usuario ya posee 1 o + cuentas en la base de datos, abortando el alta");
                        result.setStatus( ProvisioningResult.STATUS_FAILED );
                        result.addError( "El usuario ya posee 1 o + cuentas en la base de datos, abortando el alta");

            } catch (SQLException e) {
                // if(posibleError != null || posibleError != "") {
                //     result.addError("CUERPO: "+posibleError);
                // }else{
                //     result.addError(e);
                // }
            } finally {
                if (statement != null) {
return result;

i. Are you leveraging stored procedures? Yes
ii. If yes does your stored procedure generates the nativeIdentity and is it returning the said nativeIdentity so that you can map it with the user? I would think so
iii. Correlation configuration; is it been taken care of when you have configured the source? The correlations look good

The problem, for example, is that after creating an account these fields appear with “???” until you add the account