Often times it is necessary to create a mapping of keys to values in IdentityIQ. While most of IdentityIQ's data models are fairly flexible and allow attributes to be placed on them; other needs can arise to have these data structures exist independently of other objects. Fortunately, in IdentityIQ this is possible through usage of the Custom object.
Simply put, it is a simple object that has an attribute map, which can be serialized / deserialized into IdentityIQ. This is an example of what one looks like:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Custom PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Custom name="Some Custom Object">
<Attributes>
<Map>
<entry key="someKey1" value="someValue"/>
<entry key="someKey2">
<value>
<List>
<String>listValue1</String>
<String>listValue2</String>
<String>listValue3</String>
</List>
</value>
</entry>
<entry key="someKey3">
<value>
<Boolean>true</Boolean>
</value>
</entry>
</Map>
</Attributes>
</Custom>
You can create these structures in XML outside of IdentityIQ and import them into the system. Once they are there they can be used by rules, workflows, or even custom code.
Example 1: Getting a Custom object.
Custom custom = context.getObject( Custom.class, "Some Custom Object" );
System.out.println( custom.toXml() );
Example 2: Updating a Custom object.
// See if there is already a custom object, and lock it if there is.
Custom custom = (Custom) ObjectUtil.lockObject(
context, // SailPointContext
Custom.class, // Object Class - Custom.class in our case
null, // The object ID in String form
"Some Custom Object", // The object Name in String form
PersistenceManager.LOCK_TYPE_TRANSACTION // The type of lock we want - either persistent or transaction.
);
// There was not a Custom object already in the database, let's create a new one.
if ( custom == null ) {
custom = new Custom();
custom.setName( "Some Custom Object" );
}
// Now add some attributes:
custom.put( "someKey1", "someValue" );
custom.put( "someKey2", Arrays.asList( new String[] {"listValue1", "listValue2", "listValue3"} ) );
custom.put( "someKey3", true );
// Do more stuff...
// Save it and commit it.
context.saveObject( custom );
context.commitTransaction();
System.out.println( custom.toXml() );
Thats it! Enjoy your new found flexibility with the custom object!
Note: Keep in mind that these are objects stored in the database. Most times when you look up or edit these objects will result in additional call(s) to the database. Use your best judgement when to utilize these API calls to avoid any potential self-inflicted performance issues.
@neil_mcglennon ... in one of the earlier comments you have mentioned -
Structurally, the Custom object and the Configuration object are fairly similar. It is a separate namespace that won't be affected. It is bad practice to put implementation into Configuration objects, as this could be affected by patches, upgrades, etc. From a best practice standpoint, leave Configuration objects to SailPoint, and leverage Custom objects to implementation.
Does it still hold true ? The reason why i ask this is looking at SailPoint's SERI VM(IIQ 8.0) i could see most of the custom logic being built using 'Configuration' object.
Also, how can the patches affect the configuration object if its a new configuration object with a custom/new name.
Yes this still holds true.
Configuration are objects that SailPoint updates and maintains. If customers or partners use these, those settings could collide with SailPoint settings if not done carefully. New releases can introduce new settings. It can technically be done, but generally shouldn’t. SERI is actually built and maintained by SailPoint so no worries there.
Custom objects are objects which SailPoint doesn’t use, maintain or update. So you can put stuff there without repercussions or colliding with new settings on releases.
I’m encountering performance issues using Custom Object to store list of allowed values. If it is a very large list (e.g. 50,000+) the form does not load. I’m searching compass and I can’t find any article that has a solution for this. Any help would be appreciated.
If you are having performance issues with a Custom object with a very large list, I would recommend moving that list over to a custom database table and accessing it via JDBC. That way, when you create your custom database table, you can create a custom index and have the database index your data so it is more performant when returning the data to your form.
Creating a custom database table with a custom index for your data is more performant because IdentityIQ stores Custom object attributes as an unindexed CLOB column in the database. This works well for most Custom object use cases, but for use cases where large data sets need to be returned from the database in a timely manner, it is recommended to utilize a custom database table with a custom index for that data. Please refer to this article (https://community.sailpoint.com/t5/Technical-White-Papers/BSDG-10-Connecting-to-JDBC-Data-Sources/ta...) for some example code that accesses a custom table stored in IdentityIQ's database schema.
Thanks,
Eric Mendes, CISSP
Platform Architect
SailPoint Certified IdentityIQ Security Architect
Thanks @Eric_Mendes_CISSP ! Appreciate the recommendation.
Looks like ObjectUtil.lockObject does not work when there is no existing Custom object. I was getting this error:
java.lang.IllegalArgumentException: Attempt to generate refresh event with null object
Created one manually and the error went away.
Pasha
7.3p3
That makes perfect sense to me because how can the system lock an object that does not exist in the database? Additionally, if the object is not persisted in the database, then there would be no need to lock the object since no other process could interact with it.
Thanks,
Eric Mendes, CISSP
Platform Architect
SailPoint Certified IdentityIQ Security Architect
@Eric_Mendes_CISSP agreed! The code above for update has it and I just wanted to highlight for those who may use it and see the error.
In my case, I found out when I use a custom object as part of resource customization rule, it is not thread-safe. I had to use transactional locking to make sure it is updated properly.
Very nice article, really helpful
Hi Team,
Can someone help me with below query :
How same custom objects can be reused for all LPARS instead of separate one while integration of IIQ with Mainframe using RACF Full connector ?
Regards,
Gaurav Sule.