Transmit rule - Java™ example 2

The following example assumes that the transmission of the messages takes place over a communications network that charges for the time taken for transmission. It also assumes that there is a cheap-rate period when the unit-time cost is lower. The rules block any transmission of messages until the cheap-rate period. During the cheap-rate period, the queue manager is triggered at regular intervals.

import com.ibm.mqe.*;
import java.util.*;
/**
* Example set of queue manager
    rules which trigger the transmission
* of any messages waiting to be sent.
*
* These rules only trigger the
    transmission of messages if the current
* time is between the values defined
    in the variables cheapRatePeriodStart
* and cheapRatePeriodEnd
* (This example assumes that transmission
      will take place over a
* communication network which charges 
      for the time taken to transmit)
*/
public class ExampleQueueManagerRules extends MQeQueueManagerRule
implements Runnable
{
    // default interval between triggers is 15 seconds
    private static final long 
          MILLISECS_BETWEEN_TRIGGER_TRANSMITS = 15000;
    
    // interval between which we c
      heck whether the queue manager is closing down.
        private static final long
          MILLISECS_BETWEEN_CLOSE_CHECKS = 1000 ;
    
    // Max wait of ten seconds to kil off
        the background thread when 
    // the queue manager is closing down.
    private static final long
        MAX_WAIT_FOR_BACKGROUND_THREAD_MILLISECONDS = 10000;
    
    // Reference to the control block used to
        communicate with the background thread
    // which does a sleep-trigger-sleep-trigger loop.
    // Note that freeing such blocks for garbage
        collection will not stop the thread
    // to which it refers.
    private Thread th = null;
    
    // Flag which is set when shutdown of
        the background thread is required.
    // Volatile because the thread using the
        flag and the thread setting it to true
    // are different threads, and it is
        important that the flag is not held in
    // CPU registers, or one thread will
        see a different value to the other.
    private volatile boolean toldToStop = false;
   //cheap rate transmission period start and end times
    protected int cheapRatePeriodStart = 18;  /*18:00 hrs */
    protected int cheapRatePeriodEnd = 9;     /*09:00 hrs */
}

The cheapRatePeriodStart and cheapRatePeriodEnd functions define the extent of this cheap rate period. In this example, the cheap-rate period is defined as being between 18:00 hours in the evening until 09:00 hours the following morning.

The constant MILLISECS_BETWEEN_TRIGGER_TRANSMITS defines the period of time, in milliseconds, between each triggering of the queue manager. In this example, the trigger interval is defined to be 15 seconds.

The triggering of the queue manager is handled by a background thread that wakes up at the end of the triggerInterval period. If the current time is inside the cheap rate period, it calls the MQeQueueManager.triggerTransmission() method to initiate an attempt to transmit all messages awaiting transmission. The background thread is created in the queueManagerActivate() rule and stopped in the queueManagerClose() rule. The queue manager calls these rules when it is activated and closed respectively.

/**
* Overrides MQeQueueManagerRule.queueManagerActivate()
* Starts a timer thread
*/
public void queueManagerActivate()throws Exception {
    super.queueManagerActivate();
    // background thread which triggers transmission
    th = new Thread(this, "TriggerThread");
    toldToStop = false;
    th.start();    // start timer thread        
}


/**
* Overrides MQeQueueManagerRule.queueManagerClose()
* Stops the timer thread
*/
 public void queueManagerClose()throws Exception { 
    super.queueManagerClose();
        
    // Tell the background thread to stop, 
      as the queue manager is closing now.
    toldToStop = true ;
        
    // Now wait for the background thread, 
      if it's not already stopped.
    if ( th != null)  {
        try { 
        // Only wait for a certain time before 
        giving up and timing out.
         th.join( MAX_WAIT_FOR_BACKGROUND_THREAD_MILLISECONDS );
     
         // Free up the thread control block for garbage collection.            
            th = null ;
        } catch (InterruptedException e) { 
            // Don't propogate the exception. 
            // Assume that the thread will stop shortly anyway.
        }
    }    
}
 

The code to handle the background thread looks like this:

/**
* Timer thread
* Triggers queue manager every interval until thread is stopped
*/
public void run()    {
    /* Do a sleep-trigger-sleep-trigger loop until the */
   /*  queue manager closes or we get an exception.*/
    while ( !toldToStop) {
        try {               
            
            // Count down until we've waited enough
          // We do a tight loop with a smaller granularity because 
          // otherwise we would stop a queue manager from closing quickly
          long timeToWait = MILLISECS_BETWEEN_TRIGGER_TRANSMITS ;
          while( timeToWait > 0 && !toldToStop ) {
            
            // sleep for specified interval                                 
                Thread.sleep( MILLISECS_BETWEEN_CLOSE_CHECKS );
                
                // We've waited for some time. 
              Account for this in the overall wait.
                timeToWait -= MILLISECS_BETWEEN_CLOSE_CHECKS ;
          }
   if( !toldToStop && timeToTransmit()) {
            // trigger transmission on QMgr (which is rule owner)       
            ((MQeQueueManager)owner).triggerTransmission();
                      }
          } catch ( Exception e ) {
              e.printStackTrace();
          }
        }
    }
}

The variable owner is defined by the class MQeRule, which is the ancestor of MQeQueueManagerRule. As part of its startup process, the queue manager activates the queue manager rules and passes a reference to itself to the rules object. This reference is stored in the variable owner.

The thread loops indefinitely, as it is stopped by the queueManagerClose() rule, and it sleeps until the end of the MILLISECS_BETWEEN_TRIGGER_TRANSMITS interval period. At the end of this interval, if it has not been told to stop, it calls the timeToTransmit() method to check if the current time is in the cheap-rate transmission period. If this method succeeds, the queue manager's triggerTransmission() rule is called. The timeToTransmit method is shown in the following code:

protected boolean timeToTransmit()    {
    /* get current time */
    Calendar calendar = Calendar.getInstance();
    calendar.setTime( new Date() );
    /* get hour */
    int hour = calendar.get( Calendar.HOUR_OF_DAY );
    if ( hour >= cheapRatePeriodStart || hour 
            < cheapRatePeriodEnd ) {
        return true; /* cheap rate */
    }
    else    {
        return false; /* not cheap rate */
    }
}

Terms of use | WebSphere software

(c) Copyright IBM Corporation 2004, 2005. All rights reserved.