Starting transactions asynchronously

The IccStartRequestQ class enables a program to start another CICS® transaction instance asynchronously (and optionally pass data to the started transaction). The same class is used by a started transaction to gain access to the data that the task that issued the start request passed to it. Finally start requests (for some time in the future) can be cancelled.

Starting transactions

You can use any of the following methods to establish what data will be sent to the started transaction:

The actual start is requested using the start method.

Accessing start data

A started transaction can access its start data by invoking the retrieveData method. This method stores all the start data attributes in the IccStartRequestQ object such that the individual attributes can be accessed using the following methods:

Cancelling unexpired start requests

Unexpired start requests (that is, start requests for some future time that has not yet been reached) can be cancelled using the cancel method.

Example of starting transactions

CICS system ICC1 ICC2
Transaction ISR1/ITMP ISR2
Program ICC$SRQ1/ICC$TMP ICC$SRQ2
Terminal PEO1 PEO2

The scenario is as follows. We start transaction ISR1 on terminal PEO1 on system ICC1. This issues two start requests; the first is cancelled before it has expired. The second starts transaction ISR2 on terminal PEO2 on system ICC2. This transaction accesses its start data and finishes by starting transaction ITMP on the original terminal (PEO1 on system ICC1).

The programs can be found in the samples directory (see Sample source code) as files ICC$SRQ1 and ICC$SRQ2. Here the code is presented without the terminal IO requests.

Transaction ISR1 runs program ICC$SRQ1 on system ICC1. Let us consider this program first:

#include "icceh.hpp"
#include "iccmain.hpp"
void IccUserControl::run()
{

These lines include the header files for the Foundation Classes, and the main function needed to set up the class library for the application program. The run method of IccUserControl class contains the user code for this example.

   IccRequestId          req1;
   IccRequestId          req2("REQUEST1");
   IccTimeInterval       ti(0,0,5);
   IccTermId             remoteTermId("PE02");
   IccTransId            ISR2("ISR2");
   IccTransId            ITMP("ITMP");
   IccBuf                buffer;
   IccStartRequestQ* startQ = startRequestQ();

Here we are creating a number of objects:

req1
An empty IccRequestId object ready to identify a particular start request.
req2
An IccRequestId object containing the user-supplied identifier "REQUEST1".
ti
An IccTimeInterval object representing 0 hours, 0 minutes, and 5 seconds.
remoteTermId
An IccTermId object; the terminal on the remote system where we start a transaction.
ISR2
An IccTransId object; the transaction we start on the remote system.
ITMP
An IccTransId object; the transaction that the started transaction starts on this program's terminal.
buffer
An IccBuf object that holds start data.

Finally, the startRequestQ method of IccControl class returns a pointer to the single instance (singleton) class IccStartRequestQ.

  startQ->setRouteOption( "ICC2" );
  startQ->registerData( &buffer );
  startQ->setReturnTermId( terminal()->name() );
  startQ->setReturnTransId( ITMP );
  startQ->setQueueName( "startqnm" );

This code fragment prepares the start data that is passed when we issue a start request. The setRouteOption says we will issue the start request on the remote system, ICC2. The registerData method associates an IccBuf object that will contain the start data (the contents of the IccBuf object are not extracted until we actually issue the start request). The setReturnTermId and setReturnTransId methods allow the start requester to pass a transaction and terminal name to the started transaction. These fields are typically used to allow the started transaction to start another transaction (as specified) on another terminal, in this case ours.

The setQueueName is another piece of information that can be passed to the started transaction.

  buffer = "This is a greeting from program 'icc$srq1'!!";
  req1 = startQ->start( ISR2, &remoteTermId, &ti );
  startQ->cancel( req1 );

Here we set the data that we pass on the start requests. We start transaction ISR2 after an interval ti (5 seconds). The request identifier is stored in req1. Before the five seconds has expired (that is, immediately) we cancel the start request.

  req1 = startQ->start( ISR2, &remoteTermID, &ti, &req2 );
  return;
}

Again we start transaction ISR2 after an interval ti (5 seconds). This time the request is allowed to expire so transaction ISR2 is started on the remote system. Meanwhile, we end by returning control to CICS.

Let us now consider the started program, ICC$SRQ2.

  IccBuf                buffer;
  IccRequestId          req("REQUESTX");
  IccTimeInterval       ti(0,0,5);
  IccStartRequestQ* startQ = startRequestQ();

Here, as in ICC$SRQ1, we create a number of objects:

buffer
An IccBuf object to hold the start data we were passed by our caller (ICC$SRQ1).
req
An IccRequestId object to identify the start we will issue on our caller's terminal.
ti
An IccTimeInterval object representing 0 hours, 0 minutes, and 5 seconds.

The startRequestQ method of IccControl class returns a pointer to the singleton class IccStartRequestQ.

  if ( task()->startType() != IccTask::startRequest )
  {
    term->sendLine(
          "This program should only be started via the StartRequestQ");
    task()->abend( "OOPS" );
  }

Here we use the startType method of IccTask class to check that ICC$SRQ2 was started by the start method, and not in any other way (such as typing the transaction name on a terminal). If it was not started as intended, we abend with an "OOPS" abend code.

  startQ->retrieveData();

We retrieve the start data that we were passed by ICC$SRQ1 and store within the IccStartRequestQ object for subsequent access.

  buffer = startQ->data();
  term->sendLine( "Start buffer contents = [%s]", buffer.dataArea() );
  term->sendLine( "Start queue= [%s]", startQ->queueName() );
  term->sendLine( "Start rtrn = [%s]", startQ->returnTransId().name());
  term->sendLine( "Start rtrm = [%s]", startQ->returnTermId().name() );

The start data buffer is copied into our IccBuf object. The other start data items (queue, returnTransId, and returnTermId) are displayed on the terminal.

  task()->delay( ti );

We delay for five seconds (that is, we sleep and do nothing).

  startQ->setRouteOption( "ICC1" );

The setRouteOption signals that we will start on our caller's system (ICC1).

  startQ->start( startQ->returnTransId(),startQ->returnTermId());
  return;

We start a transaction called ITMP (the name of which was passed by ICC$SRQ1 in the returnTransId start information) on the originating terminal (where ICC$SRQ1 completed as it started this transaction). Having issued the start request, ICC$SRQ1 ends, by returning control to CICS.

Finally, transaction ITMP runs on the first terminal. This is the end of this demonstration of starting transactions asynchronously.

See Appendix C. Output from sample programs for the expected output from these sample programs.

[[ Contents Previous Page | Next Page Index ]]