您可能知道可以使用文件传输协议(FTP)来传输文件,但是z / OS FTP服务器有所不同。 该服务器不仅可以提供对z / OSUNIX®System Services文件的标准访问,而且还可以提供以下服务:
z / OS数据集 Job Entry Subsystem(JES)后台打印数据集 SQL结果集
您可以从任何FTP会话访问这些类型的信息。 借助Java FTP客户端,您可以充分利用信息。 自然地,本文利用对JES假脱机的访问。
FTP服务器提供对许多JES功能的访问,其中包括:
提交工作 显示工作状态 接收作业的后台打印输出(作业控制语言[JCL]消息和SYSOUT) 删除工作 提交作业并自动接收输出
本文将更详细地介绍第二和第三功能:显示作业状态和接收假脱机输出。
基本
在开始之前,请确保以下内容:
您的z / OS计算机上正在运行FTP服务器 您具有适当授权的用户ID
此外,您可以使用多个配置参数中的任何一个来控制JES接口的行为,包括最重要的配置参数JESINTERFACELEVEL 。 表1总结了配置参数。
表1. JES接口配置参数
参数 描述
JESINTERFACELEVEL 指定JES界面提供的功能级别。 为最大功能设置为2。 JESENTRYLIMIT 限制将返回多少作业。 默认值为200。 杰索纳 将检索到的作业限制为与此所有者有关的作业。 如果为空,则默认为当前用户。 杰索比名字 将检索到的作业限制为具有此作业名称的作业。 如果为空,则默认为当前用户并带有* 。 使用*检索所有作业。 耶斯达斯 将检索到的作业限制为具有此状态的作业。 如果为空,则默认为所有状态。 有效状态为OUTPUT,ACTIVE和INPUT。
您可以使用STAT命令来验证FTP服务器的设置。 清单1显示了一个示例。
清单1.使用STAT命令
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>
完成配置后,启动与服务器的普通FTP会话。 建立会话后,请使用SITE FILETYPE子命令指示您要获取JES信息,而不是普通的HFS文件。
清单2显示了Windows®客户端的交互式FTP会话。
清单2.使用SITE命令
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>
将文件类型更改为JES后,一些FTP命令的操作方式有所不同,如表2中所述。
表2. JES接口命令的差异
命令 描述
目录 列出SYSOUT队列上的作业 得到 返回一个或多个SYSOUT文件 放 向JES提交工作 删除 删除SYSOUT文件
下面描述了其中两个命令的操作。
命令:dir
SYSOUT队列上的JES作业被视为单级目录。 dir命令以两种方式之一起作用:
不带参数的dir命令返回与JESJOBNAME参数的当前设置匹配的所有作业的列表。 带有Jobid参数的dir命令返回组成该作业的所有SYSOUT文件的列表。
清单3显示了使用dir命令的示例。
清单3.使用dir命令
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>
请注意以下有关此示例的内容:
作业符合状态行125中指定的条件。 作业TSU00629具有3个文件,这是使用第二个命令时报告的内容。
命令:获取
get命令从SYSOUT队列中检索指定的JES作业的内容。 该命令以两种方式之一起作用:
使用jobid的参数。 n ,该命令从作业jobid中检索文件n的内容。 该命令使用jobid .x的参数来检索组成job jobid的所有文件的内容。 在这种情况下,文件用特殊的分隔符!! END OF JES SPOOL FILE !!连接在一起!! END OF JES SPOOL FILE !! !! END OF JES SPOOL FILE !! 。
清单4显示了使用get命令的示例。
清单4.使用get命令
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环境中的示例代码
本文中的示例是使用Eclipse环境开发并运行的。 请按照以下步骤使用示例源代码:
创建一个新的Eclipse项目,或使用现有的项目。 下载源代码JAR文件,并将其解压缩到一个临时位置。 请参阅下载 。 将源代码导入到项目中。 下载Commons Net Library。 请参阅相关主题 。 调整项目构建路径以包含Commons Net JAR文件。
Java访问
到目前为止,我已经给出了通过FTP命令行访问JES假脱机文件的示例。 这对于简单的工作而言是很好的选择,但是您可以利用Java等编程方式来利用FTP访问JES的功能。
您可以在两个级别上使用Java来通过FTP访问JES:
使用Java获得对FTP服务的基本访问。 为此,请使用Jakarta Commons Net软件包。 请参阅相关主题 ,以找到一个链接,下载的Jakarta Commons包网。 利用z / OS增强的FTP服务器。 为此,请增强Commons Net配置以使其适应z / OS FTP服务器。
下面将更详细地描述这两个级别。
使用Commons Net库
使用Commons Net库很容易,它提供了一种访问包括FTP在内的多种通信协议的方法。 使用库进行FTP访问时,请使用主类FTPClient 。 请参阅Javadoc,以获取有关该类的有用的入门说明。
清单5提供了一个示例来说明该库的易用性。
清单5.使用Commons Net库
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();
}
}
}
}
清单6显示了清单5所示程序的输出。
清单6. Commons Net库示例应用程序的结果
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
清单7中的示例代码片段显示了如何检索SYSOUT文件的内容。
清单7.检索SYSOUT文件
// 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();
清单8显示了使用清单7代码的程序的输出。
清单8.查看SYSOUT文件检索的结果
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
扩展Commons Net库的使用
上面的示例提供了一种获取JES输出的简单方法。 但是,如何获得对访问和检索内容的更细粒度的控制? FTPClient的Javadoc描述了listFiles方法。 此方法提供了一定程度的文件概念封装,因为它返回了FTPFile对象数组,而不是简单的String对象。 清单9显示了listFiles方法的用法。
清单9.使用listFiles
FTPFile[] result = ftp.listFiles("*");
for (int i=0; i < result.length; i++) {
System.out.println("file " + i + " is " + result[i].getName());
}
如清单10中的输出所示,结果是不可接受的。 检索到的文件名与FTP服务器要报告的文件名不匹配。 看起来,即使Commons Net库可以自动检测主机类型,它也不会扩展到z / OS FTP扩展。
清单10.使用listFiles结果
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
好消息是您可以使用Commons Net库将FTPClient配置为解析不同类型的文件列表。 您需要做的就是生成一个解析器,该解析器可以理解dir命令的输出并创建FTPFile类的实例。 但是首先,通过扩展FTPFile类可以获得最大的灵活性。 这使您可以存储可用于描述JES文件的特殊属性。 清单11展示了此类的概述。
清单11.扩展FTPFile类
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;
}
...
}
可以配置FTPClient通过提供的实例,以使用特定的解析器FTPClientConfig类,如清单12中该目的通过一个类,它实现的名称创建FTPFileEntryParse接口。
清单12.配置FTPClient
ftp = new FTPClient();
FTPClientConfig conf = new FTPClientConfig("evan.org.SimpleJesFileParser");
ftp.configure(conf);
清单13显示了evan.org.SimpleJesFileParser的基本实现。
清单13.实现解析器
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;
}
}
请注意以下有关图13所示的代码:
解析器的主要职责是获取一行文本并生成一个FTPFile实例。 在这种情况下,实际上您将返回JesJob的实例,因为您想提供额外的JES信息。 在此代码中执行的解析使用了正则表达式和字符串比较的混合。 这是一个简单的功能实现,尽管您可以使用性能更好的代码来完成相同的事情。 使用preParse方法从目录列表中过滤掉多余的信息行。 在该示例中,航向线被检测到并被移除。
最后,您可以调用listFiles方法,如清单14所示。请注意,返回的结果JesJob转换为JesJob类型。
清单14.使用自定义解析器
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();
}
清单15显示了清单14代码片段的示例输出。
清单15.定制解析器的输出
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
结论
本文向您展示了如何使用Java访问z / OS JES Sysout文件。 另外,扩展Commons Net Library允许将特定的JES文件属性封装在Java对象中。
翻译自: https://www.ibm.com/developerworks/systems/library/es-zosbatchjavav/index.html