When writing custom IIQ code, whether it be Rules, Workflow or Java classes, is it necessary to lock an object before modification?
Note: In version 5.1 and below, object locking was only supported for Identity objects. Certification locking has been introduced in 5.2.
If you are making modifications to objects, the recommendation is to always lock the object before modification and unlock the object after modification, to prevent concurrent modification errors. For example, multiple executing tasks may try to modify the same object at the same time. This can cause issues, such as IDX ordering problems.
Below is some explanation of various locking parameters as well as a code template that you can use that incorporates locking logic.
/**
* LockInfo.DEFAULT_LOCK_TIMEOUT
* Set to 5, by default.
* The default lock timeout in minutes. This can be overridden
* in the system configuration via the following setting:
* <entry key="persistentLockTimeout" value=""/>
* The lock timeout will not come into play, assuming an object
* lock is properly released.
* Note: When a lock times out, the value in the corresponding
* iiqlock database table column is NOT nulled out. The existing
* value will be overwritten during the next lock attempt, assuming
* the current lock is expired. So a value in this column is not
* necessarily a good indicator that an object is locked. Use
* the "iiq console" command "listLocks" to verify locked objects.
*/
/**
* ObjectUtil.DEFAULT_LOCK_TIMEOUT
* Set to 60, by default.
* Default number of seconds we wait attempting to obtain a
* persistent lock before throwing ObjectAlreadyLockedException.
*/
/**
* LOCK_TYPE_PERSISTENT
* A value for the LOCK_TYPE option that selects a persistent lock.
*
* A persistent lock is an application-level locking convention
* that uses a special column in the object table to indicate
* the lock status. A persistent lock may span transactions.
*
* Persistent locks are appropriate if you need to lock
* an object for a long period of time, or keep an object locked
* across a transaction boundary.
*
* This type of lock is most appropriate for editing sessions in
* the UI. Because it must modify the locked object it has more
* overhead than a transaction lock which makes it less suitable
* for background tasks that scan many objects.
* The other thing to be careful of is that persistent locks require
* a "lock name" that must be passed as the final argument. This is
* part of the value that will be stored in the lock column and needs
* to be unique. If you are certain that more than two instances of
* a custom task won't be running at a time, and this task will not
* launch multiple threads that need to do locking then you can hard
* code a name. If you can't be certain then you will need to generate
* a name, Util.uuid() works but the name will be relatively meaningless.
*/
/**
* LOCK_TYPE_TRANSACTION
* A value for the LOCK_TYPE option that selects a transaction lock.
*
* A transaction lock is held only for the duration of the current
* transaction, it corresponds to a Hibernate fetch with
* LockMode.UPGRADE, which in turn corresponds to a SQL
* select with the "for update" option.
*
* If another transaction has locked this object, the calling
* thread will suspend until the other transaction completes
* (or the request times out).
*
* This type of lock is appropriate for internal background tasks
* that need exclusive access to an object for a short duration
* and don't need the overhead of a persistent lock.
*/
import sailpoint.api.ObjectUtil;
import sailpoint.api.PersistenceManager;
import sailpoint.object.Identity;
import sailpoint.tools.Util;
import sailpoint.tools.GeneralException;
Identity ident = null;
String identityName = "jdoe";
try {
ident = ObjectUtil.lockObject(context, Identity.class, null, identityName, PersistenceManager.LOCK_TYPE_PERSISTENT,
Util.uuid(), ObjectUtil.DEFAULT_LOCK_TIMEOUT);
if ( ident == null ) {
return;
}
// Do something with the locked identity object here
}
catch (GeneralException ge) {
System.out.println(ge.toString());
}
finally {
if (ident != null) {
if (ident.getLock() != null) {
ident.setLock(null);
context.saveObject(ident);
context.commitTransaction();
}
}
}
Is there any particular reason why persistent locks can not be applied to Bundle objects?
As it appears the DB table is missing a lock column...