I'm having some problems with a custom rule (ex: seeing exceptions when rule is executed). Can you provide any troubleshooting advice?
IdentityIQ rule exceptions can be difficult to debug since most times the error (BSF) does not tell you on what line of code in the rule the error occurred.
One example of this would be the following:
The application script threw an exception: java.lang.NullPointerException: Null Pointer in Method Invocation BSF info: <name_of_offending_rule_here> at line: 0 column: columnNo...
I. There are several approaches here one can take in order to begin to troubleshoot the problematic rule:
1) The simplest method is to put temporary print statements in multiple places in your rule code. These print statements would go to your application server logfile and you can use them to help show you how "far" into the custom rule code you made it before the exception was thrown.
A simple psuedo-code example of this would be:
System.out.println("Starting rule code");
do something with code here
System.out.println("Through first part of code");
if (something) {
System.out.println("Something was true. Inside if statement");
do this code inside if statement
System.out.println("Now we are here");
and now do this code
System.out.println("End of if statement");
}
some more code here
System.out.println("Finished custom rule code");
2) Trace information can also be retrieved by enabling debug level logging on log4j.logger.sailpoint.server.InternalContext.
Example (in the log4j.properties file, set):
log4j.logger.sailpoint.server.InternalContext=debug
When set to debug, rule executions will be shown with a statement indicating entering the rule:
17:23:50,836 DEBUG sailpoint.server.InternalContext:94 - Entering runRule(rule = sailpoint.object.Rule@d35f5f[id=2c9081d41a2c67a7011a2c697c5301e6,name=BuildMapWithPermissions], params = {cols=[employe eNumber, roles, directPermissions, status], record=[S-MNTC08, null, sysdba, Enabled], state={},
As well as the return results of the rule:
17:23:50,852 DEBUG sailpoint.server.InternalContext:102 - Exiting runRule = {service=true, employeeNumber=XYZ-1234, directPermissions=[sysdba on 'All Objects'], status=Enabled}
To retrieve trace information as the rule is executing, the rule will need to reference the log4j object named 'log'. The following statement would insert a debug statement of, "Where you at?" during rule execution:
QueryOptions qo2 = new QueryOptions();
Filter[] filters2 = new Filter[1];
filters2[0] = null;
log.debug("Where you at?");
returnMap.put("what", "yes");
returnMap.put("why", "no");
Thus, when log4j.logger.sailpoint.server.InternalContext is set to 'debug', that statement will appear in the log file.
II. Rule execution can be tested individually
1) One very quick and direct method is to simply just execute the rule from the iiq console. Note that you can pass in an argfile if your rule requires input values.
> rule "My Correlation Rule - Test" <argfile>
This will run the rule and display the return results.
Format for the argfile is to provide a map of arguments. Arguments could be more complex if so desired.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Map PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Map>
<entry key="test" value="Hello World!"/>
</Map>
2) If supplying arguments is necessary and your rule is a BeanShell rule, you can test it in the interactive BeanShell console:
$ iiq bsh.Console
This will open the BeanShell Desktop with a prompt:
2.0b4 - by Pat Niemeyer (pat@pat.net)
bsh %
Here you can execute any number of statements valid in a bsh script, including constructing objects to be used as arguments for a test script.
More information on how to use the BeanShell Desktop can be found here:
http://www.beanshell.org/manual/contents.html
3) Finally, the iiq console supplies a convenience method to test buildMap rules. Simply assign your rule to the desired application and test the rule from the console using:
> connectorDebug "Corporate Directory" > /tmp/out.xml
Where "Corporate Directory" is the name of the application. This will build a list of mapped accounts from the application based on the assigned buildMap rule. These objects will be output to /tmp/out.xml, or whatever file you specify. Use this output to confirm that your rule is executing appropriately and use the aforementioned log.debug() statement to insert trace statements as needed.
III. Miscellaneous thoughts on rule debugging
1) Some rules are executed for both account and group aggregations. When both types of aggregations are expected to be run, you need to code said rule to handle both situations. In other words, the same code does not usually work for both types of objects. The common way this is handled is via "if" statements in the code like so:
if ( object.getObjectType().compareTo( Connector.TYPE_ACCOUNT ) == 0 ) {
.....RUN THIS CODE
}
if ( object.getObjectType().compareTo( Connector.TYPE_GROUP ) == 0 ) {
......RUN THIS OTHER CODE
}
2) Null pointer exceptions are caused when you reference a variable that is null. Take the following abbreviated example code:
String accountName = object.getAttribute("sAMAccountName");
accountName = accountName.toUpperCase()
If the object.getAttribute call does not return anything, then accountName is null. On the second line, a null pointer exception would be thrown when you attempt to call the "toUpperCase" method against a null accountName variable. When looking for null pointers in code, you look for "someVariable." syntax. The null pointer will occur with the attribute on the left side of the "dot".
Anytime you are trying to call methods on variables, you should make sure your code first checks to ensure the variable is not null.
Example:
String accountName = object.getAttribute("sAMAccountName");
if (accountName != null) {
accountName = accountName.toUpperCase()
}
What BSF stands for ?
@VinodC BSF is the Apache "Bean Scripting Framework".