What is difference between Source Mapping and target Mapping, when use Target Mapping

Dear Community,

As far doing my training we always only use “source mapping” in the identity mapping, but when it need to be use the target mapping?? and there is any good example to apply to this?

Thanks in advance

Target mapping involves the synchronization of identity attribute values to a specified attribute in the target source. Additional details can be located in the product administrator’s guide. If you have any particular inquiries, please don’t hesitate to ask.

Maybe the following sequence diagram gives some insights in ‘Source Mapping’, ‘Target Mapping’ and the ‘Identity Refresh Task’:

– Remold

3 Likes

On top of responses from our experts

Source Mapping

  • We create identity attributes, same attributes applies for every identity in SailPoint.
  • Next question you should ask is, how do I get values for these attributes, which is source mapping.
  • Identities are created based on HR System (Authoritative source).
  • There can be multiple authoritative sources, employees, contractors, vendors …etc.
  • We provide source mapping so that Identity attribute can get data from respective HR system.

Target Mapping

  • Once an Identity is created, we work on provisioning (providing access) to different target applications.

Let us Take Active Directory (AD in short form) application for example

  • User will get account by Access Request or Birthright provisioning.

  • Account (Link) will contain data for a lot of attributes such as firstname, lastname, manager, department, mobile… etc

  • User data can change, for example

    • User moves from one department to another
    • One location to another
    • It is quite common that last name gets changed for various reasons
    • Manager gets changed
  • Some attributes will never change (mostly), for example

    • Employee number
    • Firstname

Now consider the use case

Firstname: Elizabeth
Lastname: Taylor

This user lastname got changed in HR system to Hurley.

Due to source mapping, identity attribute lastname updated to Hurley

How about user AD account, lastname is still Taylor. You know the importance of AD, user name in AD will display in Teams, Outlook and many other applications.

How does user lastname gets updated in AD ?

When there is a request made, so that SailPoint provisioning engine will calculate values for all attributes as per provisioning policy form and filter the attributes that has same data for an attribute in identity object and Link object. Since lastname is modified it will be in request and gets updated in AD application.

When this request will be made ?
What if this request is not made at all ?

Till that time user last name will not be updated in AD application.

Now you will get a thought, why can’t we sync data from identity to AD account immediately ? which is Target Sync.

HR System → SailPoint → Active Directory.

Same goes for Manager attribute. Manager place significant role. Let us say if you submit a request in some application, if manager is not updated, your request will go to old manager for approval ?

Same story for all other attributes which can get modified and all other applications.

Hope this helps :slight_smile:

Thanks
Krish

8 Likes

Thank you @MVKR7T your explanation. Question because you mention Provisioning. So in the application should be a provisioning rule? Following example in Ad should be a Provisioning rule.

If there any example.where I can follow up with Target mapping. I could not find anything in compass

Provisioning means Writing data to target application.

Rule is not mandatory for provisioning, depends on connector you use.

There are around 17 categories of Rules.

For Aggregation
Provisioning
Certification
… etc

For example, Provisioning Rules

Before Provisioning Rule : When you submit a request, provisioning plan will be created which contains data for all attributes that sends data to target application. So plan will be given as an input to this Rule, where you can customize this plan. You can remove some attributes or add some more attributes or change some attribute values.

After Provisioning Rule : To do operations after provisioning (after an account created for a user in a specific application like AD). You can send an email to user that your account is created successfully, here is your credentials. Just like you get order confirmation from Amazon. You can use this Rule for Audit purpose as well.

Like this, every Rule has its own purpose. Some times Rules are mandatory, sometimes optional. You will get more knowledge as you go in your learning, just give it time.

Thanks
Krish

3 Likes

Not sure about that, you should find some live examples in your training. For documentation, I believe you downloaded SailPoint IIQ already.

If you download IIQ zip file, then you will have a doc folder in it, which has a lot of PDF documents. you can check IdentityIQ_System_Configuration doc. It has information about Identity mappings.

1 Like

There is hardly any information in the documentation regarding Target Mappings. Only 1 single paragraph under Edit Identity Attributes Page. (@MVKR7T )

but …

Target Mapping is quite simple and don’t think to complicated about it. What is does it keeps an attribute in the target application in sync with the Identity Attribute.

So if lastname changes to Hurley in IdentityIQ, the Target Mapping for lastname attribute in AD updates the lastname (which is ‘sn’ in AD) in Active Directory (using the example above).

So very plain and simple when it goes for lastname.

The difficulty lies when you can not perform a 1-on-1 copy. For instance the manager attribute in AD is not a simple String.

  • Manager in HR = John Doe
  • Manager in IdentityIQ = the Identity Object of John Doe (via the manager correlation rule in HR application configuration)
  • Manager in AD => cn=John Doe,ou=Accounts,dc=company,dc=com
    To create the value for the Manager in AD you need to have a Transformation Rule.

(for questions regarding a Transformation Rule and the option ‘Provision All Accounts’, please open another thread.

– Remold

2 Likes

Hey Sara, I think Krish and Remold have explained Target Provisioning pretty well.
As for the example which you had asked for, this thread in community might help ( a very simple target mapping use case for a JDBC app) - https://community.sailpoint.com/t5/IdentityIQ-Forum/Attribute-Sync-Target-Mapping-into-JDBC/td-p/228602

Also, if you still have any question regarding target mapping. Do let us know :slight_smile:

1 Like

@Remold, i test your case scenario but i did not see the change in the target database. I think because Im missing the Provision policies in Time tracking → update → but not sure

So the steps i did, I add target mapping on time tracking → lastname

Then via LCM i update the identity from lastName: smith to smithTest which update in iiq spt_identity lastname

but in time tracking db does not reflect the change of the last name
image

Provision transaction also said has been modify


image

Hi @fugitiva,

The JBCProvision Rule should be able to handle this change. The Rule should be modified so that it will trigger the update query when there is a Modify operation on the account, else it will not get reflected in the target application.

it has a provisioning rule


Hi @fugitiva ,

It will be easier, if you share the rule. From the screenshot you have shared, Modify Operation is in else if and the logic and the query is not visible, to confirm whether it is triggering the query or not.

yes, sorry sure

import java.util.Date;
            import java.sql.Connection;
            import java.sql.DriverManager;
            import java.sql.PreparedStatement;
            import java.sql.Statement;
            import java.sql.SQLException;
            import java.sql.ResultSet;
            import java.sql.Types;
            import java.util.List;
            import sailpoint.api.SailPointContext;
            import sailpoint.connector.JDBCConnector;
            import sailpoint.object.Application;
            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 sailpoint.tools.xml.XMLObjectFactory;
            import org.apache.commons.logging.LogFactory;
            import org.apache.commons.logging.Log;
            import sailpoint.tools.Util;


            // Internal method search for accountRequest to get the attribute, then if not null get the value of Attribute Request
            public Object getAttributeRequestValue(AccountRequest accountRequest, String attribute) {
                if (accountRequest != null) {
                    AttributeRequest attributeRequest = accountRequest.getAttributeRequest(attribute);
                    if (attributeRequest != null) {//internal if
                        return attributeRequest.getValue();//if not null return attributeRequest value
                    }
                }//finis if
                return null;//if null is true, return null
            }

            /*JDBC Provisioning Rule Body*/
            // We will handle these cases right now:
            // Account Request Create
            // Account Request Modify
            // Account Request Delete
            // Account Lock/Unlock
            // Account Enable/Disable

            Date now = new Date();

            System.out.println("\n\n\n\n\n");
            System.out.println("****************************************");
            System.out.println("Entering Provisioning Rule for Time Tracking");
            System.out.println(" Current Time =  " + now.toString());
            System.out.println("****************************************");

            // The ProvisioningResult is the return object for this type of rule. We'll create it here and then populate it later
            ProvisioningResult provisioningResult = new ProvisioningResult();

            // Check if the plan is null or not, if not null, process it, display the provisioning plan as xml
            //plan variable value come from line 32 Argument name="plan"
            if (plan != null) {
                System.out.println("*** \n The Provisioning Plan being passed in = \n***\n" + plan.toXml() + "\n****************************************");
                List accountList = plan.getAccountRequests();

                //  Get list of  Account Requests out of the plan if is not n ull and less than zero
                //if ((accountList != null) and (accountList.size() less than 0))
                if ((accountList != null) && (accountList.size() > 0)) {
                    // If the plan contains one or more account requests, we'll iterate through them
                    for (AccountRequest accountRequest : accountList) {
                        try {
                            // All of the accountRequest operations will reside in a try block in case we have any errors,
                            //we can mark the provisioningResult as "Failed" if we have an issue
                            if (AccountRequest.Operation.Create.equals(accountRequest.getOperation())) {
                                //CREATE Operation
                                System.out.println("Account Request Operation = Create");
                                PreparedStatement statement = connection.prepareStatement("insert into users (id,firstname,lastname,capability,status,locked,username) values (?,?,?,?,?,?,?)");
                                statement.setString(1, (String) accountRequest.getNativeIdentity());
                                statement.setString(2, getAttributeRequestValue(accountRequest, "firstname"));
                                statement.setString(3, getAttributeRequestValue(accountRequest, "lastname"));
                                statement.setString(5, getAttributeRequestValue(accountRequest, "status"));
                                statement.setString(6, getAttributeRequestValue(accountRequest, "locked"));
                                statement.setString(7, getAttributeRequestValue(accountRequest, "username"));
                                //
                                // Grab the role from the request. If it's a single role, it'll be a string, add it to
                                // the statement, other wise if it's a List, convert to CSV and add it to the statement
                                //
                                AttributeRequest attrReq = accountRequest.getAttributeRequest("capability");
                                if (attrReq != null) {
                                    if (attrReq.getValue() instanceof String) {
                                        statement.setString(4, (String) attrReq.getValue());
                                    } else if (attrReq.getValue() instanceof List) {
                                        String listOfRoles = Util.listToCsv((List) attrReq.getValue());
                                        statement.setString(4, listOfRoles);
                                    }
                                } else {
                                    statement.setString(4, "");
                                }

                                System.out.println("Preparing to execute: " + statement);
                                statement.executeUpdate();

                                //
                                // Sucessful Create, so mark result as COMMITTED
                                //

                                provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);


                            } else if (AccountRequest.Operation.Modify.equals(accountRequest.getOperation())) {

                                //
                                // MODIFY Operation
                                //

                                //
                                // We have a modify, this one is trickier, as we can have "Add" and "Remove"
                                // operations and each can be a single string value or a list
                                //

                                System.out.println("Account Request Operation = Modify");

                                //
                                // Determine what the current roles are first...
                                //

                                Statement curr_stmt = connection.createStatement();
                                ResultSet rs = curr_stmt.executeQuery("select * from users where id = '" + accountRequest.getNativeIdentity() + "'");

                                //
                                //  Check result set. Should only be one row since id is a unique key for the table
                                //
                                List current_roles = null;
                                String roles = "";

                                while (rs.next()) {
                                    roles = roles + "," + rs.getString("capability");
                                }
                                current_roles = Util.csvToList(roles, true);

                                if (current_roles == null) {
                                    System.out.println("We have a null current_roles list... change it to an empty list for subsequent processing.");
                                    current_roles = new ArrayList();
                                }

                                System.out.println("Current Roles for User = " + Util.listToCsv(current_roles));

                                //
                                // Get all Attribute Requests and pull out just the role ones.
                                //

                                List remove_roles = new ArrayList();
                                List add_roles = new ArrayList();
                                //
                                // Get all attribute requests and then we will filter for those related to the roles column
                                //
                                List mod_attr_requests = accountRequest.getAttributeRequests();

                                if (mod_attr_requests != null) {
                                    for (AttributeRequest req : mod_attr_requests) {
                                        if (req.getName().equals("capability")) {
                                            if (ProvisioningPlan.Operation.Remove.equals(req.getOperation())) {
                                                // Process Removes First
                                                if (req.getValue() instanceof String) {
                                                    remove_roles = Util.csvToList(req.getValue());
                                                } else if (req.getValue() instanceof List) {
                                                    remove_roles = req.getValue();
                                                }
                                            } else if (ProvisioningPlan.Operation.Add.equals(req.getOperation())) {
                                                // Process Adds Second
                                                if (req.getValue() instanceof String) {
                                                    add_roles = Util.csvToList(req.getValue());
                                                } else if (req.getValue() instanceof List) {
                                                    add_roles = req.getValue();
                                                }
                                            }

                                        }
                                    }
                                }
                                //
                                //  We now have a calculated list of the roles we are adding, the roles we are removing, and the current roles for the user.
                                //
                                System.out.println("Add Roles = " + Util.listToCsv(add_roles));
                                System.out.println("Remove Roles = " + Util.listToCsv(remove_roles));


                                //
                                // If we have roles to remove, remove them
                                //
                                if (!remove_roles.isEmpty()) {
                                    System.out.println("About to remove roles: " + remove_roles.toString() + "from the current_roles = " + current_roles.toString());
                                    current_roles.removeAll(remove_roles);
                                }
                                //
                                // If we have roles to add, check if they are there and add them as we iterate through
                                //

                                if (!add_roles.isEmpty()) {
                                    System.out.println("About to add roles: " + add_roles.toString() + " to the current_roles = " + current_roles.toString());
                                    for (Object item : add_roles) {
                                        if (!current_roles.contains(item)) {
                                            current_roles.add(item);
                                        }
                                    }
                                }

                                //
                                //  Print out the list of roles being provisioned after processing "add" and "remove" operations
                                //
                                System.out.println("Updating the roles for:" + (String) accountRequest.getNativeIdentity() + " Current Roles after adding/removing = " + Util.listToCsv(current_roles));

                                //
                                // Process update SQL operation
                                //

                                PreparedStatement statement = connection.prepareStatement("update users set capability = ? where id = ?");
                                statement.setString(2, (String) accountRequest.getNativeIdentity());
                                statement.setString(1, Util.listToCsv(current_roles));
                                statement.executeUpdate();

                                // Add these in the future.
                                // statement.setString ( 2,
                                // getAttributeRequestValue(account,"first") );
                                // statement.setString ( 3,
                                // getAttributeRequestValue(account,"last") );
                                // statement.setString ( 4,
                                // getAttributeRequestValue(account,"capability") );
                                // statement.setString ( 5,
                                // getAttributeRequestValue(account,"status") );

                                provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);

                            } else if (AccountRequest.Operation.Delete.equals(accountRequest.getOperation())) {

                                //
                                // DELETE Operation
                                //


                                System.out.println("Account Request Operation = Delete");
                                PreparedStatement statement = connection.prepareStatement("delete from users where id = ?");
                                statement.setString(1, (String) accountRequest.getNativeIdentity());
                                statement.executeUpdate();

                                provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);

                            } else if (AccountRequest.Operation.Disable.equals(accountRequest.getOperation())) {

                                System.out.println("Account Request Operation = Disable");
                                PreparedStatement statement = connection.prepareStatement("update users set status = 'I' where id = ?");
                                statement.setString(1, (String) accountRequest.getNativeIdentity());
                                statement.executeUpdate();
                                provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);

                            } else if (AccountRequest.Operation.Enable.equals(accountRequest.getOperation())) {

                                System.out.println("Account Request Operation = Enable");
                                PreparedStatement statement = connection.prepareStatement("update users set status = 'A' where id = ?");
                                statement.setString(1, (String) accountRequest.getNativeIdentity());
                                statement.executeUpdate();
                                provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);


                            } else if (AccountRequest.Operation.Lock.equals(accountRequest.getOperation())) {

                                System.out.println("Account Request Operation = Lock");
                                PreparedStatement statement = connection.prepareStatement("update users set locked = 'Y' where id = ?");
                                statement.setString(1, (String) accountRequest.getNativeIdentity());
                                statement.executeUpdate();
                                provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);


                            } else if (AccountRequest.Operation.Unlock.equals(accountRequest.getOperation())) {

                                System.out.println("Account Request Operation = Unlock");
                                PreparedStatement statement = connection.prepareStatement("update users set locked = 'N' where id = ?");
                                statement.setString(1, (String) accountRequest.getNativeIdentity());
                                statement.executeUpdate();
                                provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);

                            } else {

                                // Unknown operation!
                                System.out.println("Unknown operation ["
                                        + accountRequest.getOperation() + "]!");
                            }

                        } catch (SQLException e) {
                            System.out.println("Error: " + e);
                            provisioningResult.setStatus(ProvisioningResult.STATUS_FAILED);
                            provisioningResult.addError(e);
                        }
                    }    // account request loop
                }     // if account requests exist
            }   // if plan not null


            System.out.println("****************************************");
            System.out.println("****************************************");
            System.out.println("Exiting Provisioning Rule for Time Tracking. \n  Result=  \n" + provisioningResult.toXml(false));
            System.out.println("****************************************");
            System.out.println("****************************************");
            System.out.println("\n\n\n\n\n");

            plan.setResult(provisioningResult);

            return provisioningResult;

Modify operation is only handled for Role/Entitlement Add/Removal, not handled any attributes and not for attribute sync.

2 Likes

I see how i can add the update operation after the create operation??

Hi @fugitiva,

Try adding the below code.

String lastName = getAttributeRequestValue(account,"lastname");
if(lastName != null){
  PreparedStatement statement = connection.prepareStatement("update users set lastname = ? where id = ?");
  statement.setString(2, (String) accountRequest.getNativeIdentity());
  statement.setString(1, lastName);
  statement.executeUpdate();
}

String firstName = getAttributeRequestValue(account,"firstname");
if(firstName != null){
  PreparedStatement statement = connection.prepareStatement("update users set firstname = ? where id = ?");
  statement.setString(2, (String) accountRequest.getNativeIdentity());
  statement.setString(1, firstName);
  statement.executeUpdate();
}
2 Likes

Where? should I first do else if (AccountRequest.Operation.Modify.equals(accountRequest.getOperation())){

here your code?
}

I’m getting this error

Here where I place the modify/update

 //UPDATE Operation
                        else if (AccountRequest.Operation.Modify.equals(accountRequest.getOperation())) {

                            // MODIFY Operation, update
                            System.out.println("Account Request Operation = Modify - Update Identity");

                            String lastName = getAttributeRequestValue(account,"lastname");
                            if(lastName != null){
                                PreparedStatement statement = connection.prepareStatement("update users set lastname = ? where id = ?");
                                statement.setString(2, (String) accountRequest.getNativeIdentity());
                                statement.setString(1, lastName);
                                statement.executeUpdate();
                            }

                            String firstName = getAttributeRequestValue(account,"firstname");
                            if(firstName != null){
                                PreparedStatement statement = connection.prepareStatement("update users set firstname = ? where id = ?");
                                statement.setString(2, (String) accountRequest.getNativeIdentity());
                                statement.setString(1, firstName);
                                statement.executeUpdate();
                            }
                        }
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<!--This rule is add in application ->Rules -> Connector rules-> provision rule -->
<Rule language="beanshell" name="JDBCProvision-TimeTracking" type="JDBCProvision">
    <Description>A Provisioning rule for the Time Tracking application.
        Handles Account Creates/Deletes/Modifies/Unlocks/Enables/Disables</Description>
    <Signature returnType="ProvisioningResult">
        <Inputs>
            <Argument name="log" type="org.apache.commons.logging.Log">
                <Description>
                    The log object associated with the SailPointContext.
                </Description>
            </Argument>
            <Argument name="context" type="sailpoint.api.SailPointContext">
                <Description>
                    A sailpoint.api.SailPointContext object that can be used to query the database if necessary.
                </Description>
            </Argument>
            <Argument name="application">
                <Description>
                    The application whose data file is being processed.
                </Description>
            </Argument>
            <Argument name="schema">
                <Description>
                    The Schema currently in use.
                </Description>
            </Argument>
            <Argument name="connection">
                <Description>
                    A connection object to connect to database.
                </Description>
            </Argument>
            <Argument name="plan">
                <Description>
                    The ProvisioningPlan created against the JDBC application.
                </Description>
            </Argument>
        </Inputs>
        <Returns>
            <Argument name="result">
                <Description>
                    A Provisioning Result object is desirable to return the status.IT can be a new object or part of  Provisioning Plan
                </Description>
            </Argument>
        </Returns>
    </Signature>
    <Source>
        import java.util.Date;
        import java.sql.Connection;
        import java.sql.DriverManager;
        import java.sql.PreparedStatement;
        import java.sql.Statement;
        import java.sql.SQLException;
        import java.sql.ResultSet;
        import java.sql.Types;
        import java.util.List;
        import sailpoint.api.SailPointContext;
        import sailpoint.connector.JDBCConnector;
        import sailpoint.object.Application;
        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 sailpoint.tools.xml.XMLObjectFactory;
        import org.apache.commons.logging.LogFactory;
        import org.apache.commons.logging.Log;
        import sailpoint.tools.Util;


        // Internal method search for accountRequest to get the attribute, then if not null get the value of Attribute Request
        public Object getAttributeRequestValue(AccountRequest accountRequest, String attribute) {
            if (accountRequest != null) {
                AttributeRequest attributeRequest = accountRequest.getAttributeRequest(attribute);
                if (attributeRequest != null) {//internal if
                    return attributeRequest.getValue();//if not null return attributeRequest value
                }
            }//finis if
            return null;//if null is true, return null
        }

        /*JDBC Provisioning Rule Body*/
        // We will handle these cases right now:
        // Account Request Create
        // Account Request Modify
        // Account Request Delete
        // Account Lock/Unlock
        // Account Enable/Disable

        Date now = new Date();

        System.out.println("\n\n\n\n\n");
        System.out.println("****************************************");
        System.out.println("Entering Provisioning Rule for Time Tracking");
        System.out.println(" Current Time =  " + now.toString());
        System.out.println("****************************************");

        // The ProvisioningResult is the return object for this type of rule. We'll create it here and then populate it later
        ProvisioningResult provisioningResult = new ProvisioningResult();

        // Check if the plan is null or not, if not null, process it, display the provisioning plan as xml
        //plan variable value come from line 32 Argument name="plan"
        if (plan != null) {
            System.out.println("*** \n The Provisioning Plan being passed in = \n***\n" + plan.toXml() + "\n****************************************");
            List accountList = plan.getAccountRequests();

            //  Get list of  Account Requests out of the plan if is not n ull and less than zero
            //if ((accountList != null) and (accountList.size() less than 0))
            if ((accountList != null) &amp;&amp; (accountList.size() > 0)) {
                // If the plan contains one or more account requests, we'll iterate through them
                for (AccountRequest accountRequest : accountList) {
                    try {
                        // All of the accountRequest operations will reside in a try block in case we have any errors,
                        //we can mark the provisioningResult as "Failed" if we have an issue
                        if (AccountRequest.Operation.Create.equals(accountRequest.getOperation())) {
                            //CREATE Operation
                            System.out.println("Account Request Operation = Create");
                            PreparedStatement statement = connection.prepareStatement("insert into users (id,firstname,lastname,capability,status,locked,username) values (?,?,?,?,?,?,?)");
                            statement.setString(1, (String) accountRequest.getNativeIdentity());
                            statement.setString(2, getAttributeRequestValue(accountRequest, "firstname"));
                            statement.setString(3, getAttributeRequestValue(accountRequest, "lastname"));
                            statement.setString(5, getAttributeRequestValue(accountRequest, "status"));
                            statement.setString(6, getAttributeRequestValue(accountRequest, "locked"));
                            statement.setString(7, getAttributeRequestValue(accountRequest, "username"));
                            //
                            // Grab the role from the request. If it's a single role, it'll be a string, add it to
                            // the statement, other wise if it's a List, convert to CSV and add it to the statement
                            //
                            AttributeRequest attrReq = accountRequest.getAttributeRequest("capability");
                            if (attrReq != null) {
                                if (attrReq.getValue() instanceof String) {
                                    statement.setString(4, (String) attrReq.getValue());
                                } else if (attrReq.getValue() instanceof List) {
                                    String listOfRoles = Util.listToCsv((List) attrReq.getValue());
                                    statement.setString(4, listOfRoles);
                                }
                            } else {
                                statement.setString(4, "");
                            }

                            System.out.println("Preparing to execute: " + statement);
                            statement.executeUpdate();
                            // Sucessful Create, so mark result as COMMITTED
                            provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);
                        }
                        //UPDATE Operation
                        else if (AccountRequest.Operation.Modify.equals(accountRequest.getOperation())) {

                            // MODIFY Operation, update
                            System.out.println("Account Request Operation = Modify - Update Identity");

                            String lastName = getAttributeRequestValue(account,"lastname");
                            if(lastName != null){
                                PreparedStatement statement = connection.prepareStatement("update users set lastname = ? where id = ?");
                                statement.setString(2, (String) accountRequest.getNativeIdentity());
                                statement.setString(1, lastName);
                                statement.executeUpdate();
                            }

                            String firstName = getAttributeRequestValue(account,"firstname");
                            if(firstName != null){
                                PreparedStatement statement = connection.prepareStatement("update users set firstname = ? where id = ?");
                                statement.setString(2, (String) accountRequest.getNativeIdentity());
                                statement.setString(1, firstName);
                                statement.executeUpdate();
                            }
                        }
                        // MODIFY Operation -  Role: capability
                        //add / remove role
                     else if (AccountRequest.Operation.Modify.equals(accountRequest.getOperation())) {
                        // MODIFY Operation
                        // We have a modify, this one is trickier, as we can have "Add" and "Remove"
                        // operations and each can be a single string value or a list
                        System.out.println("Account Request Operation = Modify - Update Role");

                        // Determine what the current roles are first...
                        Statement curr_stmt = connection.createStatement();
                        ResultSet resultSet = curr_stmt.executeQuery("select * from users where id = '" +
                                            accountRequest.getNativeIdentity() + "'");

                        //  Check result set. Should only be one row since id is a unique key for the table
                        List current_roles = null;
                        String roles = "";
                        while (resultSet.next()) {
                            roles = roles + "," + resultSet.getString("capability");
                        }
                        current_roles = Util.csvToList(roles, true);

                        if (current_roles == null) {
                            System.out.println("We have a null current_roles list... change it to an empty list for subsequent processing.");
                            current_roles = new ArrayList();
                        }

                        System.out.println("Current Roles for User = " + Util.listToCsv(current_roles));
                        // Get all Attribute Requests and pull out just the role ones.

                        List remove_roles = new ArrayList();
                        List add_roles = new ArrayList();

                        // Get all attribute requests and then we will filter for those related to the roles column
                        List mod_attr_requests = accountRequest.getAttributeRequests();

                        if (mod_attr_requests != null) {
                            for (AttributeRequest req : mod_attr_requests) {
                                if (req.getName().equals("capability")) {
                                    if (ProvisioningPlan.Operation.Remove.equals(req.getOperation())) {
                                        // Process Removes First
                                        if (req.getValue() instanceof String) {
                                            remove_roles = Util.csvToList(req.getValue());
                                        } else if (req.getValue() instanceof List) {
                                            remove_roles = req.getValue();
                                        }
                                    } else if (ProvisioningPlan.Operation.Add.equals(req.getOperation())) {
                                        // Process Adds Second
                                        if (req.getValue() instanceof String) {
                                            add_roles = Util.csvToList(req.getValue());
                                        } else if (req.getValue() instanceof List) {
                                            add_roles = req.getValue();
                                        }
                                    }

                                }
                            }
                        }

                        //  We now have a calculated list of the roles we are adding, the roles we are removing, and the current roles for the user.
                        System.out.println("Add Roles = " + Util.listToCsv(add_roles));
                        System.out.println("Remove Roles = " + Util.listToCsv(remove_roles));

                        // If we have roles to remove, remove them
                        if (!remove_roles.isEmpty()) {
                            System.out.println("About to remove roles: " + remove_roles.toString() + "from the current_roles = " + current_roles.toString());
                            current_roles.removeAll(remove_roles);
                        }

                        // If we have roles to add, check if they are there and add them as we iterate through
                        if (!add_roles.isEmpty()) {
                            System.out.println("About to add roles: " + add_roles.toString() + " to the current_roles = " + current_roles.toString());
                            for (Object item : add_roles) {
                                if (!current_roles.contains(item)) {
                                    current_roles.add(item);
                                }
                            }
                        }
                        //  Print out the list of roles being provisioned after processing "add" and "remove" operations
                        System.out.println("Updating the roles for:" + (String) accountRequest.getNativeIdentity() + " Current Roles after adding/removing = " + Util.listToCsv(current_roles));

                        // Process update SQL operation -  base on role: capability
                        PreparedStatement statement = connection.prepareStatement("update users set capability = ? where id = ?");
                        statement.setString(2, (String) accountRequest.getNativeIdentity());
                        statement.setString(1, Util.listToCsv(current_roles));
                        statement.executeUpdate();

                        // Add these in the future.
                        // statement.setString ( 2,
                        // getAttributeRequestValue(account,"first") );
                        // statement.setString ( 3,
                        // getAttributeRequestValue(account,"last") );
                        // statement.setString ( 4,
                        // getAttributeRequestValue(account,"capability") );
                        // statement.setString ( 5,
                        // getAttributeRequestValue(account,"status") );

                        provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);

                    }// DELETE OPERATION
                     else if (AccountRequest.Operation.Delete.equals(accountRequest.getOperation())) {
                        System.out.println("Account Request Operation = Delete");
                        PreparedStatement statement = connection.prepareStatement("delete from users where id = ?");
                        statement.setString(1, (String) accountRequest.getNativeIdentity());
                        statement.executeUpdate();

                        provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);

                    }//disable user - status: I
                     else if (AccountRequest.Operation.Disable.equals(accountRequest.getOperation())) {

                        System.out.println("Account Request Operation = Disable");
                        PreparedStatement statement = connection.prepareStatement("update users set status = 'I' where id = ?");
                        statement.setString(1, (String) accountRequest.getNativeIdentity());
                        statement.executeUpdate();
                        provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);

                    }//ENABLE USER - status: A
                     else if (AccountRequest.Operation.Enable.equals(accountRequest.getOperation())) {
                        System.out.println("Account Request Operation = Enable");
                        PreparedStatement statement = connection.prepareStatement("update users set status = 'A' where id = ?");
                        statement.setString(1, (String) accountRequest.getNativeIdentity());
                        statement.executeUpdate();
                        provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);


                    }//LOCKED user - locked=Y
                     else if (AccountRequest.Operation.Lock.equals(accountRequest.getOperation())) {

                        System.out.println("Account Request Operation = Lock");
                        PreparedStatement statement = connection.prepareStatement("update users set locked = 'Y' where id = ?");
                        statement.setString(1, (String) accountRequest.getNativeIdentity());
                        statement.executeUpdate();
                        provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);


                    }//Unlock user - locked=N
                     else if (AccountRequest.Operation.Unlock.equals(accountRequest.getOperation())) {

                        System.out.println("Account Request Operation = Unlock");
                        PreparedStatement statement = connection.prepareStatement("update users set locked = 'N' where id = ?");
                        statement.setString(1, (String) accountRequest.getNativeIdentity());
                        statement.executeUpdate();
                        provisioningResult.setStatus(ProvisioningResult.STATUS_COMMITTED);

                    } else {
                        // Unknown operation!
                        System.out.println("Unknown operation ["
                                + accountRequest.getOperation() + "]!");
                    }

                } catch (SQLException e) {
                    System.out.println("Error: " + e);
                    provisioningResult.setStatus(ProvisioningResult.STATUS_FAILED);
                    provisioningResult.addError(e);
                }
            }    // account request loop
        }     // if account requests exist
    }   // if plan not null

        System.out.println("****************************************");
        System.out.println("****************************************");
        System.out.println("Exiting Provisioning Rule for Time Tracking. \n  Result=  \n" + provisioningResult.toXml(false));
        System.out.println("****************************************");
        System.out.println("****************************************");
        System.out.println("\n\n\n\n\n");

        plan.setResult(provisioningResult);

        return provisioningResult;</Source>
</Rule>