OUTPUT Processing

본 장에서는 OUTPUT의 개념과 처리방식에 대해 기술한다.

1. 개요

OUTPUT Processing은 JOB 수행 도중에 생성된 SYSOUT을 JOB이 종료된 후에 처리하는 단계이다.

SYSOUT은 OUTPUT이라는 단위로 나뉘어져 처리된다. OUTPUT Processing은 SYSOUT의 내용을 프린터로 출력하는 작업과 인터널 리더를 통하여 SYSOUT을 JOBQ로 submit하는 작업, SYSOUT을 지정한 External Writer를 사용해 처리하는 3가지의 작업을 한다.

3가지 작업 중 어떤 작업을 수행할 지는 SYSOUT의 속성에 따라 달라진다.

  1. OpenFrame에서 프린터로 출력하는 작업은 엄밀히 말하면 물리적인 프린터를 직접 가동시키는 것은 아니고, 외부 프린터 솔루션에 프린트할 데이터와 프린트에 사용될 리소스 정보(FORMS, FORMDEF, PAGEDEF 등)를 전달하는 것이다. 외부 프린터 솔루션에 데이터와 정보를 전달하기 위해 OpenFrame 환경설정에 print 서브젝트, PRINTn 섹션의 COMMAND, DRIVER_PATH 키의 VALUE 항목에 필요한 명령어와 공유 라이브러리의 경로를 설정해야 한다.

  2. 인터널 리더를 통한 submit에서는 OpenFrame 환경설정에 print 서브젝트, INTRDR 섹션의 DRIVER_PATH 키의 VALUE 항목에 필요한 공유 라이브러리 경로를 설정해야 한다.

  3. External Writer를 사용한 처리는 OpenFrame 환경설정에 print 서브젝트, WRITER 섹션에 External Writer의 이름과 필요한 공유 라이브러리 경로를 설정해야 한다.

print 서브젝트의 설정방법에 대한 자세한 내용은 OpenFrame Batch "환경설정 안내서"를 참고한다.

2. OUTPUT

OUTPUT은 OUTPUT Processing에서 처리되는 단위로, JOB 수행이 끝나면 생성된 SPOOL 데이터셋은 OUTPUT Processing 단계를 거치게 된다.

OUTPUT은 JCL의 SYSOUT과 OUTPUT 문에 의해 결정된다. 보통은 하나의 SPOOL 데이터셋이 1개의 OUTPUT으로 처리되며, 다음의 예처럼 하나 이상의 OUTPUT으로도 처리될 수 있다.

다음 예와 같이 JCL이 구성되면 1개의 SPOOL 데이터셋이 여러 개의 OUTPUT 처리에 사용된다.

//OUT01  OUTPUT  FORMDEF=FORM1
//OUT02  OUTPUT  FROMS=LETTER01,FROMDEF=LTR1,PAGEDEF=LTR4
//PRT    DD  SYSOUT=A,OUTPUT=(*.OUT01,*.OUT02)

위의 JCL에서 PRT DD는 OUT01, OUT02 2개의 OUTPUT DD를 참조하고 있다. JOB이 끝나면 OUT01의 OUTPUT 문을 참조하는 OUTPUT과 OUT02의 OUTPUT 문을 참조하는 OUTPUT이 OUTPUT Processing에 따라 처리된다.

  • OUT01을 참조하는 OUTPUT이 처리되면 FORM1의 FORMDEF의 포맷으로 PRT DD에 정의된 SPOOL 데이터셋의 내용이 기본 용지에 출력된다.

  • OUT02를 참조하는 OUTPUT이 처리되면 LTR1이라는 FORMDEF와 LTR4라는 PAGEDEF의 포맷으로 LETTER01이라는 용지에 SPOOL 데이터셋의 내용이 출력된다.

3. OUTPUT 처리

JOB 수행이 끝나면 SPOOL 데이터셋은 OUTPUT 단위로 OUTPUTQ에 등록된다. 등록된 OUTPUT은 ofrpmsvr에 의해 스케줄링되어 일반 프린터 또는 External Writer에 의해 처리되거나 인터널 리더에 의해 다시 submit된다. ofrpmsvr는 OUTPUTQ에서 OUTPUT STATUS를 확인하여 OUTPUT을 가져와 OpenFrame 환경설정에 print 서브젝트, PRINTn 섹션의 CLASS 키의 VALUE 항목과 OUTPUT CLASS를 비교하여 스케줄링하고, OUTPUT DISPOSITION에 따라 OUTPUT을 처리한다.

3.1. OUTPUT STATUS

OUTPUTQ에 등록된 OUTPUT의 상태 정보를 나타낸다. OUTPUT의 상태는 ofrpmsvr에 의해 처리되는 과정에서 바뀐다.

다음은 OUTPUT STATUS의 종류를 보여준다.

종류 설명

Unable

OUTPUT이 생성될 때의 초기 상태로 스케줄링이 되지 않은 채 OUTPUTQ에 대기하고 있는 상태이다.

Ready

OUTPUTQ에서 꺼내져 스케줄링이 되기 전 상태이다.

Print

스케줄링되어 PRINTERn, 인터널 리더 또는 External Writer로 작업이 이관된 상태이다.

Hold

OUTPUT DISPOSITION이 LEAVE일 경우 OUTPUT 처리 후 OUTPUTQ에 남아 대기하는 상태이다.

Cancel

OUTPUT 처리가 사용자에 의해 취소된 상태이다.

Error

PRINTERn, 인터널 리더 또는 External Writer에 이관된 작업에 오류가 발생한 상태이다.

JOB 수행 중 등록되는 OUTPUT은 초기에 U(Unable) 상태이다. ofrpmsvr는 주기적으로 OUTPUTQ를 스캔하며 등록된 OUTPUT 중 상태가 U(Unable) 또는 R(Ready) 인 것을 꺼내와 상태를 R(Ready)로 갱신하며 작업을 스케줄링한다. 이후 ofrpmsvr는 OUTPUT의 처리를 해당 프린터, 인터널 리더 또는 External Writer로 이관하며 상태를 P(Print)로 갱신한다. 만일 OUTPUT DISPOSITION이 'LEAVE’라면 OUTPUT의 정상 처리 후 상태는 H(Hold)로 바뀌어 OUTPUTQ에 남아 대기하게 된다.

OUTPUT 처리 중 tjesmgr를 통한 사용자의 명령에 의해 OUTPUT이 'PURGE' 됐을 경우, 해당 OUTPUT의 상태는 C(Cancel)이 되고 프린터 작업 중 오류가 발생할 경우 상태는 E(Error)로 갱신된다.

3.2. OUTPUT CLASS

OUTPUT에 부여된 1Byte 문자로 A-Z, 0-9가 사용된다. OUTPUT CLASS는 JCL에서 지정한다.

OUTPUT 문에서 OUTPUT CLASS를 지정한 경우 OUTPUT 문을 참고하는 SYSOUT 문에 CLASS가 또 지정되면, SYSOUT 문에서 지정된 값이 오버라이드되므로 SYSOUT 문에서는 CLASS를 지정하지 않도록 한다.

다음에서는 PRINT DD의 OUTPUT CLASS가 Y로 지정된다.

//OUT1     OUTPUT CLASS=Y,FORM=TEST
//PRINT    DD SYSOUT=(,),OUTPUT=*.OUT1

SYSOUT문에서 OUTPUT CLASS를 지정하는 경우 다음은 PRINT DD의 OUTPUT CLASS가 A로 지정된다.

//PRINT    DD SYSOUT=A

OUTPUT CLASS를 애스터리스크(*)로 지정하면 JOB 문에서 MSGCLASS로 지정된 CLASS가 OUTPUT CLASS로 지정된다.

다음 예에서는 PRINT DD의 OUTPUT CLASS가 X로 지정된다.

//COPY02   JOB CLASS=I,MSGCLASS=X,MSGLEVEL=(1,1)
...

//PRINT    DD SYSOUT=*
OUTPUT CLASS의 우선 순위

OUTPUT CLASS의 지정은 다음의 순서대로 적용된다.

  1. SYSOUT=class

  2. OUTPUT CLASS=class

  3. JOB MSGCLASS=class

SYSOUT에 CLASS 지정이 있는 경우 OUTPUT 문에 CLASS를 지정했더라도 SYSOUT에 지정된 값이 우선 적용된다.

SYSOUT=* 또는 SYSOUT=(,)과 같이 CLASS가 명시되지 않은 경우에 OUTPUT CLASS 파라미터에 값의 지정이 있으면 해당 지정 값이 적용된다. 만약 SYSOUT에 CLASS 지정이 없고 OUTPUT문에도 CLASS 파라미터를 지정하지 않았다면 JOB 문의 MSGCLASS에 지정된 값이 OUTPUT의 CLASS로 적용된다.

이 중 어느 곳에도 CLASS를 명시하지 않았다면 OpenFrame 환경설정에 tjclrun 서브젝트, JOB 섹션의 MSGCLASS 키의 VALUE 항목에 지정되어 있는 값이 선택된다.

3.3. OUTPUT DISPOSITION

OUTPUT에 부여된 조치사항이다. JOB이 성공적으로 종료되었는지 여부에 따라 정상 처리(Normal Disposition)와 비정상 처리(Abnormal Disposition)로 나뉜다.

다음은 OUTPUT DISPOSTION에 따른 JOB 처리 과정을 나타낸 그림이다.

figure 5 1
OUTPUT DISP에 따른 처리과정

DISP의 종류와 성격은 다음과 같다.

종류 설명

WRITE

OUTPUT이 스케줄링되어 프린트되어야 함을 의미한다. 정상 처리되면 OUTPUT이 삭제된다.

HOLD

사용자가 해제할 때까지 스케줄링되지 않고 OUTPUTQ에 대기한다. 사용자가 해제하면 DISP는 WRITE로 변경된다.

KEEP

WRITE와 마찬가지로 OUTPUT이 스케줄링되어 프린트되어야 함을 의미한다. 정상 처리된 후 DISP는 LEAVE로 변경된다.

LEAVE

사용자가 해제할 때까지 스케줄링받지 않고 OUTPUTQ에 대기한다. 사용자가 해제하면 DISP는 KEEP으로 변경된다.

PURGE

OUTPUTQ에서 삭제한다.

OUTPUT DISPOSITION은 다음과 같은 방법으로 지정한다.

  1. JCL의 OUTPUT 문으로 지정한다.

    다음 예에서는 PRINT DD의 OUTPUT DISPOSITION에 정상 처리로 WRITE, 비정상 처리로 PURGE가 지정된다. 즉, JCL이 수행되어 JOB이 정상 종료되면 OUTPUT을 처리하고, JOB이 비정상 종료되면 OUTPUT을 처리하지 않는다.

    //OUT1     OUTPUT  OUTDISP=(WRITE,PURGE)
    //PRINT    DD SYSOUT=(A,),OUTPUT=*.OUT1
  2. 다음 예에서 SUBM DD는 INTRDR 속성을 가진다.

    JOB이 끝난 후 SUBM DD에 정의된 SYSOUT 데이터는 인터널 리더를 통하여 submit된다.

    //SUBM    DD SYSOUT=(A,INTRDR)
  3. JCL의 OUTPUT 문에서 지정하지 않으면, OUTPUT CLASS에 따라 OpenFrame 환경설정에 설정된 값으로 지정된다.

    설정 내용은 OpenFrame 환경설정에 tjes 서브젝트, OUTCLASS 섹션에서 OUTPUT DISPOSITION이 클래스에 따라 다음과 같은 예처럼 정의된다.

    OUTPUT CLASS가 A인 OUTPUT은 '(WRITE,WRITE)'로 지정되고, OUTPUT CLASS가 B이면 '(HOLD,PURGE)'로 지정된다. 만약 OUTPUT CLASS에 해당하는 DISP이 OUTCLASS 섹션에 정의되어 있지 않으면 기본 값으로 '(PURGE,PURGE:80)'가 사용된다.

    $ ofconfig list -n NODE1 -s tjes -sec OUTCLASS
    
    ===================================================================================
      SUBJECT   |     SECTION      |         KEY         |            VALUE
    ===================================================================================
        tjes    |     OUTCLASS     |          A          |         WRITE,WRITE
                |                  |          B          |         HOLD,PURGE
    ===================================================================================

OUTPUTQ에 들어있는 OUTPUT들은 인터널 리더를 통해 처리되어 JOB으로 다시 submit되어야 할 것들과 외부 라이터로 전송되어야 할 것들, 리포트를 위해 프린트되어야 할 것들이 있다.

인터널 리더를 통해 처리되는 OUTPUT들은 OUTPUT DISPOSITION이 WRITE 또는 KEEP이고, OpenFrame 환경설정의 print 서브젝트, INTRDR 섹션에 등록되어 있으면 OUTPUT CLASS에 상관없이 무조건 인터널 리더에 의해 submit된다.

외부 라이터로 전송되어야 할 OUTPUT들은 인터널 리더와 유사하게 OUTPUT DISPOSITION이 WRITE 또는 KEEP이고, OpenFrame 환경설정의 print 서브젝트, WRITER 섹션에 SMTPP(SMTP)와 같이 외부 라이터명을 키로 등록하고 해당 외부 라이터를 호출할 공유 라이브러리의 경로를 값으로 지정해두면 OUTPUT CLASS에 상관없이 지정된 라이브러리를 호출하여 실행한다.

프린트되어야 할 OUTPUT들은 OUTPUT DISPOSITION이 WRITE 또는 KEEP일 때 OUTPUT CLASS 정보를 OpenFrame 환경설정의 print 서브젝트, PRINTERn 섹션에 등록된 클래스 정보와 비교하여 정보가 맞으면 프린트된다. PRINTERn 섹션에 등록된 클래스 정보가 SYSOUT의 OUTPUT CLASS를 포함하고 있으면, ofrpmsvr은 PRINTERn 섹션에 설정된 명령어와 공유 라이브러리를 사용하여 외부 프린터 솔루션에 데이터와 프린트 리소스 정보를 전달한다.

3.4. Internal Reader

인터널 리더(Internal Reader)는 Online CICS 또는 Batch 프로그램이 JOB을 TJES로 submit할 수 있도록 하는 모듈이다. OpenFrame 상에서 동작하는 모든 JOB은 인터널 리더를 통해 submit할 수 있다.

인터널 리더를 사용하기 위해서는 DD 문에 SYSOUT=(out_class,INTRDR)와 같이 기술하여, DD에 저장된 내용이 인터널 리더로 출력하도록 한다.

다음 예제는 인터널 리더 사용법을 보여준다.

###########################################################################
## IEBEDT05 - iebedit SYSUT1 JCL and extract RMSTEP1 only.               ##
##            then submit it to intrdr                                   ##
###########################################################################
//IEBEDT05 JOB CLASS=A,MSGCLASS=X,MSGLEVEL=(1,1)
//IEBEDT   EXEC PGM=IEBEDIT
//SYSIN    DD *
    EDIT START=,TYPE=INCLUDE
/*
//SYSUT2   DD SYSOUT=(A,INTRDR)
//SYSUT1   DD DATA
INTERNAL READER로 submit하고자 하는 JCL 내용
/*
//

위 JCL은 SYSUT1 DD로 주어진 JCL을 SYSUT2로 복사하여 SYSUT2를 CLASS A의 인터널 리더로 출력하는 JOB이다.

위와 같이 JCL에 USER와 PASSWD가 기술되지 않은 경우 인터널 리더는 OpenFrame 환경설정의 tjes 서브젝트, INTRDR 섹션의 USERNAME, PASSWORD 키의 VALUE 항목을 이용하여 JCL을 submit한다.

3.5. External Writer

External Writer는 JOB 수행 후 생성된 OUTPUT들을 공유 라이브러리를 통해 SMTP 등 OpenFrame에서 제공하지 않는 외부 기능을 호출하여 처리할 수 있도록 하는 모듈이다.

External Writer를 사용하기 위해서는 DD 문에 SYSOUT=(out_class,external_writer_name)과 같이 기술하고, OpenFrame 환경설정에 print 서브젝트, WRITER 섹션의 external_writer_name에 해당하는 키와 그에 맞는 VALUE를 지정해야 한다. 현재 OpenFrame에서는 External Writer로 SMTPP(SMTP)만 지원하고 있다.

OpenFrame에서 SMTPP(SMTP)를 사용하기 위해서는 2개의 소프트웨어가 준비되어야 한다.

  1. MTA (Mail transport Agent): 메일 송수신을 위한 메일 전송 에이전트이며, 기본적으로 SMTP(메일 전송 프로토콜) 포트인 25번 포트를 사용한다. sendmail, postfix 등이 있다.

  2. Netcat: TCP나 UDP 프로토콜을 사용하는 네트워크 연결에서 데이터를 읽고 쓰는 유틸리티이다. OpenFrame에서는 Netcat 커맨드를 통해 SMTP 포트인 25번 포트에 연결하고 메일 데이터를 보낸다. 이후 MTA(postfix 등)를 통해 메일이 전송된다.

다음 예제는 Extenral Writer인 SMTPP(SMTP)의 사용법을 보여준다.

//EXTJOB   JOB (MDB114J),'          ',
//         CLASS=A,
//         MSGCLASS=K,
//         MSGLEVEL=(1,1),
//         NOTIFY=&SYSUID
//*
//JCLLIB   JCLLIB ORDER=(SCDC.PROD.JCLLIB)
//*
//JOBLIB   INCLUDE MEMBER=JOBLIB
//JSTEP01  EXEC PGM=IEBGENER
//SYSIN    DD DUMMY (MODE=I)
//SYSPRINT DD SYSOUT=*
//SYSUT2   DD SYSOUT=(B,SMTPP)
//SYSUT1   DD *
HELO JES2PRD1
MAIL FROM:<sender@tmax.co.kr>
RCPT TO:<recipient@tmax.co.kr>
/*
//         DD *
DATA
SUBJECT: SMTP TEST

THIS IS A TEST MAIL, From OpenFrame
PROCESSING.
/*
//*

위 JCL은 SYSUT1 DD로 주어진 JCL을 SYSUT2로 복사하여 SYSUT2를 SYSOUT에 지정된 External Writer인 SMTPP(SMTP)를 통해 SMTP 서버로 메일을 전송하는 JOB이다.

SMTP(SMTPP)모듈의 동작구조는 다음과 같다.

figure 5 2
SMTP 동작구조
  1. JCL의 메일 관련 데이터를 가공하여 파일에 저장한다.

  2. Netcat 유틸리티를 통해 localhost의 25번 포트로 연결하고 해당 파일을 전달한다. 25번 포트는 SMTP포트로, postfix 등을 통해 메일을 보내거나 메일 서버끼리 메일을 주고 받을 때 주로 사용한다.

  3. postfix 등의 메일 송신 에이전트가 파일에 적힌 SMTP 커맨드를 수행하고 메일을 전송한다.

3.6. 그 외 Printer

Internal Reader 또는 External Writer가 지정된 경우를 제외하면 TJES에서는 OpenFrame 환경설정의 print 서브젝트, PRINTERn 섹션에 최대 9개까지 프린터를 지정하여 SYSOUT의 OUTPUT에 대한 출력 처리를 할 수 있다. OpenFrame에서는 출력 처리를 직접 수행하지는 않으며, 외부 프린터 솔루션을 선정하여 출력에 필요한 정보들을 전달하는 방식으로 출력 처리를 수행한다.

PRINTERn 섹션에는 각각 CLASS, COMMAND, DRIVER_PATH 를 키로 지정할 수 있다.

CLASS 키에는 해당 프린터에서 처리할 수 있는 출력 클래스를 값으로 지정한다. 만약 SYSOUT에 지정된 출력 클래스와 일치하는 클래스가 기술되어 있지 않다면 출력 처리는 수행되지 않는다.

COMMAND 키에는 외부 프린터 솔루션에 전달할 명령어를 값으로 지정한다.

DRIVER_PATH 키에는 외부 프린터 솔루션과의 인터페이스를 위해 OpenFrame에서 제공하는 공유 라이브러리의 경로를 값으로 지정한다. 현재 OpenFrame에서는 libbspprt.so, liblrsprt.so의 2가지 공유 라이브러리를 지원하고 있다.

libbspprt.so에서는 OUTPUT에 관한 정보를 담고 있는 outputid.cc, outputid.ec라는 2개의 스크립트 파일을 생성한다. 각 파일에 출력되는 정보는 다음과 같다.

파일 종류 출력 정보

*.ec

STORE:
CLS={출력 클래스}
PATTERN=99
PROGRAMN={프로그램명}
INPUT_COUNT=1
INPUT1:
INPUT={출력 경로}
RID_COUNT=1
INPUT_RID1:
RID=

*.cc

CHANGE:
RI_COUNT=1
RI1:
RID=
JOB={작업명}
STEP={스텝명}
JOBNO={작업 아이디}
LPCI={form lpci}
OVERLAYNAME={form overlay name}
CODE={form code}
NOTE={note}
SHEETSIZE={forms form size}
LANDSCAPE=
PRINTMODE={PORTRAIT | LANDSCAPE | format}
CLISTN={clist명}
CLISTCMD={BATCH | clist 명령어}
DDN={DD명}
DSNAME={데이터셋명}
TERMINAL={terminal}
SIDE={forms side}
FILE={데이터셋명}
RI1_DI1:
DIST=ALL
SSET=01
COPY={copies | 1}

liblrsprt.so에서도 libbspprt.so와 동일하게 outputid.cc, outputid.ec라는 2개의 스크립트 파일을 생성한다. 하지만 각 파일에 출력되는 정보는 libbspprt.so의 출력 정보와 차이가 있으며, 내용은 다음과 같다.

파일 종류 출력 정보

*.ec

STORE:
CLS={출력 클래스}
PATTERN={forms}
PROGRAMN=
INPUT_COUNT=1
INPUT1:
INPUT={출력 경로}
RID_COUNT=1
INPUT1_RID1:
RID={라이터명 | 999999999999999999999999}
OUTPUT:
USERDATAn={userdata}
ADDRESS={address}
DEST={dest}
ROOM='{room}'
BUILDING='{building}'
DEPT='{dept}'
NAME='{name}'
CHARS={chars}
FCB={fcb}
FORMDEF={formdef}
FORMS={forms}
JESDS={jesds}
MAILCC={mailcc}
MAILBCC={mailbcc}
MAILFROM='{mailfrom}'
MAILTO={mailto}
OVERLAYB={overlayb}
OVERLAYF={overlayf}
PAGEDEF={pagedef}
REPLYTO={replyto}
RETAINS='{retains}'
TITLE='{title}'
TRC={trc}
UCS={ucs}
USERLIB={userlib}
WRITER={라이터명}
BURST={burst}
DATACK={datack}
DEFAULT={default}
NOTIFY={notify}
PIMSG={YES | NO}
PORTNO={portno}
PRMODE={prmode}
PRTY={prty}

*.cc

CHANGE:
RI_COUNT=1
RI1:
RID={라이터명 | 999999999999999999999999}
CODE={A | M | F | 0 | 1 | 2}
JOB='{작업명}'
STEP='{스텝명}'
DD='{DD명}'
JOBNO='{작업 아이디}'
MAXLL={lecord length}
FCB='{fcb}'
COPIES={copies | 1}