Access z/OS batch jobs from Java

Java provides access to z/OS batch jobs from anywhere

Java™ can provide a simple way to submit z/OS® batch jobs to run -- but that is just the beginning. You can also use Java, from any platform, to check on the status of your z/OS batch jobs. This article is a follow-on to developerWorks article, Submit batch jobs from Java on z/OS.

Evan Williams (evan.williams@isi.com.au), Senior Consultant, Independent Systems Integrators

Photo of Evan WilliamsEvan Williams is a consultant based in Brisbane, Australia. His 20 years of computing experience is based in the mainframe area -- especially DB2 on the mainframe. However, lately he has embraced all things new, such as Java and XML. Evan is particularly interested in the integration of these newer technologies with the mainframe world.



19 December 2006

Introduction

You probably know that you can use File Transfer Protocol (FTP) to transfer files, but the z/OS FTP server is a little different. Not only can it provide standard access to z/OS UNIX® System Services files, the server can also provide the following:

  • z/OS datasets
  • Job Entry Subsystem (JES) spool datasets
  • SQL result sets

You can access these types of information from any FTP session. With the help of a Java FTP client, you can put the information to good use. Naturally, this article makes use of the access to the JES spool.

The FTP server provides access to a number of JES functions, including the following:

  • Submitting a job
  • Displaying the status of jobs
  • Receiving the spool output of a job (Job Control Language [JCL] messages and SYSOUT)
  • Deleting a job
  • Submitting a job and automatically receiving output

This article addresses the second and third functions in more detail: displaying job status and receiving spool output.

Basics

Before starting, ensure the following:

  • Your z/OS machine has the FTP server running
  • You have a suitably authorized user ID

In addition, you can use any of several configuration parameters to control the behaviour of the JES interface, including the most important configuration parameter JESINTERFACELEVEL. Table 1 shows a summary of configuration parameters.

Table 1. JES interface configuration parameters
ParameterDescription
JESINTERFACELEVELSpecifies the level of function the JES interface provides. Set to 2 for the most function.
JESENTRYLIMITLimits how many jobs will be returned. The default is 200.
JESOWNERLimits jobs retrieved to jobs with this owner. If blank, defaults to the current user.
JESJOBNAMELimits jobs retrieved to jobs with this job name. If blank, defaults to the current user concatenated with an *. Use * to retrieve all jobs.
JESSTATUSLimits jobs retrieved to jobs with this status. If blank, defaults to all states. Valid states are OUTPUT, ACTIVE, and INPUT.

You can use the STAT command to verify the settings of the FTP server. Listing 1 shows an example.

Listing 1. Using the STAT command
ftp> quote stat
211-Server FTP talking to host 192.168.152.1, port 1858
211-User: ISIELW  Working directory: ISIELW.
211-The control connection has transferred 117 bytes
211-There is no current data connection.
211-The next data connection will be actively opened
211-to host 192.168.152.1, port 1858,
211-using Mode Stream, Structure File, type ASCII, byte-size 8
211-Automatic recall of migrated data sets.
211-Automatic mount of direct access volumes.
211-Auto tape mount is allowed.
211-Inactivity timer is set to 300
211-Timer FTPKEEPALIVE is set to 0
211-VCOUNT is 59
211-ASA control characters in ASA files opened for text processing
211-will be transferred as ASA control characters.
211-Trailing blanks are removed from a fixed format
211-data set when it is retrieved.
211-Data set mode.  (Do not treat each qualifier as a directory.)
211-ISPFSTATS is set to FALSE
211-Primary allocation 1 track.  Secondary allocation 1 track.
211-Partitioned data sets will be created with 27 directory blocks.
211-FileType SEQ (Sequential - default).
211-Number of access method buffers is 5
211-RDWs from variable format data sets are discarded.
211-Records on input tape are unspecified format
211-SITE DB2 subsystem name is DB2
211-Data not wrapped into next record.
211-Tape write is not allowed to use BSAM I/O
211-Truncated records will not be treated as an error 
    ...
211-JESLRECL is 80
211-JESRECFM is Fixed
211-JESINTERFACELEVEL is 2
211-Encoding is set to SBCS
211-Port of Entry resource class for IPv4 clients is: TERMINAL
211-Record format VB, Lrecl: 256, Blocksize: 6233
211 *** end of status ***
ftp>

When you finish configuration, start an ordinary FTP session with the server. After you establish a session, use the SITE FILETYPE subcommand to indicate that you want to obtain JES information rather than normal HFS files.

Listing 2 shows an interactive FTP session from a Windows® client.

Listing 2. Using the SITE command
C:\>ftp 192.168.152.2
Connected to 192.168.152.2.
220-FTPD1 IBM FTP CS V1R5 at p390.qld.isi.com.au, 04:26:27 on 2006-09-06.
220 Connection will close if idle for more than 5 minutes.
User (192.168.152.2:(none)): isielw
331 Send password please.
Password:
230 ISIELW is logged on.  Working directory is "ISIELW.".
ftp> quote SITE FILETYPE=JES
200 SITE command was accepted
ftp>

After you change the filetype to JES, several FTP commands operate differently, as described in Table 2.

Table 2. JES interface command differences
CommandDescription
dirLists jobs on the SYSOUT queue
getReturns one or more SYSOUT files
putSubmits a job to JES
deleteRemoves SYSOUT files

The operation of two of these commands is described below.

Command: dir

JES jobs on the SYSOUT queue are treated as single-level directories. The dir command works in one of two ways:

  • The dir command with no arguments returns a list of all jobs that match the current setting of the JESJOBNAME parameter.
  • The dir command with an argument of a Jobid returns a list of all SYSOUT files that make up that job.

Listing 3 shows an example using the dir command.

Listing 3. Using the dir command
ftp> dir
200 Port request OK.
125 List started OK for JESJOBNAME=ISIELW*, JESSTATUS=ALL and JESOWNER=ISIELW
JOBNAME  JOBID    OWNER    STATUS CLASS
ISIELW   TSU00629 ISIELW   OUTPUT TSU      ABEND=522 3 spool files
ISIELW   TSU00609 ISIELW   OUTPUT TSU      ABEND=522 3 spool files
ISIELW   TSU00294 ISIELW   OUTPUT TSU      ABEND=522 3 spool files
ISIELW   TSU00250 ISIELW   OUTPUT TSU      ABEND=522 3 spool files
ISIELW   TSU00218 ISIELW   OUTPUT TSU      ABEND=522 3 spool files
ISIELW   TSU00199 ISIELW   OUTPUT TSU      ABEND=622 3 spool files
ISIELW   TSU00171 ISIELW   OUTPUT TSU      ABEND=522 3 spool files
250 List completed successfully.
ftp: 524 bytes received in 0.06Seconds 8.45Kbytes/sec.
ftp> dir TSU00629
200 Port request OK.
125 List started OK for JESJOBNAME=ISIELW*, JESSTATUS=ALL and JESOWNER=ISIELW
JOBNAME  JOBID    OWNER    STATUS CLASS
ISIELW   TSU00629 ISIELW   OUTPUT TSU      ABEND=522
--------
         ID  STEPNAME PROCSTEP C DDNAME   BYTE-COUNT
         001 JES2              K JESMSGLG       962
         002 JES2              K JESJCL       13983
         003 JES2              K JESYSMSG     17176
3 spool files
250 List completed successfully.
ftp: 340 bytes received in 0.03Seconds 10.63Kbytes/sec.
ftp>

Note the following about this example:

  • The jobs match the criteria as specified in the status line 125.
  • Job TSU00629 has 3 files, and this is what is reported when using the second command.

Command: get

The get command retrieves the contents of a specified JES job from the SYSOUT queue. The command works in one of two ways:

  • Using an argument of jobid.n, the command retrieves the contents of file n from the job jobid.
  • Using an argument of jobid.x, the command retrieves the contents of all files that make up job jobid. In this case, the files are concatenated with a special separator of !! END OF JES SPOOL FILE !!.

Listing 4 shows an example using the get command.

Listing 4. Using the get command
ftp> get TSU00629.x
200 Port request OK.
125 Sending all spool files for requested Jobid
250 Transfer completed successfully.
ftp: 37422 bytes received in 1.19Seconds 31.53Kbytes/sec.
ftp> get TSU00629.1
200 Port request OK.
125 Sending data set ISIELW.ISIELW.TSU00629.D0000002.JESMSGLG
250 Transfer completed successfully.
ftp: 1402 bytes received in 0.16Seconds 8.93Kbytes/sec.
ftp>

Java environment for sample code

The examples in this article were developed and run using the Eclipse environment. Follow these steps to use the sample source code:

  1. Create a new Eclipse project, or use an existing one.
  2. Download the source code JAR file, and unzip it to a temporary location. See Download.
  3. Import the source code into the Project.
  4. Download the Commons Net Library. See Resources.
  5. Adjust the Project build path to include the Commons Net JAR file.

Java access

So far, I have given examples of FTP command line access to the JES spool files. This is fine for simple work, but you can exploit the power of accessing the JES using FTP using a programmatic approach, such as Java.

You can use Java at two levels to access the JES using FTP:

  • Using Java to gain basic access to FTP services. To do this, use the Jakarta Commons Net package. See Resources to find a link to download the Jakarta Commons Net package.
  • Exploiting the z/OS enhanced FTP server. To do this, enhance the Commons Net configuration to adapt to the z/OS FTP server.

The two levels are described below in more detail.

Using the Commons Net library

Using the Commons Net library is easy, and it provides a means to access a number of communication protocols, including FTP. When using the library for FTP access, use the main class FTPClient. Refer to the Javadoc for useful getting-started notes about this class.

Listing 5 provides an example to illustrate how easy the library is to use.

Listing 5. Using the Commons Net library
package evan.org;

import org.apache.commons.net.ftp.*;
import java.io.IOException;

/**
 * This class provides a simple example of how to access
 * JES files using an FTP server from Java code.
 * <p>The user ID and password must be valid for the server
 * accessed.
 */
 public class FtpExampleOne {

	public FtpExampleOne() {
	}

	public static void main(String[] args) {

		FTPClient ftp = null;

		String sUserid = "ISIELW";
		String sPassword = "PASSWD";
		String sHost = "192.168.152.2";
		String sJobPrefix = "ISIELW*";
		String replyText;

		ftp = new FTPClient();

		FTPFile[] result = null;

		try {

			// Connect to the server

			ftp.connect(sHost);
			replyText = ftp.getReplyString();
			System.out.println(replyText);

			// Log into the server

			ftp.login(sUserid, sPassword);
			replyText = ftp.getReplyString();
			System.out.println(replyText);

			// Tell the server to use the JES interface

			ftp.site("filetype=jes");
			replyText = ftp.getReplyString();
			System.out.println(replyText);

			// Get a list of jobs

			String[] names = ftp.listNames("*");
			for (int i = 0; i < names.length; i++) {
				System.out.println("file " + i + " is " + names[i]);
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				ftp.quit();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

Listing 6 shows the output from the program shown in Listing 5.

Listing 6. Results of Commons Net library example application
220-FTPD1 IBM FTP CS V1R5 at p390.qld.isi.com.au, 00:29:00 on 2006-09-07.
220 Connection will close if idle for more than 5 minutes.

230 ISIELW is logged on.  Working directory is "ISIELW.".

200 SITE command was accepted

file 0 is TSU00629
file 1 is TSU00609
file 2 is TSU00294
file 3 is TSU00250
file 4 is TSU00218
file 5 is TSU00199
file 6 is TSU00171

The example code fragment in Listing 7 shows how to retrieve the contents of a SYSOUT file.

Listing 7. Retrieving a SYSOUT file
	// Retrieve part of a JES job

	String sRemoteFilename = "TSU00629.2";
	
	InputStream is = ftp.retrieveFileStream(sRemoteFilename);
	BufferedReader br = new BufferedReader(new InputStreamReader((is)));
	boolean bContinue = true;
	while (bContinue) {
		String sLine = br.readLine();
		if (sLine != null) {
			System.out.println("line ... " + sLine);
		} else {
			bContinue = false;
			is.close();
			br.close();
		}
	}
	ftp.completePendingCommand();

Listing 8 shows the output from a program that uses the Listing 7 code.

Listing 8. Viewing the results of the SYSOUT file retrieval
220-FTPD1 IBM FTP CS V1R5 at p390.qld.isi.com.au, 00:40:52 on 2006-09-07.
220 Connection will close if idle for more than 5 minutes.

230 ISIELW is logged on.  Working directory is "ISIELW.".

200 SITE command was accepted

        1 //ISIELW  JOB 'ACCT#',REGION=8192K                                      TSU00629
        2 //ISPFPROC EXEC ISPFPROC                                                        
          XX********************************************************************  00010000
          XX*                                                                     00020000
          XX*                 ISPF FULL-FUNCTION LOGON PROC                       00030000
          XX*                                                                     00040000
          XX********************************************************************* 00050000
        3 XXISPFPROC EXEC PGM=IKJEFT01,REGION=0M,DYNAMNBR=175,                    00060000
          XX             PARM='%ISPFCL'                                           00070000
          XX*TEPLIB  DD  DISP=SHR,DSN=ISIMPO.VSS611.VANLOAD                       00080000

Extending use of the Commons Net library

The examples above provide a simple approach to obtaining JES output. But, how can you get more fine-grained control over what you access and retrieve? The Javadoc for the FTPClient describes a listFiles method. This method provides a degree of encapsulation of the files concept, because it returns an array of FTPFile objects rather than simple String objects. Listing 9 shows the use of the listFiles method.

Listing 9. Using listFiles
FTPFile[] result = ftp.listFiles("*");
for (int i=0; i < result.length; i++) {
	System.out.println("file " + i + " is " + result[i].getName());
}

As the output in Listing 10 shows, the results are not acceptable. The retrieved filenames do not correspond with the filenames the FTP server is meant to report. Seemingly, even though the Commons Net library can detect the host type automatically, this does not extend to the z/OS FTP extensions.

Listing 10. Using listFiles results
220-FTPD1 IBM FTP CS V1R5 at p390.qld.isi.com.au, 02:03:36 on 2006-09-07.
220 Connection will close if idle for more than 5 minutes.

230 ISIELW is logged on.  Working directory is "ISIELW.".

200 SITE command was accepted

file 0 is CLASS
file 1 is files
file 2 is files
file 3 is files
file 4 is files
file 5 is files
file 6 is files
file 7 is files
file 8 is TSU

The good news is you can use the Commons Net library to configure the FTPClient to parse different types of file listings. All you need to do is to produce a parser that can understand the output from the dir command and create instances of an FTPFile class. But first, get the most flexibility by extending the FTPFile class. This enables you to store the special attributes available to describe the JES files. Listing 11 illustrates the outline of such a class.

Listing 11. Extending the FTPFile class
package evan.org;

import org.apache.commons.net.ftp.FTPFile;

/**
 * The JesJob class extends the FTPFile class. This 
 * allows for <code>JES</code> specific information to
 * be maintained, in addition to the standard <code>FTPFile</code>
 * information.
 * <p>This allows information for the spool files such as:
 * <ul>
 * <li>job name</li>
 * <li>job id</li>
 * <li>job owner</li>
 * <li>job status</li>
 * <li>job class</li>
 * <li>job return code</li>
 * </ul>
 */public class JesJob extends FTPFile {

	private static final long serialVersionUID = 1L;

	private String sJobName;
	private String sOwner;
	private String sStatus;
	private String sJobClass;
	private String sReturnCode;
	private String sNumFiles;

	public JesJob() {
		super();
		sJobName = "";
		sOwner = "";
		sStatus = "";
		sJobClass = "";
		sReturnCode = "";
		sNumFiles = "";
	}

	public String getJobName() {
		return sJobName;
	}

	public void setJobName(String jobname) {
		sJobName = jobname;
	}
	...
}

You can configure the FTPClient to use a particular parser by supplying an instance of the FTPClientConfig class, as shown in Listing 12. This object is created with the name of a class that implements the FTPFileEntryParse interface.

Listing 12. Configuring the FTPClient
ftp = new FTPClient();

FTPClientConfig conf = new FTPClientConfig("evan.org.SimpleJesFileParser");
ftp.configure(conf);

Listing 13 shows a basic implementation of evan.org.SimpleJesFileParser.

Listing 13. Implementing the parser
package evan.org;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPFileEntryParser;

public class SimpleJesFileParser implements FTPFileEntryParser  {

	/** Parses a single line of text, and returns an FTPFile.
	 * <p>Typically, the text would be something like this:  
	 * <pre>
	 * ISIELW   TSU00807 ISIELW   OUTPUT TSU      ABEND=522 3 spool files
	 * jobname  jobid    owner    status type     result   
	 * </pre> 
	 * 
	 * @see org.apache.commons.net.ftp.FTPFileEntryParser#parseFTPEntry(java.lang.String)
	 */
	public FTPFile parseFTPEntry(String arg0) {

		JesJob f = new JesJob();

		String sOwner = "";
		String sStatus = "";
		String sType = "";
		String sReturnCode = "";
		
		// Use regular expressions to break into words ...
		// remembering that:
		// - the first backslash is the Java String escape mechanism
		//   so that \\S is really just \S in regexp terms.
		// - \S    means any non-whitespace character
		// - \S+   means a bunch of them
		// - (\S+) means a bunch of them - as a group 
		// - \s+   means some whitespace

		Pattern p = Pattern.compile("(\\S+)\\s+(\\S+)\\s+(.*)");
		Matcher matcher = p.matcher(arg0);
		if (matcher.find()) {
			String sJobname = matcher.group(1);
			String sJobid = matcher.group(2);
			String sRemainder = matcher.group(3);

			if (!sRemainder.equals("")) {

				Pattern p2 = Pattern
						.compile("(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(.*)");
				Matcher matcher2 = p2.matcher(sRemainder);
				if (matcher2.find()) {
					sOwner = matcher2.group(1);
					sStatus = matcher2.group(2);
					sType = matcher2.group(3);
					String remainder = matcher2.group(4);

					if (remainder.startsWith("RC=")) {
						sReturnCode = remainder.substring(3, 8);
					}
					if (remainder.startsWith("ABEND=")) {
						sReturnCode = "S" + remainder.substring(6, 10);
					}
					if (remainder.startsWith("(JCL error)")) {
						sReturnCode = "JCL error";
					}
				}
			}
			f.setName(sJobid);
			f.setJobName(sJobname);
			f.setOwner(sOwner);
			f.setStatus(sStatus);
			f.setJobClass(sType);
			f.setReturnCode(sReturnCode);
			f.setType(FTPFile.DIRECTORY_TYPE);
		}
		return f;
	}

	/** Filter a list that contains the strings from a list of 
	 *  file entries.
	 *  This is an opportunity to remove any superfluous lines;
	 *  that is, strings that do not describe a real file. A common
	 *  example is headings.  
	 *  
	 * @see org.apache.commons.net.ftp.FTPFileEntryParser#preParse(java.util.List)
	 */
	public List preParse(List arg0) {

		Iterator it = arg0.iterator();
		while (it.hasNext()) {
			Object o = it.next();
			if (o instanceof String) {
				String s = (String) o;
				String sSub = s.substring(9, 14);
				if (sSub.equals("JOBID")) {
					it.remove();
				}
			}
		}
		return arg0;
	}

	public String readNextEntry(BufferedReader arg0) throws IOException {
		String s = arg0.readLine();
		return s;
	}
}

Note the following about the code shown in Figure 13:

  • The main responsibility of the parser is to take a line of text and produce an FTPFile instance. In this case, you actually return an instance of JesJob, because you want to provide the extra JES information.
  • The parsing performed in this code uses a mixture of regular expressions and string comparisons. This is a simple, functional implementation, though you could use better performing code to do the same thing.
  • Use the preParse method to filter out extra lines of information from the directory listing. In the example, the heading line is detected and removed.

Finally, you can invoke the listFiles method, as shown in Listing 14. Note that the returned result is cast to the JesJob type.

Listing 14. Using the custom parser
ftp = new FTPClient();

FTPClientConfig conf = new FTPClientConfig("evan.org.SimpleJesFileParser");
ftp.configure(conf);

try {

	String replyText;
	// Connect to the server

	ftp.connect(sHost);
	replyText = ftp.getReplyString();
	System.out.println(replyText);

	// Login to the server

	ftp.login(sUserid, sPassword);
	replyText = ftp.getReplyString();
	System.out.println(replyText);

	// Tell server that the file will have JCL records

	ftp.site("filetype=jes");
	replyText = ftp.getReplyString();
	System.out.println(replyText);

	ftp.site("jesowner=*");
	ftp.site("jesjobname=" + sJobPrefix);

	FTPFile[] result = ftp.listFiles("*");
	for (int i = 0; i < result.length; i++) {
		JesJob job = (JesJob) result[i];
		System.out.println("file " + i  
				+ " is " + job.getName()
				+ " jobname is " + job.getJobName() 
				+ " class is "   + job.getJobClass() 
				+ " status is "  + job.getStatus()
				+ " rc is "      + job.getReturnCode());
	}
} catch (Exception e) {
	e.printStackTrace();
}

Listing 15 shows sample output from the Listing 14 code fragment.

Listing 15. Output from the custom parser
220-FTPD1 IBM FTP CS V1R5 at p390.qld.isi.com.au, 04:30:52 on 2006-09-07.
220 Connection will close if idle for more than 5 minutes.

230 ISIELW is logged on.  Working directory is "ISIELW.".

200 SITE command was accepted

file 0 is TSU00629 jobname is ISIELW class is TSU status is OUTPUT rc is S522 
file 1 is TSU00609 jobname is ISIELW class is TSU status is OUTPUT rc is S522 
file 2 is TSU00294 jobname is ISIELW class is TSU status is OUTPUT rc is S522 
file 3 is TSU00250 jobname is ISIELW class is TSU status is OUTPUT rc is S522 
file 4 is TSU00218 jobname is ISIELW class is TSU status is OUTPUT rc is S522 
file 5 is TSU00199 jobname is ISIELW class is TSU status is OUTPUT rc is S522 
file 6 is TSU00171 jobname is ISIELW class is TSU status is OUTPUT rc is S522 
file 7 is TSU00656 jobname is ISIELW class is TSU status is ACTIVE rc is

Conclusion

This article showed you how to use Java to access z/OS JES Sysout files. In addition, extending the Commons Net Library allows the specific JES file attributes to be encapsulated in Java objects.


Download

DescriptionNameSize
Sample Java source codees-jesjava.jar6KB

Resources

Learn

Get products and technologies

Discuss

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 Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=184411
ArticleTitle=Access z/OS batch jobs from Java
publish-date=12192006