Exploiting CICS Channels and Containers from Java clients

Beyond the 32KB COMMAREA limit


Introduction to CICS channels and containers

Prior to CICS TS V3, program-to-program communications between CICS applications was limited to the COMMAREA (short for communications area). This single communications area has a maximum size of approximately 32KB which limited the maximum amount of data exchanged per call and imposed a tightly coupled interface between requester and provider applications (see Figure 1). In addition, to convert COMMAREA data into a different code page, you have to assemble CICS DFHCNV templates to enable CICS to perform the conversion based on the name of the program invoked. This process has limited flexibility and complicates application development by adding a system programming tasks into the application development lifecycle.

Figure 1. Using a COMMAREA for inter-program communication
Diagram of COMMAREA linkages
Diagram of COMMAREA linkages

With CICS TS V3, for program-to-program communications you can now place virtually unlimited amounts of data into a set of named containers associated with a specific channel. You can place any number of containers in a given channel, and then pass the channel (with all of its containers) to the target program (see Figure 2). Rather than any specific size limitation inherent in the communications area, the amount of data that can now be transferred in a channel is only limited by the 31-bit addressability of a CICS region, which implies an upper limit of 2GB for each container.

Figure 2. Using channels and containers for inter-program communication
Diagram of Container linkages
Diagram of Container linkages

Using channels and containers in CICS

For any given CICS program, you can only use one channel at time, the name of which you can dynamically discover using the ASSIGN CHANNEL command. This channel effectively defines the interface with the partner application as defined by the exchanged containers. You retrieve individual containers from the channel using the GET CONTAINER command, and conversely place container data into a channel using the PUT CONTAINER command. The CICS COBOL code snippet in Listing 1 illustrates the use of these commands.

Listing 1. Using channels and containers in CICS/COBOL
       01 INPUT-CONT       PIC X(16) VALUE 'INPUTDATA'.
       01 INPUTSTRING      PIC X(72) VALUE SPACES.  

                    FLENGTH(INPUTLENGTH) END-EXEC.

      * Perform business logic here     


Using channels and containers in a Java client

A Java client application can similarly use the same channel and container mechanism to interface with CICS programs, using the new Channel class provided with the existing base classes (JavaGateway and ECIRequest). You construct a channel object ahead of time and then create containers from it using the createContainer() method. You can then populate the channel object and pass it on the ECI request call using the new channel-based ECIRequest class constructor. Listing 2 shows a snippet of Java code that implements this process.

Listing 2. Using channels and containers in a Java client
try {
JavaGateway javaGateObject = new JavaGateway(“tcp://localhost", 2006); 		// 01
Channel theChannel = new Channel(“CTGCHANNEL”);					// 02
theChannel.createContainer(“INPUTDATA”, “Hello CICS”);				// 03
ECIRequest eciRequestObject = new ECIRequest(					// 04
					ECIRequest.ECI_LUW_NEW );

javaGateObject.flow(eciRequestObject);						// 05

if (eciRequestObject.getRc() == 0) {						// 06
Container cont = null;
cont = theChannel.getContainer(“OUTPUTMESSAGE”);				// 07
String str = cont.getCHARData();
System.out.println (“Returned data” + str);					// 08
} catch (Exception e) {
  System.out.println("Unexpected Exception:"+e);


  1. Create the Java Gateway connection using the specified host name and port, which opens the socket connection to the Gateway daemon.
  2. Create a Channel with the specified name.
  3. Add a CHAR container to the channel and populate it with the input string.
  4. Create an ECI request with the specific properties.
  5. Flow the ECI request using the existing JavaGateway object.
  6. Check for errors on the flow.
  7. Get the output message container from the channel.
  8. Use the getCHARData() method on the container to obtain the output string from the CICS application.

Enhancing your application

The container and channel approach to passing data is quite different from the traditional CICS COMMAREA approach. When using COMMAREAs for data transfer it is typical to pass a single fixed size buffer large enough to hold both the input data and the response data, and then rely on the CICS optimizations to remove trailing null data from the network flows. Containers, on the other hand, can be variable in size and number, and can be created, modified or deleted from the channel by either the sender or receiver. Containers, on the other hand, can be variable in size and number, and can be created, modified or deleted from the channel by either the sender or receiver.

Optimizing channel flows

When CICS receives a link with a channel, the data returned from CICS updates the Java client’s copy of the containers. If the linked-to program in CICS doesn't change a container, CICS knows that there is no need to send the data for the container back on the return flow because the Java client already has this data. This process minimizes the amount of data transferred across the network. You should design your applications to take advantage of this optimization by separating data into different input, output and error containers. The data from input containers flow on the link, output containers flow on a normal return, and error containers only flow on abnormal returns.

Optimizing data flows

The key to optimizing data transfers with containers is to understand the actual flow of data, the basic principal being that only modified containers are returned by CICS on an ECI or DPL call.

This approach of using separate containers for separate data records allows a much more structured approach to programming and a variety of potential benefits. For example, in a real-life application where CICS returns various types of records in response to a query based on a specific customer identifier, the usage of containers provides a variety of benefits. The client application would no longer need to work with variable length arrays or make multiple invocations to the server, and would simply place the customer identifier in a container associated with a channel and pass the channel to the server. The server program, instead of sending arrays of various sized records in a single COMMAREA, or possibly returning multiple invocations for each record, would place each customer record in its own container, and then return all containers at once. When the data was passed back to the client, the customer identifier container would be unchanged and would therefore not be re-transmitted, but the various records would be available by browsing the returned containers in the channel.

Browsing containers sets

Browsing the containers available in a channel is very simple in Java applications because containers are returned as a java.util.Set that you can simply iterate through. When using the Channel class, the getContainers() method returns a collection of containers. The code in Listing 3 illustrates how to iterate through this collection to browse the available containers returned on an ECI call.

Listing 3. Iterating through the container set
Iterator<Container> it = theChannel.getContainers().iterator();
while (it.hasNext()) {
	Container cont = it.next();
	System.out.print(cont.getName() + " = " + cont.getCHARData());

Error handling

You need to consider these situations to handle errors when using containers and channels:

  • The success of the call to open the connection to the Gateway,
  • The ECI request API call
  • Application errors returned from the CICS application

You can hande connection errors from the call to open the Gateway by simply catching exceptions thrown from the JavaGateway constructor, which opens the socket connection to the remote Gateway. Most exceptions will cause IOExceptions as Listing 4 shows:

Listing 4. Handling connection errors
try {

	JavaGateway javaGateObject = new JavaGateway(CTGURL, CTGPORT);
       // Set ECI call parameters
	} catch (IOException ioe) {
			System.out.println("Could not connect to Gateway: "
			 + ioe.toString());
	catch (Exception e) {
			System.out.println("Handled exception: " + e.toString());

Handling errors from the ECI request API call is quite simple using the getRC() method on the ECIRequest object, which returns both errors form the Gateway daemon and errors from the CICS calls. In addition, you should also check the Abend_Code field if the return code indicates that a CICS abend has occurred, as this may provide further details about abnormal conditions in CICS. The code in Listing 5 illustrates logic to perform this error checking.

Listing 5. Handling errors from the ECI request
if (eciRequestObject.getRc() == 0) { 

//… Analyse results from  ECI call

} else {
	System.out.print(" ECI request failed: RC = "
				+ eciRequestObject.getRcString() + "("
				+ eciRequestObject.getRc() + ")");
				// Get CICS abend code if set
	if (eciRequestObject.getRc() ==  ECIRequest.ECI_ERR_TRANSACTION_ABEND){
		System.out.print(" Abend=" + eciRequestObject.Abend_Code);

Best practices suggest that when you receive data back from the ECI call, before browsing the container set the requesting application should first test for the presence of an error container to determine if the CICS application returned an application level error. The code in Listing 6 shows a simple try catch block to test the channel for the presence of a container called ERRORDATA:

Listing 6. Testing for an error container
try {
	Container errorcont  = theChannel.getContainer(“ERRORDATA”);
		System.out.println(" ERROR: CICS Returned container[" 
		+ errorcont.getName() + "] " + " Data[" 
		+ errorcont.getCHARData().trim() + "]");

	catch (ContainerNotFoundException e) {
		System.out.println(" ECI call completed successfully”);
	catch (Exception e) {
		System.out.println("Exception handling Error container: "
			+ e.toString());

Data conversion: CHAR and BIT containers

If you need to transfer data into CICS from a Java client on a UNIX or Windows system, you will usually need to convert character data from ASCII to EBCDIC. Unlike COMMAREA-based data transfers, the data conversion models for containers are much simpler with conversion occurring dynamically at the point of access by the API. This means that no CICS DFHCNV templates are required, and instead delegates control to the application programmer to ensure the data is correctly transferred.

There are two fundamentally different types of containers; CHAR and BIT, and only CHAR based containers are eligible for data conversion. So the first test is to work out which type of container you have been passed. You can easily use the enum ContainerType to test for CHAR or BIT containers, as Listing 7 shows

Listing 7. Testing for CHAR or BIT containers
Iterator<Container> it = theChannel.getContainers().iterator();
while (it.hasNext()) {

	Container cont = it.next();
	switch (cont.getType()) {

	case CHAR: 
		System.out.print("\t[CHAR] " + cont.getName() + " = ");
	case BIT: 
		System.out.print("\t [BIT] " + cont.getName() + " = ");
		byte[] data = cont.getBITData();			
                              //Process byte array here… 

By default all CHAR containers created by the CICS Transaction Gateway are created in the default JVM encoding of the Java client, which will typically be an ASCII or Unicode style encoding. Figure 3 illustrates how data is converted when passed into CICS from a Linux/Intel client using the default JVM UTF-8 encoding:

Figure 3. Data conversion for CHAR containers
Diagram of data conversion
Diagram of data conversion

The flow of data from the Java client to the CICS program and back is as follows:

  1. A String object is initially created in the Java client, encoded in Unicode.
  2. A new Container object is created in a channel and is populated with the String. This creates a new CHAR container with a byte array encoded in the default JVM encoding of UTF-8.
  3. The UTF-8-encoded container data flows to CICS in the specified channel.
  4. CICS receives the channel and makes the containers available to the linked to program.
  5. The CICS program issues a GET CONTAINER command, and the data is dynamically converted from the channel code page of UTF-8 to the local CICS EBCDIC encoding. This is the code page specified in the CICS SIT option LOCALCCSID.
  6. The CICS program issues a PUT CONTAINER DATATYPE(CHAR) command, which creates a new container in the named channel, and the data area specified is converted from EBCDIC to the UTF-8 code page of the channel.
  7. The CICS program returns and the channel and its container set flows back from CICS to the Java client
  8. The Java client accesses the returned set of containers using the getCHARdata() method on the Container object. This returns a Java String object, which is again in Unicode.

Coded Character Set Identifiers and Unicode conversion services

Whereas CICS traditionally refers to character sets via an alphanumeric code page (such as “IBM037” or “UTF-8”), you can also use a Coded Character Set Identifier (CCSID) such as 37 or 1208, when dealing with container based data conversion . A CCSID is referred to in numeric form because it is a 16-bit number identifying a specific set of information including the encoding scheme identifier, character set identifier, code page identifier, and additional coding-related required information. The standardized character sets used by IBM are documented at the IBM Globalization site..

CICS uses these CCSIDs internally for all conversion of data in containers. It uses the facilities of the underlying z/OS Unicode Conversion Services to perform any necessary conversion. The complete list of CCSIDs available for use by Unicode Conversion services on any given z/OS configuration can be displayed using the MVS command D UNI,CONV. The output in Listing 8 from the sample MVS command shows that the conversion service is available for conversion from 1208 (UTF8) to 037 (EBCDIC)

Listing 8: Output from Unicode Conversion Services
D UNI,CONV,FROMID=1208,TOID=037       
CUN3000I 10.59.24 UNI DISPLAY 972     
  CONVERSION: 01208-00037-E

Customizing data conversion

Since conversion of large amounts of data from one encoding to another can be a costly operation, it is a good practice to ensure that data is only converted if required and is converted only once. The best way to do this is to use the CICS facilities for conversion using CHAR containers with the system defaults as shown in Figure 3. However, in certain circumstances it may be beneficial to implement a different conversion strategy.

Passing complex records as BIT containers

If you use BIT containers then character data flows to and from CICS as unformatted bytes and is treated as an array of bytes in the ECI API. Neither CICS nor the CICS Transaction Gateway will perform any data conversion and your application will be responsible for marshalling the data between ASCII and EBCDIC encodings if necessary. Typically BIT containers are best used for non-character data such as integers, packed decimal data, or other non-character data. However, it may also be useful if a complex structure, such as an existing record previously used in a COMMAREA interface is re-used as the interface for a container. In this case you could use a BIT container to flow the data as a binary object, and then use specific Java classes to marshal the record data. The J2C data binding classes beans provided by Rational Application Developer V7.5 provide a simple way of importing COBOL records and generating Java wrapper code to access numeric or character data types for use with CICS containers. Further information on using the J2C Data binding beans is listed in the resources section

Overriding container CCSID encoding

Although string objects in Java are held internally in Unicode, they are converted to byte arrays when used to populate containers. These byte arrays are by default encoded in the default encoding set by the JVM, which will be the encoding used to send data to CICS (see Figure 3.) However, if your CICS application requires input in a specific encoding, it is recommended that to optimize the data conversion you should:

  1. Directly set the encoding of the channel in the Java client.
  2. Specify the same encoding in CICS using the INTOCCSID option on the CICS GET CONTAINER command.

For instance, if you have a CICS application that needs to handle input data as Unicode, then the channel CCSID can be set to 1208 (which is UTF-8) as shown in Listing 9.

Listing 9: Overriding the Java client channel CCSID
int ccsid = 1208;                    
Channel theChannel = new Channel(“CTGCHANNEL”);
theChannel.createContainer(“INPUTDATA”, “Hello CICS”);

This setting results in the container data being transmitted to CICS, encoded using UTF-8. The CICS application should then use the INTOCCSID(1208) option on the GET CONTAINER command (see Listing 10) to ensure that the data remains encoded as UTF-8 without being converted to the CICS region’s EBCDIC local CCSID.

Listing 10: Usage of INTOCCSID with GET CONTAINER

If the same container data is subsequently required in an EBCDIC encoding, then you can issue additional GET CONTAINER commands without the INTOCCSID option to retrieve the data encoded in EBCDIC.

Optimizing multiple GETs

In CICS each command to access a container causes data to be converted at the point of access. If you issue multiple GET commands at different points in an application, then the overhead of data conversion will be incurred each time for the same container data. In this case a more optimal solution would be for the CICS application to copy the input container to a temporary channel and then use this container for multiple accesses. This model is illustrated in the CICS COBOL example in Listing 11:

Listing 11: Using a temporary channel
      * Get container from default input channel, data converted        
           EXEC CICS GET CONTAINER(INPUT-CONT)                         

      * Cache converted container in working channel, no conversion     
           EXEC CICS PUT CONTAINER(INPUT-CONT)                         
      * Read container data from working channel, no conversion
      * This GET operation may be repeated several times                
           EXEC CICS GET CONTAINER(INPUT-CONT)                         

      * Return data to new container in default channel, data converted
           EXEC CICS PUT CONTAINER(OUTPUT-CONT)                    
                            FLENGTH(LENGTH OF OUTPUTSTRING)                      

Using our sample application

The sample application provided with this paper provides a Java client and CICS COBOL application illustrating the usage of the techniques outlined in this paper. The Java sample can be used with any CICS Transaction Gateway V7.1 system to test container usage with an interconnected CICS TS V3.2 region.

Reviewing what we learned

In this article we have illustrated how the new CICS Transaction Gateway Channel and Container API can be used in a Java client to quickly and easily exchange large amounts of structured data with a CICS application. We have shown how to efficiently structure your Java code to handle potential error situations, and how to optimize the exchange of data when dealing with ASCII to EBCDIC conversion.

Downloadable resources

Related topics


Sign in or register to add and subscribe to comments.

ArticleTitle=Exploiting CICS Channels and Containers from Java clients