Web Services After Operation Rule Validation

Hi guys,

I am working on a custom After Operation Rule where I need to add “true” value to the isActive attribute and Concatenate the entitlements with the application name selected by ‘ - ‘

Input Json

{
  "userId": "1234",
  "firstName": "John",
  "lastName": "Smith",
  "applications": [
    {
      "appName": "WEB",
      "accessLevels": ["Admin"]
    },
    {
      "appName": "ABC",
      "accessLevels": ["Manager"]
    }
  ]
}

Expected Json Output

{
  "userId": "1234",
  "firstName": "John",
  "lastName": "Smith",
  "isActive": true,
  "entitlements": [
    "WEB - Admin",
    "ABC - Manager"
  ]
}

After Operation Rule

import java.util.*;
import org.apache.commons.lang.StringUtils;

try {
    Map acct = new HashMap();
    acct.put("userId", account.get("userId"));
    acct.put("firstName", account.get("firstName"));
    acct.put("lastName", account.get("lastName"));
    acct.put("isActive", true);

    List ents = new ArrayList();
    List<Map> apps = (List<Map>) account.get("applications");
    if (apps != null) {
        for (Map app : apps) {
            String appName = (String) app.get("appName");
            List<String> levels = (List<String>) app.get("accessLevels");
            if (levels != null) {
                for (String lvl : levels) {
                    if (StringUtils.isNotBlank(appName) && StringUtils.isNotBlank(lvl)) {
                        ents.add(appName + " - " + lvl);
                    }
                }
            }
        }
    }
    acct.put("entitlements", ents);
    return acct;
} catch (Exception e) {
    log.error("Error in After Operation Rule: " + e.getMessage(), e);
    return account; // fallback to original
}

Is this coding approach supported and compatible in ISC After Operation Rules?

Or do I need to re-write this logic

Hi @selvasanthosh

The approach you shared — are you going to implement it during aggregation to reflect within the ISC attribute, or during provisioning to reflect in the target system?

It is during aggregation in ISC attribute. I want to store it in this format for the Account Attribute - “ Entitlement “

Hi @selvasanthosh

you can go with raw response or processed response object

here is an example using raw response object

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;
import java.util.ArrayList;

// After Operation Rule
Map updatedMapInfo = new HashMap();

if (processedResponseObject != null) {

    List dataList = new ArrayList();

    for (Map iterateMap : processedResponseObject) {
        if (iterateMap != null) {
            Map userMap = new HashMap();

            // Copy base attributes
            userMap.put("userId", iterateMap.get("userId"));
            userMap.put("firstName", iterateMap.get("firstName"));
            userMap.put("lastName", iterateMap.get("lastName"));
            userMap.put("isActive", true);

            // Build entitlements list
            List entitlements = new ArrayList();
            List apps = (List) iterateMap.get("applications");
            if (apps != null) {
                for (Map app : apps) {
                    String appName = (String) app.get("appName");
                    List accessLevels = (List) app.get("accessLevels");
                    if (accessLevels != null) {
                        for (String access : accessLevels) {
                            entitlements.add(appName + " - " + access);
                        }
                    }
                }
            }

            userMap.put("entitlements", entitlements);

            dataList.add(userMap);
        }
    }

    updatedMapInfo.put("data", dataList);
}

return updatedMapInfo;

Modify the code slightly based on your JSON output

Hi @Gopi2000 ,

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;

Map updatedMapInfo = new HashMap();
try {
	if (processedResponseObject != null) {
		List dataList = new ArrayList();
		for (Map iterateMap : processedResponseObject) {	
			if (iterateMap != null) {
				Map userMap = new HashMap();		
				userMap.put("userId", iterateMap.get("userId"));
				userMap.put("firstName", iterateMap.get("firstName"));
				userMap.put("lastName", iterateMap.get("lastName"));
				userMap.put("isActive", "Test - true");
				List applicationRoles = new ArrayList();
				List<Map> apps = (List<Map>) iterateMap.get("applications");
				if (apps != null) {
					for (Map app : apps) {
						String appName = (String) app.get("appName");
						List<String> levels = (List<String>) app.get("accessLevels");	
						if (levels != null) {
							for (String lvl : levels) {
								if (appName != null && !appName.trim().isEmpty() &&
									lvl != null && !lvl.trim().isEmpty()) {
									applicationRoles.add(appName + " - " + lvl);
								}	
							}	
						}					
					}
				}
				userMap.put("application-Role", applicationRoles);
				dataList.add(userMap);
			}
		}
		updatedMapInfo.put("data", dataList);
	}
	} catch (Exception e) {
	log.error("Error in After Operation Rule: " + e.getMessage(), e);
	updatedMapInfo.put("data", new ArrayList()); // fallback empty
}
return updatedMapInfo;

this is my code. I have attached the code to my source and ran the aggregation, after aggregation it’s not populating any value. it’s not taking the inputs from the code.

could you cross check the attribute application-Role is present with in the schema and response mapping

Yeah it’s there. I tried changing the value for isActive to test, but still after the aggregation it’s showing the value from the Original JSON path.

Did you change your response mapping in your UI for the source to Accounts/Identities list JSONPath: $.data[*]as in the code you are sending/updating/returning to updatedMapInfo.put(“data”, dataList);
return updatedMapInfo;

if the above is fine, then do the below to troubleshoot :

What i Would suggest is, throw a general execption after each step and see step by step where values are being poplated, and where issue might be..

for eg

are values like userid etc being populated into the usermap or not.

Eg : throw new GeneralException(“userMap” + String.valueOf(userMap));

Keeo doing that in all lines and run aggregatin and keep checking it if all details are being populated correctly and where issue might come up

Hi @selvasanthosh ,

I think the rule is clear. Just try adding loggers to the rule, and as it is a connector rule, we can monitor the logs via VA.

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;

Map updatedMapInfo = new HashMap();
try {
	// Log the entire input object to confirm data is present
	log.error("Processing processedResponseObject: " + processedResponseObject);

	if (processedResponseObject != null) {
		List dataList = new ArrayList();
		for (Map iterateMap : processedResponseObject) {	
			
			// Log the current account map
			log.error("Processing account map: " + iterateMap);
			
			if (iterateMap != null) {
				Map userMap = new HashMap();		
				userMap.put("userId", iterateMap.get("userId"));
				userMap.put("firstName", iterateMap.get("firstName"));
				userMap.put("lastName", iterateMap.get("lastName"));
				userMap.put("isActive", "Test - true");
				List applicationRoles = new ArrayList();
				
				// Log the 'applications' list to see if it was retrieved correctly
				List apps = (List) iterateMap.get("applications");
				log.error("Applications list: " + apps);
				
				if (apps != null) {
					// ... (rest of your logic)
					for (Map app : apps) {
						// Log the appName and levels for each iteration
						String appName = (String) app.get("appName");
						List levels = (List) app.get("accessLevels");	
						log.error("App Name: " + appName + ", Levels: " + levels);
						// ... (rest of your logic)
					}
				}
				
				userMap.put("application-Role", applicationRoles);
				log.error("Final userMap for account: " + userMap);
				dataList.add(userMap);
			}
		}
		updatedMapInfo.put("data", dataList);
log.error("Final updated Map info: " + updatedMapInfo);
	}
	
} catch (Exception e) {
	log.error("Error in After Operation Rule: " + e.getMessage(), e);
	updatedMapInfo.put("data", new ArrayList()); 
}
return updatedMapInfo;

Check the logs.

And as @rahulb635 mentioned, just verify the rootPath - $.data and responsecode - 200 or 2**

I have some questions here.

  1. Do you see any errors after running this code before? If yes, please provide it here.
  2. In the account schema, what’s the type of the attribute “isActive” - String or boolean?

No error is coming but the Accounts are 0 after the Aggregation.
they updated the api. now isActive is a String and we are fetching it directly from the JSON.

Now how to check the logs? I checked the logs but nothing was there, can you help me exactly which logs we have to check

This is the working code. When I run the aggregation and checked the log it is returning the expected output. But after the aggregation the accounts getting fetched was 0.

And in Aggregation HTTP operation if I give $ as a response information it’s returning the data in the logs, but if I give $.data as a response information the logs returning null data.

Can anyone please help me with this issue.

import java.util.*;
import org.json.JSONArray;
import org.json.JSONObject;

Map updatedMapInfo = new HashMap();
List newProcessedResponseObject = new ArrayList();
try {
	if (processedResponseObject != null && processedResponseObject.size() > 0) {	
		for (Map iterateMap : processedResponseObject) {	
			if (iterateMap != null) {
				Map currentMap = new HashMap();	
				currentMap.put("userld", iterateMap.get("userId"));
				currentMap.put("firstName", iterateMap.get("firstName"));
				currentMap.put("lastName", iterateMap.get("lastName"));
				currentMap.put("isActive", "testActive");
				
				List appList = new ArrayList();
				// Get applications JSON string
				Object appsObj = iterateMap.get("applications");
				
				if (appsObj != null) {
					String appsJson = appsObj.toString().trim();
					
					// Parse JSON Array
					JSONArray appsArray = new JSONArray(appsJson);
					for (int i = 0; i < appsArray.length(); i++) {
						JSONObject appObj = appsArray.getJSONObject(i);
						String appName = appObj.optString("appName", "");

						log.error("GMOX - Print appName" + appName);

						JSONArray accessArr = appObj.optJSONArray("accessLevels");
						if (accessArr != null && accessArr.length() > 0) {
							for (int j = 0; j < accessArr.length(); j++) {
								String access = accessArr.getString(j);
								appList.add(appName + "-" + access);	
								log.error("GMOX - Print Concatenated" + appName + "$$$$$$$$$$$$$$$$$$$$$$$$" + access);
							}
							} else {
							appList.add(appName);	
						}	
					}	
				}
				currentMap.put("applications", appList);
				log.error("GMOX - Print applications" + appList);
				newProcessedResponseObject.add(currentMap);	
			}	
		}	
	}
	updatedMapInfo.put("data",newProcessedResponseObject);
	log.error("GMOX - Print Final Output" + updatedMapInfo);

	} catch (Exception ex) {
	log.error("Exception while parsing applications in After Operation Rule: " + ex.getMessage());	
}

log.trace("GMOX - Print Exit Rule");
return updatedMapInfo;

Code looks good. If you are using processedResponseObject then you should have applications in response mapping. If “applications” is not part of response mapping then user rawresponseObject and build user object.

Hi @suresh_voya ,

applications is part of response mapping but still nothing is getting popolated.

Should I replace processedResponseObject with rawresponseObject ?

Add the logger and print both raw ad process response objects. Then you can see whether data is coming in expected format or not.

If you have applications in response mapping then above logic should work. Print the objects and review the incoming json response.

The actual issue was the userId attribute name wrtitten as userLd. Now the code is working fine.

Thanks for your inputs and help

2 Likes

Hi @selvasanthosh,

Excellent rule to construct entitlement. I would like to throw in some suggestions as well.

The issue could be how data is being configured in HTTP response mapping. Try aggregation after removing root path($.data) if configured and direct mapping in attribute path(schema attribute: User ID; attribute path: userId). I also see an lowercase “L“ instead of “I“ in your rule with line: -

currentMap.put(“userld“, iterateMap.get(“userId“));

Good luck

1 Like

@TheOneAMSheriff ,

Exactly that was the issue!!. Thanks for your time man.

1 Like

I have same issue, updatedMap has correct data, but accounts not populated for source. Tried with root path : ($.data) and also tried after removing root path.

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.