Using TimerWaitActivity

This implementor allows to put the process on pause for certain period of time, and is referred to as Timer activity.

The activity takes two common attributes, "Amount", which specifies the number of units to wait (the internal attribute name is indeed "TIMER_WAIT") and "Unit" for the wait amount (Seconds, Minutes, or Hours, and default to Minutes).

This attribute can also take a binding expression instead of a fixed number. For example, you can specify "${myvar}", which is a variable that is supposed to contain an integer value indicating the number of seconds to wait. You can use an expression to calculate the value dynamically.

Alternatively, you can subclass this implementor and override the method int getWaitPeriodInSeconds() to achieve the desired customization. If you do go this way, you may need to customize the activity pagelet in MDW Studio so that the two attributes are not shown.

To wait for a particular date and time, you can calculate the number of minutes from the time the activity is invoked to the desired date and time.

Note that in the case when you do not need to wait, rather than returning 0 or negative numbers in getWaitPeriodInSeconds(), you should return DEFAULT_WAIT, which is defined as 30 (seconds). The reason for this is to avoid race condition, as returning 0 will immediately trigger a JMS message to resume the activity instance.

Notes About Timeouts

Wait For Unsolicited Events

It is often desired that when a process is waiting for a particular time to arrive, it needs to handle unsolicited external events such as receiving a supplemental order or cancellation of the request. The activity allows to optionally register for listening to unsolicited events before the timer expires. It uses the same mechanism as EventWaitActivity to register the event waits (following this link for details of event wait registration and additional details).

When the activity instance receives an event before the timer expires, it can be left in one of the 3 statuses:

We note that the activity can only listen to recurring events. This limitation is needed to avoid infinite looping when the activity instances resume waiting from hold status, non-recurring events that have already arrived would always trigger a transition.

To provide custom code handling unsolicited events, you will need to override processOtherMessage(String message). The method is passed in with one argument, which is the entire message. The default method does nothing. The completion code after processing the message is configured in MDW Studio, but you can override it in the code by invoking setReturnCode().

A word of caution: the wait is implemented via delayed JMS resume messages, so it depends on the persistence of JMS message store provided by the container. In current ECOM practice, a new WLS domain is created for every new release, so the deployment process needs to include a step to copy JMS file store from the old domain to the new domain.

Advanced Usage

The activity allows to wait for additional periods upon timer expiration through customization and this feature can be used to implement a polling pattern - the activity periodically invokes custom code to determine if further wait is needed. This functionality is used to replace work transition validator concept in MDW 3.*.

We must emphasize that this feature is not recommended, due to the fact that polling may take a lot more CPU resources. The recommended approach is to use the event wait activity.

There are two ways to use these feature. The first way is very similar to that of work transition validator in MDW 3.*. You specify a custom validator in the attribute Custom Validator, which must be a class name. That class must implement the interface com.centurylink.mdw.workflow.work.transition.validation.WorkTransitionValidator (the name is kept for backward compatibility reasons). The class must implement 3 methods of the interface:

The second and perhaps more preferred method is to subclass this activity and override the method boolean processTimerExpiration(). Your method needs to return true when no more wait is needed, and must invoke void sendDelayedResumeMessage(int seconds) and return false when further delay is needed. The following is a sample implementation of the method.
     protected boolean processTimerExpiration() 
         throws ActivityException
     {
         // determine number of seconds to wait further
         // a 0 or negative number indicates no further wait is needed
         int seconds = customLogicToDetermineHowLongToWait();
         if (seconds>0) {
             logger.info("Wait for additional " + seconds + " seconds");
             sendDelayedResumeMessage(seconds);
             return false;
         } else return true;
     }