CICS exception handling in JCICS programs

CICS® conditions and exceptions are integrated into the Java™ exception-handling architecture to handle problems that occur in CICS. You can use a set of Java exceptions and methods to handle CICS error conditions, and abend or roll back CICS tasks.

Contents

Class hierarchy of JCICS exceptions

The JCICS API classes contain checked exceptions and unchecked exceptions. CICS checked exceptions extend the CicsException class. They correspond to the response codes of error conditions returned from the underlying EXEC CICS commands and need to be handled by your program. CICS unchecked exceptions extend the CicsRuntimeException class and represent failures within CICS or ABENDs.

The following diagram shows the class hierarchy of some example exceptions in JCICS:
Figure 1. Class hierarchy of checked and unchecked exceptions in JCICS
Class hierarchy of example unchecked and checked exceptions in JCICS

For more information about each class, see JCICS Javadoc information.

Catching checked exceptions

In Java, checked exceptions are used when you want the user of your API to design how to handle the exceptional situation. They must either be caught or declared as part of the method signature using the throws keyword. Any Java code that calls a method declared as throwing a checked exception must either provide logic to catch the checked exception, or add the exception to its own method signature, in order to propagate the exception further up the stack. The constraints on checked exceptions are enforced at compile time, and failure to adhere to the specification will result in a compilation error.

By contrast, in traditional high-level languages such as COBOL, when a CICS command returns an error (such as unknown program on a link), it returns a response code (for example, PGMIDERR) to the application using the data area supplied in the RESP parameter of the CICS command. This enables the application to handle or ignore errors on a call-by-call basis.
EXEC CICS LINK PROGRAM('ECIPROG') RESP(RESP)
        END-EXEC
IF RESP = DFHRESP(INVREQ)
  .......
END-IF

In JCICS, things are similar because almost all JCICS commands can throw sub-classes of the checked CICSConditionException, which represent error response codes from the underlying EXEC CICS commands. The full list of Java exception classes and the CICS error conditions they map to can be found at Mapping between CICS conditions and JCICS exceptions.

For example, an INVREQ response code maps to an InvalidRequestException class. The class hierarchy looks like this:
java.lang.Exception
  com.ibm.cics.server.CicsException
    com.ibm.cics.server.CicsConditionException
      com.ibm.cics.server.CicsResponseConditionException
        com.ibm.cics.server.InvalidRequestException

The following example shows how the InvalidRequestException class, which maps into the INVREQ response code, can be used in a Program.link() call. Each sub-class of CicsConditionException, including InvalidRequestException, can be individually caught so specific errors can be caught or ignored.

Order is important, a compilation error is displayed if a catch clause for a more generic exception appears before a catch clause for a more specific one (that is, for one of its sub-classes). This example logs a message for the InvalidRequestException and carries on processing. This means the transaction will continue normal processing and thus potentially commit any recoverable data, so make sure you don’t do this for fatal errors. The example then catches all other CICS errors (catch(CicsConditionException cce)) and throws them up the stack using a new RuntimeException class to drive subsequent error handling, which by default will abend the CICS task and rollback the transaction.

task task = Task.getTask();
task.out.println("Hello world");

try    
{   
        Program prog = new Program();
        prog.setName(PROG_NAME);
        prog.setSyncOnReturn(false);  
        byte[] ca = new byte[CA_LEN];
        prog.link(ca);
 
}
catch (InvalidRequestException ire) 
{
    task.out.println("Invalid request on link - INVREQ");
} 
catch (CicsConditionException cce) 
{
    throw new RuntimeException(cce);
}

Catching unchecked exceptions

In Java, unexpected error conditions are represented by Java classes that extend the RuntimeException class and are known as unchecked exceptions. Unchecked exceptions are not subject to the compile time checking mandated for checked exceptions, although they can be caught if required. In the JCICS API, all the unchecked exceptions extend the CICSRuntimeException class.

All of the unchecked exceptions that extend the CICSRuntimeException class represent conditions within CICS that are generally not handled by an application, to avoid interrupting the Java applications. They can include CICS ABENDs or some internal CICS events, such as program termination. Java code running in CICS must not catch these exceptions without re-throwing them, either explicitly in a catch block, or implicitly by catching a superclass of these exceptions such as Exception or Throwable as follows:

try
{
    ...
} 
catch ( Exception e ) 
{
    ...
}   

Instead, they need to be allowed to propagate out of the Java environment and back to CICS, where the task will abend. Included in this list is the AbendException class, which represents an ABEND of a CICS task. These ABENDs typically occur during sync point processing. The AbendException class must only be caught if you want to develop your own Java abend handling routine and re-throw the exception. If a Java exception such as a null pointer exception is allowed to propagate out of the Java code and back to the JVM server runtime, this is generally surfaced as one of the CICS ABENDs prefixed with AJ. Most commonly, an uncaught exception will result in an AJ04 abend, and the transaction will be rolled back.

Consideration for web applications: Any Java exception that is not handled by a web application will be caught by the web container and drive the servlet exception handling process. As part of this processing any uncommitted CICS units of work will be rolled back by CICS.
Important: Applications must not call Task.abend() after catching an AbendException. If Task.abend() is called, CICS issues the message DFHSJ1007, and disables and restarts the JVMSERVER.

Abending and rolling back CICS tasks

It is also possible for a Java application to abend or roll back the CICS task directly. This can be achieved using the Task.abend() or Task.rollback() methods in the Task class, as shown in the LinkServEC01 sample. Abending the CICS task is similar in concept to the throwing of Java exception because it allows a CICS ABEND handler written in COBOL (or another language) to take control of error processing.

The various forms of the Task.abend() method allow an application to optionally specify an abend code or whether a dump is required. The forceAbend() methods provide the same options as the equivalent abend methods, but are equivalent to specifying the CANCEL keyword on the EXEC CICS ABEND command. Invoking a forceAbend() method always terminates the task abnormally, and overrides any existing CICS abend handlers that have been established for the task.

Rolling back the transaction is equivalent to issuing an EXEC CICS SYNCPOINT ROLLBACK command, and allows the task to continue but rolls back all the updates that have taken place so far in the current unit-of-work. In JCICS this is achieved using the Task.rollback() method of the Task class as follows:
try
{
    Task.getTask().rollback();
} 
catch (InvalidRequestException ire) 
{
    .....
}  

LinkServEC01 contains a full sample where Task.rollback() is used to roll back the CICS task.

Note that when accessing resources that are controlled by the Liberty transaction manager, such as a remote Db2® database using JDBC type 4 connectivity, it is necessary to use the Java transaction API (JTA) to create a Java transaction to control the global transaction scope, including the subordinate CICS unit-of-work. In this case it is not possible to use the Task.rollback() method and instead the JTA API needs to be used.