com.ibm.datapower.wamt.clientAPI
Class Lock

java.lang.Object
  extended by com.ibm.datapower.wamt.clientAPI.Lock

public class Lock
extends java.lang.Object

An implementation of a re-entrant lock that can be either blocking (like synchronized) or non-blocking (fail-fast). The purpose of this implementation is to provide a lock to write methods with the ability to test if another thread already owns the lock. That is not available with the synchronized keyword.

All updates (writes) to anything in an object that uses Lock must invoke lockNoWait(), whether done by the clientAPI or internally via a background thread. Each object that uses Lock has its own instance of a Lock object, these instances of Lock operate independently of each other (e.g., calling lockNoWait() on one device does not prevent using (locking) another device on another thread.

The intention is for callers of the clientAPI to invoke only short-running tasks. If the lock exists when the clientAPI is invoked (for example, because a separate thread already has it locked for a short running or long running task), the clientAPI method which does not own the lock will fail with an LockBusyException.

Anything long-running should be queued for execution by a background thread (see ProgressContainer). If the background execution queue is already full (which is not the default behavior), then a FullException will be thrown. (For more information about this circumstance, see FullException.) Instead of failing fast, the background execution thread should block until the lock is available, since there is no user interface penalty when a background thread blocks for a long period.

Locking design:

The following may seem unnecessarily complicated (i.e., why not just use synchronized ?), but there are some unusual requirements:

Best practices for using Lock:

The public clientAPI methods must not be long-running. If there is a task that requires a long run, then it should be queued for another thread to execute. This is because the UI (consumer of the clientAPI) must be responsive and not block for indeterminate periods. The UI could be any client (i.e., servlet, or a rich client).

Locks are fail-fast. If a thread tries to acquire a lock that is already held by another thread, the thread trying to acquire the busy lock will fail without blocking or waiting. This means that callers should expect to either acquire the lock quickly, or receive an exception quickly. If a caller receives an exception while trying to acquire a lock, it may (at the caller's discretion) retry the lock acquisition at a later time or abort the entire operation. [Note: requests for locks via the clientAPI should fail-fast. However, daemons can wait for locks to be acquired, so this class provides a lockWait() method that will block until the lock is available. So this class needs to support both fail-fast acquisition and blocking acquisition.]

If the thread is unable to obtain all the locks it requires, it should fail and release the locks it was able to obtain up until the failure point.

Objects that implement the Persistable interface can be persisted to a datastore using the dataAPI. Those objects can be deleted from the datastore. If you try to use an object that has been deleted from the datastore and you still have a reference to that object, it will throw a DeletedException. This is necessary because the datastore has the notion of a delete or destructor, but Java objects do not have the notion of a destructor that can be immediately invoked such as in C++. It is not considered acceptable to access a persistable Java object that was deleted from the datastore. If this occurs, an exception will be thrown. Because the clientAPI has a lot of persistence, a lot of the clientAPI methods will throw a DeletedException.

All the Lock methods are synchronized, meaning that access is serialized around the lock, not serializing around the work areas directly.


Field Summary
static java.lang.String COPYRIGHT_2009_2013
           
 
Constructor Summary
Lock(java.lang.String name)
          Create a mutex lock.
 
Method Summary
 boolean isAvailable()
          Check if the lock is available for acquisition by this thread.
 void lockNoWait()
          Try to acquire the lock, but fail fast if the lock is held by another thread.
 void lockWait()
          Acquire the lock, even if it requires blocking until another thread releases this lock.
 java.lang.String toString()
          Get a String representation of this object for the purpose of debugging or tracing.
 void unlock()
          Release the current lock, or decrement the reentrancy counter.
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

COPYRIGHT_2009_2013

public static final java.lang.String COPYRIGHT_2009_2013
See Also:
Constant Field Values
Constructor Detail

Lock

public Lock(java.lang.String name)
Create a mutex lock. It is initially in the unlocked state. You must use one of the lock acquisition methods (lockWait(), lockNoWait()) to trigger the lock to prevent other threads from acquiring it.

Parameters:
name - a human-readable name for the lock. This name will appear in log and exception messages and in the method toString().
Method Detail

isAvailable

public boolean isAvailable()
Check if the lock is available for acquisition by this thread. This method should never block.

Returns:
true if the lock is available for acquisition and is not currently held by another thread, false otherwise. Since this lock is reentrant, it will return true if the current thread already holds this lock.

lockWait

public void lockWait()
Acquire the lock, even if it requires blocking until another thread releases this lock. Because blocking may occur, this method may take an indeterminate amount of time to run. Since the lock is reentrant, this method will return immediately if the current thread already holds the lock. Usually only background tasks will attempt to acquire locks using this blocking method, since background tasks aren't sensitive to being long-running.


lockNoWait

public void lockNoWait()
                throws LockBusyException
Try to acquire the lock, but fail fast if the lock is held by another thread. Since this lock is reentrant, this method will return immediately successfully if the current thread already holds the lock. If the lock is held by another thread, this method will throw a LockBusyException immediately. This method does not block, so it should return (successfully or with an exception) quickly. Usually most clientAPI invocations from a user interface will use this method, since the user interface is sensitive to long-running methods on its threads.


unlock

public void unlock()
Release the current lock, or decrement the reentrancy counter. If this lock has been acquired by the current thread only once (meaning that the reentrancy counter equals 1), then release this lock so that it may be acquired by any thread. If the reentrancy count is greater than 1, then decrement the reentrancy counter by 1 and maintain ownership of this lock. This method should never block.


toString

public java.lang.String toString()
Get a String representation of this object for the purpose of debugging or tracing.

Overrides:
toString in class java.lang.Object
Returns:
a String representation of this object for the purpose of debugging or tracing.


© Copyright IBM Corp. 2006, 2010 All Rights Reserved.