Exploiting CICS Channels and Containers from Java clients

Beyond the 32KB COMMAREA limit

Inter-program data transfer with CICS applications from Java clients has traditionally been limited to the maximum size of the communications area (COMMAREA), 32KB. However, now with CICS Transaction Gateway V7.1 you can transfer any number of containers of unlimited size in a new structure called a channel.

In addition to providing the ability to send more data, containers let you portion data into smaller chunks and simplifies the process of data conversion. To use these new capabilities, you will need to use the new IP interconnectivity (IPIC) protocol provided by CICS Transaction Server (CICS TS) V3.2. for use with External Call Interface (ECI) requests from the CICS Transaction Gateway into CICS.

This paper provides background details on basic concepts for using channels and containers in CICS, along with step by step coding examples when using the ECIRequest class, together with a working set of CICS and Java client samples for use as a standalone Java client.

Phil Wakelin (Phil_Wakelin@uk.ibm.com), CICS Transaction Gateway Technical Architect, IBM

Phil Wakelin is the CICS Transaction Gateway Technical Architect, and a member of the CICS strategy and planning team. Based at IBM Hursley, he is an IBM Certified Solutions Expert in CICS Web Enablement and the author of many papers, IBM Redbooks, and CICS SupportPacs.



15 October 2008

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

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

Using channels and containers in CICS

Note: The GET and PUT CICS commands can optionally use the CHANNEL keyword. If this is omitted the current channel in scope will be used, which you can discover using the ASSIGN command as shown in Listing 1.

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 OUTPUT-CONT      PIC X(16) VALUE 'OUTPUTMESSAGE'.
       01 CHANNELNAME      PIC X(16) VALUE SPACES.
       01 INPUTSTRING      PIC X(72) VALUE SPACES.  
       01 OUTPUTSTRING     PIC X(72) VALUE SPACES.  
       …
       EXEC CICS ASSIGN CHANNEL(CHANNELNAME).

       EXEC CICS GET CONTAINER(INPUT-CONT)
                    INTO(INPUTSTRING)
                    CHANNEL(CHANNELNAME)
                    FLENGTH(INPUTLENGTH) END-EXEC.

      * Perform business logic here     

       EXEC CICS PUT CONTAINER(OUTPUT-CONT)
                    CHANNEL(CHANNELNAME)
                    FROM(OUTPUTSTRING)
                    FLENGTH(LENGTH OF OUTPUTSTRING)
                    END-EXEC.

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_SYNC_TPN, 
					“CICSSERV”, 
					null, 
					null, 
					"CICSPROG", 
					"CSMI", 
					theChannel, 
					ECIRequest.ECI_NO_EXTEND, 
					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);
  e.printStackTrace();
}

Explanation:

  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.

Conversational programming

Note that all existing containers are sent to CICS by the Java client on each request. Thus if multiple requests to the same CICS program are made in sequence, the client application should ensure that only the required containers are sent on subsequent requests. This can be achieved by either creating a new Channel object for each call, or ensuring that any redundant containers are deleted from the channel before it is resent.

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

Invalid call type

CICS TG returns the return code ECI_ERR_INVALID_CALL_TYPE (-14) to the ECI API call if an attempt is made to send a channel over a connection type (such as SNA or ECI/IP) that does not support channels and containers.

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
	javaGateObject.flow(eciRequestObject);	
	} 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);
	}
	System.out.println();
}

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() + "]");
        return;
	}

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

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() + " = ");
		System.out.println(cont.getCHARData());
		break;
					
	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

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

Data conversion failures:

The CICS message DFHAP0802 may be listed in the CICS message log if CICS fails to convert container data from one encoding to another. This error is caused by the inability of the z/OS Unicode conversion service to perform the conversion. Note that the message will only be produced once per lifetime of the CICS region, since CICS dynamically caches conversion information when using 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

Custom numeric conversion

The Java client sample EciChanTest.java provided with this article includes examples of how to convert byte arrays to string data or integers, and how to format for display as hexadecimal.

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

JVM encodings

The default encoding that will be used by the IBM Java 5 SDK on US Windows systems is CCSID 5348 and on Linux/Intel systems is 1208.

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.setCCSID(ccsid);
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
           EXEC CICS GET CONTAINER(INPUT-CONT)
                         FLENGTH(INPUTLENGTH)
                         INTOCCSID(1208)
                         INTO(INPUTSTRING)
                         END-EXEC.

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)                         
                            FLENGTH(INPUTLENGTH)                        
                            INTO(INPUTSTRING)                            
                            END-EXEC.                                   

      * Cache converted container in working channel, no conversion     
           EXEC CICS PUT CONTAINER(INPUT-CONT)                         
                            CHANNEL('WORKCHANNEL')                      
                            FROM(INPUTSTRING)                            
                            FLENGTH(INPUTLENGTH)                        
                            END-EXEC.               
                    
      * Read container data from working channel, no conversion
      * This GET operation may be repeated several times                
           EXEC CICS GET CONTAINER(INPUT-CONT)                         
                            CHANNEL('WORKCHANNEL')                      
                            FLENGTH(INPUTLENGTH)                        
                            INTO(INPUTSTRING)                            
                            END-EXEC.                                   

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

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.


Download

DescriptionNameSize
Sample Java and CICS COBOL applicationcontainers.zip11KB

Resources

Learn

Get products and technologies

  • Install the following fixes to address specific issues with channels and containers:
    • Correct data conversion when using channels and containers from non-EBCDIC systems such as the CICS Transaction Gateway, requires the PTF for CICS APARs PK49490 and PK49021.
    • Correct data conversion for non US-ASCII Java clients requires the PTF for APAR PK62925 available in CICS Transaction Gateway V7.1.0.2
    • Review additional software requirements in the CICS Transaction Gateway support site.
  • Evalaute our latest products for modernizing and deploying core System z applications at the IBM Enterprise Modernization Sandbox for System z

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=345516
ArticleTitle=Exploiting CICS Channels and Containers from Java clients
publish-date=10152008