The EPI C++ classes support synchronous ("blocking"), and deferred synchronous ("polling") and asynchronous ("callback") protocols.
In the example above the CclSession object is created with the synchronization type of Ccl::sync. When this CclSession object is passed as the first parameter on a CclTerminal send method, a synchronous call is made to CICS®. The C++ Client application is then blocked until the reply was received from CICS. When the reply is received, updates are made to the CclScreen object according to the 3270 data stream received, then control is returned to the C++ program.
To make asynchronous calls the CclSession object used on the CclTerminal send method is created with a synchronization type of Ccl::async. The call is made to CICS using the CclTerminal send method, but control returns immediately to the Client application without waiting for a reply from CICS. The CclTerminal object starts a separate thread which waits for the reply from CICS. When a reply is received, the handleReply method on the CclSession object is invoked. To process the reply, the handleReply method should be overridden in a CclSession subclass:
class MySession : public CclSession { public: MySession(Ccl::Sync protocol) : CclSession( protocol ) {} // Override reply handler method void handleReply( State state, CclScreen* screen ); };
The implementation of the handleReply method can process the screen data available in the CclScreen object, which will have been updated in line with the 3270 data stream sent from CICS:
void MySession::handleReply( State state, CclScreen* screen ) { // Check the state of the session switch( state ) { case CclSession::client: case CclSession::idle: // Output data from the screen for ( int i=1; i < screen->fieldCount(); i++ ) { cout << "Field " << i << ": " << screen->field->text(); screen->setAID( CclScreen::PF3 ); … } // end switch }
Most Client application will want to wait until the CICS server program has finished sending data (that is, the CclSession/CclTerminal state is client or idle) before processing the screen. However, some long-running server programs may send intermediate results or progress information that can usefully be accessed while the state is still server.
try { // Connect to CICS server CclTerminal terminal( "CICS1234" ); // Create asynchronous session MySession session(Ccl::async); // Start CESN transaction on CICS server terminal.send( &session, "CESN" ); // Replies processed asynchronously in overridden // handleReply method … } catch ( CclException &exception ) { cout << "CclClass exception: " << exception.diagnose() << endl; }
Note that the handleReply method is run on a separate thread. If the main Client application program needs to know when the reply has been received, a message or semaphore could be used to communicate between the handleReply method and the main program.
try { // Connect to CICS server CclTerminal terminal( "CICS1234" ); // Create deferred synchronous session MySession session(Ccl::dsync); // Start CESN transaction on CICS server terminal.send( &session, "CESN" ); … if ( terminal.poll()) // reply processed in handleReply method else // no reply received yet } catch ( CclException &exception ) { cout << "CclClass exception: " << exception.diagnose() << endl; }
A CICS server transaction may send more than one reply in response to a CclTerminal send call. More than one CclTerminal poll call may therefore be needed to collect all the replies. Use the CclTerminal state method to find out if further replies are expected. If there are, the value returned will be server.
As in the synchronous and asynchronous cases, the handleReply method can conveniently be used to encapsulate the code processing the 3270 data returned from CICS from one or more transmissions.