Chapter 34

Interfacing with CICS Systems

by Mark Wutka


CONTENTS

IBM's Customer Information Control System (CICS) is an extremely popular transaction processing system. Sites all over the world use CICS for ordering, inventory, accounting, and almost any other business application you can think of. While CICS itself is still a very active operating system, it can be considered a "legacy" system with respect to the Internet.

IBM, realizing the potential of the Internet, has taken huge strides in opening up their products to the Internet. They have created gateways for the AS/400 line of computers and have been pushing them as Web servers. There is also a TCP/IP gateway available for MVS systems, which has been a boon to many MVS shops.

In the area of CICS, IBM has created a CICS Web gateway that allows you to create CGI scripts that make calls into CICS. Rather than just stick with that, however, IBM took a major step forward and created the Java-CICS gateway. The Java-CICS gateway allows a Java applet or application to send requests to a CICS system and receive responses. This gateway sits between the CICS system and your Java programs and translates TCP/IP requests from the Java side into SNA or TCP/IP requests on the CICS side. Figure 34.1 shows the relationship between the Java-CICS gateway, a CICS system, and your Java program.

Figure 34.1 : The Java-CICS gateway connects Java programs to CICS systems.

Tip
The Java-CICS gateway is an excellent example of a non-Java encapsulation program that is Java-friendly.

A Thumbnail Sketch of CICS

CICS is a transaction-processing system that performs a number of very handy functions. First and foremost, it manages multiple simultaneous transactions, some of which may be distributed across multiple machines.

The main focus of CICS is processing transactions. You group operations in a transaction into Logical Units of Work (LUW). You can have multiple LUWs in a single transaction. For instance, booking a seat on an airplane would be considered an LUW. Your entire reservation is a transaction, made up of one or more LUWs (after all, you are probably booking seats on multiple flights).

Like other transaction systems, CICS has the ability to abort or "roll back" a transaction. For instance, when you book a seat on an airplane, you want that booking to be visible immediately. If you get the last seat on a plane, you don't want someone else booking that same seat. If you suddenly decide that you don't want to fly at all, the friendly airline agent helping you build the reservation would then abort the transaction. The CICS system would undo all your seat bookings. This kind of feature is usually associated only with database systems, but CICS is not a database system. You still need a database system to use CICS-either IBM's DB2 database or a variety of popular relational databases.

CICS started out back before personal computers hit the scene, so it is well-versed in communicating with older "legacy" terminals like the IBM 3270 series. IBM has done a good job in keeping CICS up-to-date with clients, and today it supports clients on a large number of platforms, including Windows NT, OS/2, and various flavors of UNIX. CICS didn't remain stuck in the "character mode" frame of mind, either. You can buy automated tools for building Graphical User Interfaces for CICS.

CICS also has the ability to communicate with a variety of clients, and even other CICS servers. It supports the popular TCP/IP protocol, as well as IBM's proprietary SNA protocol and even NetBIOS.

For more information about CICS, visit the CICS home page on the Web at http://www.hursley.ibm.com/cics/.

The CICS External Call Interface

The External Call Interface (ECI) is a mechanism used by CICS to allow non-CICS clients to invoke programs under CICS. CICS has a remote procedure call mechanism called DPL (Distributed Program Link) which allows a CICS program to start up a CICS program on another CICS host. ECI works exactly the same way as DPL, except that the program that originates the call is not running under CICS.

CICS applications are built as a series of programs, where one program runs another program, which is why you can do almost anything you need with ECI.

To run a CICS program using ECI, you must supply CICS with a user name and password, as well as the name of the program you want to run. You pass data to the program via a block of data called the COMMAREA block. The contents of the block vary from program to program. There is no fixed format to the block. Typically, however, you pass text information in the block. If you have to pass a numeric value, you pass numbers as a text string.

You must also pass information about the LUW for your transaction. A unit of work can span multiple ECI calls, if it needs to. An LUW is similar to a transaction in a relational database. As you make changes over the course of an LUW, the changes are not visible to the rest of the system until you commit the LUW, that is, until you save it. If there is a failure of some kind, CICS will undo the changes made so far in the current LUW, but not the previous LUWs.

When you make an ECI call, you pass an LUW token, which is like a session ID for the LUW. When you start a new LUW, you pass a token called ECU_LUW_NEW. CICS will then generate an LUW token value for subsequent ECI calls for this LUW. You must also pass an extend mode parameter for the LUW. You pass either a value of ECI_EXTENDED or ECI_NO_EXTEND. It's very easy to determine when to use ECI_EXTENDED and when to use ECI_NO_EXTEND. You use ECI_NO_EXTEND on the last ECI call in an LUW, and ECI_EXTENDED for all others. If you have only one call in the LUW, it's both the first and last call, so it is sent with the ECI_NO_EXTEND parameter.

Sometimes, you realize you want to back out the LUW (undo the changes) or commit it without actually calling another program. You can use an extend mode of ECI_COMMIT to commit the current LUW, or ECI_BACKOUT to back out the changes in the current LUW.

In addition to the preceding parameters, which are part of the regular ECI interface, you must pass an additional parameter to the Java-CICS gateway. You must supply the name of the CICS server you want to talk to, because the gateway can talk to many different servers.

The Java-CICS Gateway API

While the ECI may seem fairly complicated to you so far, the Java API is actually very simple. In fact, the API consists of only two classes-the JGateConnection class and the ECIRequest class.

The JGateConnection class represents a connection to a Java-CICS gateway server. You can create multiple connections to a single server, or to different servers. You can perform only one ECI call at a time over a single connection. You can perform as many ECI calls as you like over one connection, just one at a time.

The constructor for the JGateConnection class takes two parameters-the name and port number of the gateway server you are connecting to. For example:

JGateConnection cicsGateway = new JGateConnection(
"gateway.myplace.com", 4321);

Once you have created the connection, you use the flow method to send ECI requests to the gateway. The flow method takes an ECIRequest object as its only parameter. Any information returned from the ECI call is stored in the Commarea array in the ECIRequest.

You create an ECIRequest by passing its constructor the name of the CICS server, the user name, password, Commarea, extend mode, and LUW token.

Suppose you had a CICS program called "BOOKSEAT" that booked a seat on an airline flight. Furthermore, assume that the name of the CICS server is "RES," and that the user name and password are airjava and whee, respectively. Also, assume that you must store a 4-digit flight number, a 5-digit date in the form DDMMM, and a 3-letter seat number in the Commarea. The following code segment would create the ECIRequest to book seat 35B on flight 5050 on January 12. Also, this is a one-shot LUW, so use an extend mode of ECI_NO_EXTEND, and an LUW token of ECI_LUW_NEW.

byte[] commarea = new byte [12];
// A quickie to copy a string into a byte array
"505012JAN35B".getBytes(0, 12, commarea, 0);
ECIRequest request = new ECIRequest("RES", "airjava", "whee",
     "BOOKSEAT", commarea, ECI_NO_EXTEND, ECI_LUW_NEW);

To send this request to CICS, you use the flow method in the JGateConnection object, like this:

cicsGateway.flow(request);    // send the ECI request

Once you send the request, you can check the CICS return code, which is stored in the Cics_Rc variable in the ECIRequest object. If the request completed successfully, the Cics_Rc value should be 0.

Creating Multiple-Call LUWs

The one-shot, or single-call, LUW is very simple to make, and will probably cover most situations for you. When you do a multiple-call LUW, there are a few extra things you have to deal with:

Tip
If you reuse the same ECIRequest object for each ECI call in an LUW, the Luw_Token variable will already contain the correct LUW token value. You need to change only the token value when you start a new LUW.

Suppose you want to book a round-trip flight using the BOOKSEAT program illustrated previously. Because you want this to be a single LUW, that is, you want to book both seats as a single transaction, you call BOOKSEAT twice as part of a single LUW. The following code books seat 35B on flight 5050 on January 12 and seat 12A on flight 1313 on January 13 as a single LUW:

byte[] commarea = new byte [12];
// A quickie to copy a string into a byte array
"505012JAN35B".getBytes(0, 12, commarea, 0);
// Book the first flight leg
ECIRequest request = new ECIRequest("RES", "airjava", "whee",
     "BOOKSEAT", commarea, ECI_EXTENDED, ECI_LUW_NEW);
cicsGateway.flow(request);     // send the ECI request
// Now copy in the return flight leg
"131313JAN12A".getBytes(0, 12, commarea);
// Change the extend mode on the ECI request to ECI_NO_EXTEND
request.Extend_Mode = ECI_NO_EXTEND;
// Book the second flight leg
cicsGateway.flow(request);     // send the ECI request

Caution
Be careful when creating multiple-call LUWs. If there is a significant amount of time between calls, you could keep system resources locked unnecessarily. Remember that CICS keeps certain locks on data while an LUW is in progress.

Creating Web Interfaces to CICS

Even before IBM came out with the Java-CICS gateway, you were able to provide Web access into CICS systems. Using a CICS TCP/IP gateway, you could write CGI scripts that used ECI to run programs on the CICS system. Figure 34.2 illustrates this configuration.

Figure 34.2 : A CICS TCP/IP gateway allows CGI programs to make ECI calls.

As usual, this solution suffered from the usual problems of CGI-the CGI program exited after each request, and you had fairly high session-startup costs.

As you might guess, a Java Web server is an excellent alternative to CGI when accessing CICS. You could, if you wanted, create a servlet that talked to a CICS TCP/IP gateway, but there's no need to do this when IBM has already created the Java-CICS gateway.

You can create Java servlets that execute CICS programs. The advantage to the servlets is that they can use existing connections to the CICS gateway, eliminating the session startup overhead you get with CGI. Figure 34.3 illustrates the relationship between the servlet, the Java-CICS gateway, and the CICS system.

Figure 34.3 : The Java servlet relating to the Java-CICS gateway and the CICS system.

You can use the techniques outlined in Chapter 33, "Web-Enabling Legacy Systems," to preserve session information, so you can perform multiple-call LUWs via Web requests.

Recall that in Chapter 33, you created a session ID variable that was used as a lookup value for the session-related information. In the CICS case, the session components you are concerned with are the JGateConnection and the Luw_Target for the LUW. Using these two values, you can create an ECI request for an existing LUW. The following class saves the information for the session:

public class LUWSession
     public JGateConnection connection;
     public int LUWTarget;
     public LUWSession(JGateConnection connection,
          int LUWTarget)
     {
          this.connection = connection;
          this.LUWTarget = LUWTarget;

Providing a CORBA Interface to CICS

It would be really nice if there were a standard CORBA interface into CICS, but in the meantime, you can provide your own CORBA access to CICS in a variety of ways.

Creating a CORBA-CICS Gateway

You may want to use the Java-CICS gateway from a number of CORBA clients, maybe even non-Java clients. One way you can do this is to define an IDL interface that mimics the ECI interface. The following IDL definition creates one such interface:

module CICS {
// Define the different values for the extend mode
     enum ExtendType {
          ECI_NO_EXTEND,
          ECI_EXTENDED,
          ECI_BACKOUT,
          ECI_COMMIT
     };
// Define the constant for a new LUW token
     const long ECI_LUW_NEW = 0;
// Set up a data type for the commarea
     typedef sequence<octet> byteArray;
     interface ECI {
// Define the flow method that will send calls to CICS
          void flow(in string serverName, in string programName,
               in string userName, in string password,
               inout byteArray commarea,
               in long extendMode, inout long luwToken);
     };
};

The preceding interface should look very familiar because it is the same as the Java-CICS gateway API. It simply wraps a CORBA framework around the old API. You still have to do the work of implementing the CORBA server, but all it would do is create an ECI request, pass it to a JGateConnection object, and update the luwToken value. This is not necessarily the best way to create a CORBA interface to CICS, however. Figure 34.4 illustrates how this CORBA-CICS gateway fits in with the client, the Java-CICS gateway, and the CICS system.

Figure 34.4 : A CORBA-CICS gateway uses the Java-CICS gateway to make ECI calls.

The reason you probably want to avoid setting things up this way is that you don't want to carry the CICS-specific features into your future versions. In other words, an interface like this is one of those cases where the remnants of a legacy system can stay embedded in your application long after the legacy system has departed. For example, suppose you write all your applications to use this ECI interface over CORBA. You're now passing all sorts of different requests using the same method call. The only difference between the requests is the program name and the contents of the Commarea.

Now, suppose you replace your CICS system with a newer one. If you don't want to replace all your existing applications, you have to create an encapsulation that maps the program name and Commarea information to whatever the new system needs. Someone looking at an application cannot determine what a particular ECI call does without knowing what the CICS program did.

Creating CORBA Interfaces to CICS Programs

Following the encapsulation principles from Chapter 32, look at the CICS system as an application or group of applications to see what it actually does. For example, the BOOKSEAT program from earlier in this chapter can be represented by the following IDL interface:

module Reservations {
     struct Date {
          short year;
          short month;
          short day;
     };
     interface Booking {
          void bookSeat(in short flightNumber,
               in Date date, in string seat);
     };
};

Your CORBA server for this interface would invoke the BOOKSEAT program in the CICS system. Unlike the previous CORBA interface, this one is not tied to the CICS system. Remember that the dates in the CICS reservations system were specified in DDMMM format, like 04JUL or 25DEC. Because other systems may not use a notation like that, the CORBA Reservations module defines a generic date class that the CORBA server can then convert into whatever format it needs to.