Cooperative Locking
Cooperative locking is a mechanism that is intended to prevent concurrent updates to an object by two or more Content Engine API-based applications. The mechanism is cooperative because applications volunteer to lock objects, check for locks, and honor an object's locked state by not modifying the object until it is unlocked. Note that any application with the appropriate permissions can perform any action on an object regardless of whether it is locked or not. In addition, an object's lock is not checked or honored by non-cooperating applications. Cooperative locking does not prevent an application from updating or deleting a locked object. Cooperative locking provides a voluntary mechanism to lock objects, test for locks, and decide which action to take based on the object's lock state.
You can lock objects of the following interfaces (and subinterfaces):
CustomObject, Document, and Folder. These
interfaces provide methods for locking, unlocking, extending a lock, and checking the lock status of
an object. In addition, the superinterface, Containable, provides
readable properties with lock information, such as the owner and duration of a lock.
Locking or unlocking an object creates a pending action instance
of Lock or Unlock. When these actions are committed to the server,
a LockEvent or
UnlockEvent is
triggered. These events can be audited.
To modify a document, folder, or custom object, an application that participates in cooperative locking performs the following steps:
- Lock the object
- Apply changes to the object
- Unlock the object
Before you modify a document, folder, or custom object, an application that participates in cooperative locking would first check the lock state of an object, and, if locked, perhaps get information about the lock.
For code samples, see Working with Lockable Objects.
Locking an Object
You apply a lock to an object by calling the object's lock method. The
timeout parameter of the lock method is the number of seconds that
the object is to be locked. The expiration time equals the time value of the object's
DateLastModified property plus the number of seconds specified in the lock method's
timeout parameter. Subsequent update activity on an object by the lock owner causes
the DateLastModified time to change, which has the side effect of refreshing the lock and extending
the lock's timeout period. The lock owner can also explicitly call the updateLock method to extend
the lock's timeout period. Although calling this method is the recommended way to extend a lock, a
similar effect might be achieved by calling the unlock method followed by the
lock method, another application might intervene between the calls and steal the
lock.
After you
call the lock or updateLock method
on an object, you must save it to commit the lock operation on the
server. You must have at least the AccessRight.WRITE permission
to successfully run the save.
While a CustomObject, Document, or Folder is
locked, other cooperating applications must treat the object as if
they have read access to it until the lock is removed or expires.
Applying Changes
After an object is locked, the lock owner can modify the content, properties, and permissions of the locked object as is normally done. The extent of the modifications that can be performed depends on the scope of the lock owner's permissions.
Unlocking an Object
The owner of an object's lock can remove the lock in one of the following ways:
- By calling the unlock method. Only the lock owner can remove an existing lock.
- By allowing the lock's timeout value to expire.
If you attempt to unlock an object that's not locked, an EngineRuntimeException is thrown
with an exception code of E_OBJECT_NOT_LOCKED.
Checking Lock Status
An application that participates in cooperative locking must determine the lock status of a
CustomObject, Document, or Folder object before
it attempts to modify the object. While the isLocked method is provided
to test the lock status, note that this method returns an approximation of the locked state at the
time of the call. After this method runs and returns the value, the object's lock state might be
immediately changed by another application's call to the lock method or the lock
might expire. Therefore, the recommended way of testing the status is to call the
lock method and then handle any exception that is thrown if the method fails.
If an object is locked, an application can get information about the lock from the Containable
interface, which has the following lock-related, read-only properties. These properties are
populated as a result of a successful call to the lock method, and are stored in
the property cache of the object.
- LockOwner property identifies the client that exclusively owns the write-access lock on the object.
- LockToken property contains a string (GUID) that represents a lock.
- LockTimeout
property value is used to calculate a lock's expiration time. The property's value is initially set
by the
lockmethod, and the value can be reset by a call toupdateLock. The property value is the number of seconds beyond the value in the object's DateLastModified property that the lock owner can hold the lock on the object. (If the DateLastModified property is not set, the DateCreated property value is used for the calculation.) The result of the calculation is measured against the current system time. The lock is considered expired when the value of the object's DateLastModified property value plus the value of the LockTimeout property is less than the current system time.