Writing Java classes to redirect JVM stdout and stderr output

Use the USEROUTPUTCLASS option in a JVM profile to name a Java™ class that intercepts the stdout stream and stderr stream from the JVM. You can update this class to specify your choice of time stamps and record headers, and to redirect the output.

6.3 beta Support for USEROUTPUTCLASS function is deprecated.

CICS supplies sample Java classes, com.ibm.cics.samples.SJMergedStream and com.ibm.cics.samples.SJTaskStream, that you can use for this purpose. Sample source is provided for both these classes in the /usr/lpp/cicsts/cicsts64/samples/com.ibm.cics.samples directory. The /usr/lpp/cicsts/cicsts64 directory is the installation directory for CICS files on z/OS UNIX . This directory is specified by the USSDIR parameter in the DFHISTAR installation job. The sample classes are also shipped as a class file, com.ibm.cics.samples.jar , which is in the directory /usr/lpp/cicsts/cicsts64/lib. You can modify these classes, or write your own classes based on the samples.

Controlling the location for JVM output, logs, dumps and trace has information about:
  • The types of output from JVMs that are and are not intercepted by the class that is named by the USEROUTPUTCLASS option. The class that you use must be able to deal with all the types of output that it might intercept.
  • The behavior of the supplied sample classes. The com.ibm.cics.samples.SJMergedStream class creates two merged log files for JVM output and for error messages, with a header on each record that contains APPLID, date, time, transaction ID, task number, and program name. The log files are created by using transient data queues, if they are available; or z/OS UNIX files, if the transient data queues are not available, or cannot be used by the Java application. The com.ibm.cics.samples.SJTaskStream class directs the output from a single task to z/OS UNIX files, adding time stamps and headers, to provide output streams that are specific to a single task.
For a JVM server to use an output redirection class, you must create an OSGi bundle that contains your output redirection class. You must ensure that the bundle activator registers an instance of your class as a service in the framework and sets the property com.ibm.cics.server.outputredirectionplugin.name=class_name. You can use the constant com.ibm.cics.server.Constants.CICS_USER_OUTPUT_CLASSNAME_PROPERTY to get the property name. The following code excerpt shows how you might register your service in the bundle activator:
Properties serviceProperties = new Properties();
    serviceProperties.put(Constants.CICS_USER_OUTPUT_CLASSNAME_PROPERTY, MyOwnStreamPlugin.class.getName());
    context.registerService(OutputRedirectionPlugin.class.getName(), new MyOwnStreamPlugin(), serviceProperties);
You can either add the OSGi bundle to the OSGI_BUNDLES option in the JVM profile, or ensure that the bundle is installed in the framework when the first task is run. Whichever method you use, you must still specify the class in the USEROUTPUTCLASS option.
If you decide to write your own classes, you need to know about:
  • The OutputRedirectionPlugin interface
  • Possible destinations for output
  • Handling output redirection errors and internal errors

The output redirection interface

CICS supplies an interface called com.ibm.cics.server.OutputRedirectionPlugin in com.ibm.cics.server.jar, which can be implemented by classes that intercept the stdout and stderr output from the JVM. The supplied samples implement this interface.

The following sample classes are provided:
  • A superclass com.ibm.cics.samples.SJStream that implements this interface
  • The subclasses com.ibm.cics.samples.SJMergedStream and com.ibm.cics.samples.SJTaskStream, which are the classes named in the JVM profile

Like the sample classes, ensure that your class implements the interface OutputRedirectionPlugin directly, or extends a class that implements the interface. You can either inherit from the superclass com.ibm.cics.samples.SJStream, or implement a class structure with the same interface. Using either method, your class must extend java.io.OutputStream.

The initRedirect() method receives a set of parameters that are used by the output redirection class or classes. The following code shows the interface:
package com.ibm.cics.server;

import java.io.*;

public interface OutputRedirectionPlugin {

  public boolean initRedirect( String inDest,
                            PrintStream inPS,
                            String inApplid,
                            String inProgramName,
                            Integer inTaskNumber,
                            String inTransid
                           );
  }               

The superclass com.ibm.cics.samples.SJStream contains the common components of com.ibm.cics.samples.SJMergedStream and com.ibm.cics.samples.SJTaskStream. It contains an initRedirect() method that returns false, which effectively disables output redirection unless this method is overridden by another method in a subclass. It does not implement a writeRecord() method, and such a method must be provided by any subclass to control the output redirection process. You can use this method in your own class structure. The initialization of output redirection can also be performed using a constructor, rather than the initRedirect() method.

The inPS parameter contains either the original System.out print stream or the original System.err print stream of the JVM. You can write logging to either of these underlying logging destinations. You must not call the close() method on either of these print streams because they remain closed permanently and are not available for further use.

Possible destinations for output

The CICS-supplied sample classes direct output from JVMs to a directory that is specific to a CICS region; the directory name is created using the applid associated with the CICS region. When you write your own classes, if you prefer, you can send output from several CICS regions to the same z/OS UNIX directory or file.

For example, you might want to create a single file containing the output associated with a particular application that runs in several different CICS regions.

Threads that are started programmatically using Thread.start() are not able to make CICS requests. For these applications, the output from the JVM is intercepted by the class you have specified for USEROUTPUTCLASS, but it cannot be redirected using CICS facilities (such as transient data queues). You can direct output from these applications to z/OS UNIX files, as the supplied sample classes do.

Handling output redirection errors and internal errors

If your classes use CICS facilities to redirect output, they should include appropriate exception handling to deal with errors in using these facilities.

For example, if you are writing to the transient data queues CSJO and CSJE, and using the CICS-supplied definitions for these queues, the following exceptions might be thrown by TDQ.writeData:
  • IOErrorException
  • LengthErrorException
  • NoSpaceException
  • NotOpenException

If your classes direct output to z/OS UNIX files, they should include appropriate exception handling to deal with errors that occur when writing to z/OS UNIX. The most common cause of these errors is a security exception.

The Java programs that will run in JVMs that name your classes on the USEROUTPUTCLASS options should include appropriate exception handling to deal with any exceptions that might be thrown by your classes. The CICS-supplied sample classes handle exceptions internally, by using a Try/Catch block to catch all throwable exceptions, and then writing one or more error messages to report the problem. When an error is detected while redirecting an output message, these error messages are written to System.err, making them available for redirection. However, if an error is found while redirecting an error message, then the messages which report this problem are written to the file indicated by the STDERR option in the JVM profile used by the JVM that is servicing the request. Because the sample classes trap all errors in this way, this means that the calling programs do not need to handle any exceptions thrown by the output redirection class. You can use this method to avoid making changes to your calling programs. Be careful that you do not send the output redirection class into a loop by attempting to redirect the error message issued by the class to the destination which has failed.