Cooperative locking is a mechanism 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 has been 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 neither checked nor honored by a non-cooperating application (such as Enterprise Manager). Cooperative locking does not prevent an application from updating or deleting a locked object. Cooperative locking simply provides a voluntary mechanism to lock objects, test for locks, and decide which action to take based on the object's lock state.
NOTE To successfully use cooperative locking, you must synchronize machine clocks on your server and client machines.
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 participating in cooperative locking would perform the following steps:
Before modifying a document, folder, or custom object, an application participating 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.
You apply a lock to an object by calling the object's lock method. However, you cannot lock the following:
Document
object that is checked out by another userDocument
object (that is, one whose IsFrozenVersion
property is true
).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. This is the recommended way to extend a lock;
although a similar effect could be achieved by calling unlock
followed
by lock
, another application could intervene between the calls
and steal the lock.
Keep in mind that after calling the lock
or updateLock
method on an object, you must save it to commit the lock operation on the server. Therefore, you must have permission to at least modify the object in order to successfully execute the save. For example,
to lock a Folder
object, AccessLevel.WRITE_FOLDER
or AccessLevel.FULL_CONTROL
must be set to "allow" for the caller.
As long as a CustomObject
,
Document
, or Folder
is locked, other cooperating applications must treat the object as if they have only read access to it until the lock is removed or expires.
Once an object is locked, the lock owner can modify the content, properties, and permissions of the locked object as is normally done. Of course, the extent of the modifications that can be performed depends on the scope of the lock owner's permissions.
The owner of an object's lock can remove the lock in one of the following ways:
If you attempt to unlock an object that's not locked, an EngineRuntimeException
is thrown with an exception code of E_OBJECT_NOT_LOCKED
.
An application participating 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. Once this method executes and returns the value, the object's lock state could be immediately changed by another application's call to the lock
method or the lock could expire. Therefore, the recommended way of testing the status is to call the lock
method and then handle any exception 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.
lock
method, and the value can be reset by a call to updateLock
. 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.NOTE Because these properties will be set continuously for objects in high demand by cooperative applications, refresh these properties before retrieving them to ensure that you get the most current values from the server.