An important concept in the message processing in the fulfillment process is that no component should handle more than one message per order at any given time.

For example, a component is currently handling a ModifyOrderNotification message for orderId ‘1234’ and a ModifyOrder message for orderId ‘1234’ is received during processing. The ModifyOrder message blocks and waits until the first message finishes running. This does not prohibit any messages that come for another orderId from being processed. This is accomplished with locking and the ClientLockManager. All fulfillment components use the lock manager located at /atg/dynamo/service/ClientLockManager.

The lock acquired is for the key that is returned by the method getKeyForMessage in OrderFulfiller and HardgoodFulfiller. The default implementation returns the orderId specified in the message. This method can be overridden if the key to determine the locking needs to be changed but you want to preserve the principle of having one message per key/message at a time.

The design of the OrderFulfiller and the HardgoodFulfiller uses the ClientLockManager to prevent one component from processing messages for two different orders at the same time. Extending the ModificationHander for either class does not require any locking changes. The only time you should be concerned with locking is if the HardgoodFulfiller is not extended when a fulfiller class is created.

Note: Every ClientLockManager (one per Oracle ATG Web Commerce instance) should be configured to point to the Commerce instance running the ServerLockManager. Every Commerce component should use the same ClientLockManager. For more information on the ServerLockManager, see the SQL Repository Caching chapter in the ATG Repository Guide.

The following example demonstrates how the lock manager is used:

TransactionDemarcation td = new TransactionDemarcation();
try {
       td.begin(getTransactionManager(), td.REQUIRED);
       getClientLockManager().acquireWriteLock(pOrderId);
       LockReleaser lr = new LockReleaser(getClientLockManager(),
                getTransactionManager().getTransaction());
       lr.addWriteLock(pOrderId);

           <insert your code here>

catch (DeadlockException de) {
       if(isLoggingError())
             logError(de);
       return false;
}
catch (LockManagerException lme) {
       if(isLoggingError())
             logError(lme);
       return false;
}
catch(TransactionDemarcationException t) {
      if(isLoggingError())
             logError(t);
      return false;
}
finally {
     try {
        td.end();
     }
     catch(TransactionDemarcationException tde) {
        if(isLoggingError())
              logError(tde);
     }
}

The LockReleaser registers each lock with the transaction. The lock is released when the transaction ends. Because of this, it is imperative that a transaction be in place when the LockReleaser is created. This is the reason for all the code using TransactionDemarcation. For more information on transactions, see the Transaction Management chapter in the ATG Platform Programming GuideATG Platform Programming Guide.