Case Study 1: Multi-Screen Account Management Application
[IBM Enterprise COBOL]
Background
Cornerstone National Bank is replacing its aging green-screen account management system with a modernized CICS application. The existing system consists of twelve separate CICS transactions, each with its own program, that were developed independently over two decades. Tellers must memorize twelve different transaction codes, navigate inconsistent screen layouts, and manually re-enter customer information when moving between functions. A task that should take thirty seconds -- looking up a customer, viewing their account, and posting a deposit -- requires three separate transactions and nearly two minutes of key entry.
The replacement application consolidates the most common teller operations into a single, menu-driven CICS application with seamless navigation between screens. The new application uses a single transaction code (ACMG) and manages all screen flow internally using COMMAREA-based state management, XCTL for screen-to-screen navigation, and TS queues for browse list support.
This case study walks through the complete design and implementation of the four-screen application: a main menu, an account inquiry screen, a transaction entry screen, and a confirmation screen.
Problem Statement
The application must support the following workflow:
- Main Menu -- The teller enters a customer account number and selects an action: Inquiry, Deposit, Withdrawal, or Transfer.
- Account Inquiry -- Displays the account details including customer name, account type, balances, and the last ten transactions. Supports PF7/PF8 paging through the transaction history.
- Transaction Entry -- Allows the teller to enter a deposit, withdrawal, or transfer amount. Validates the amount against business rules (minimum deposit, sufficient funds for withdrawals, valid target account for transfers).
- Confirmation -- Displays a summary of the pending transaction and asks the teller to confirm or cancel. Upon confirmation, the transaction is posted and a receipt reference number is generated.
Navigation rules: - PF3 from any screen returns to the previous screen - PF12 from any screen returns to the main menu - ENTER processes the current screen's action - Clear key ends the transaction
Application Architecture
Screen Flow
+-------------------+
| MAIN MENU |
| (ACMGMENU map) |
+--------+----------+
|
+--------------+--------------+
| |
+--------v---------+ +---------v--------+
| ACCOUNT INQUIRY | | TRANSACTION ENTRY|
| (ACMGINQ map) | | (ACMGTXN map) |
+--------+---------+ +---------+--------+
| |
| PF7/PF8: page | ENTER: validate
| through TSQ |
| +--------v--------+
| | CONFIRMATION |
| | (ACMGCNF map) |
| +-----------------+
COMMAREA Design
The COMMAREA carries all state information between pseudo-conversational interactions:
01 WS-COMMAREA.
* Header section
05 CA-VERSION PIC 9(02) VALUE 01.
05 CA-EYE-CATCHER PIC X(08) VALUE 'ACMGCA '.
* Navigation state
05 CA-CURRENT-SCREEN PIC X(04).
88 CA-MENU-SCREEN VALUE 'MENU'.
88 CA-INQ-SCREEN VALUE 'INQY'.
88 CA-TXN-SCREEN VALUE 'TXNE'.
88 CA-CNF-SCREEN VALUE 'CONF'.
05 CA-PREV-SCREEN PIC X(04).
05 CA-ACTION-CODE PIC X(01).
88 CA-ACTION-INQUIRY VALUE 'I'.
88 CA-ACTION-DEPOSIT VALUE 'D'.
88 CA-ACTION-WITHDRAWAL VALUE 'W'.
88 CA-ACTION-TRANSFER VALUE 'T'.
* Account context
05 CA-ACCOUNT-NUM PIC X(12).
05 CA-CUST-NAME PIC X(30).
05 CA-ACCT-TYPE PIC X(02).
05 CA-CURRENT-BAL PIC S9(11)V99 COMP-3.
05 CA-AVAIL-BAL PIC S9(11)V99 COMP-3.
* Transaction context
05 CA-TXN-AMOUNT PIC S9(09)V99 COMP-3.
05 CA-TXN-TARGET-ACCT PIC X(12).
05 CA-TXN-REF-NUM PIC X(16).
05 CA-TXN-TIMESTAMP PIC X(26).
* Browse state (for inquiry paging)
05 CA-TSQ-NAME PIC X(08).
05 CA-TSQ-TOTAL-ITEMS PIC 9(05) VALUE 0.
05 CA-CURRENT-PAGE PIC 9(03) VALUE 1.
05 CA-PAGE-SIZE PIC 9(02) VALUE 10.
* Error message
05 CA-MESSAGE PIC X(79).
* Filler for expansion
05 CA-FILLER PIC X(50).
The COMMAREA is 300 bytes -- well within the 32,763-byte COMMAREA limit. The version field and eye-catcher support future upgrades. The navigation state fields (CA-CURRENT-SCREEN, CA-PREV-SCREEN) implement the state machine that controls screen flow.
BMS Map Definitions
Main Menu Map
ACMGMMS DFHMSD TYPE=MAP,MODE=INOUT,LANG=COBOL,TIOAPFX=YES, X
STORAGE=AUTO,CTRL=(FREEKB,FRSET)
ACMGMENU DFHMDI SIZE=(24,80),LINE=1,COLUMN=1
DFHMDF POS=(01,01),LENGTH=79, X
ATTRB=(ASKIP,BRT), X
INITIAL='CORNERSTONE NATIONAL BANK - ACCOUNT MANAGEMEX
NT'
DFHMDF POS=(02,01),LENGTH=79,ATTRB=(ASKIP), X
INITIAL='-----------------------------------------------X
--------------------------------'
DFHMDF POS=(04,03),LENGTH=15,ATTRB=(ASKIP), X
INITIAL='Account Number:'
ACCTNO DFHMDF POS=(04,19),LENGTH=12,ATTRB=(UNPROT,BRT,IC,FSET)
DFHMDF POS=(04,32),LENGTH=1,ATTRB=(ASKIP)
DFHMDF POS=(06,03),LENGTH=25,ATTRB=(ASKIP), X
INITIAL='Select Action:'
DFHMDF POS=(08,05),LENGTH=30,ATTRB=(ASKIP), X
INITIAL='1. Account Inquiry'
DFHMDF POS=(09,05),LENGTH=30,ATTRB=(ASKIP), X
INITIAL='2. Deposit'
DFHMDF POS=(10,05),LENGTH=30,ATTRB=(ASKIP), X
INITIAL='3. Withdrawal'
DFHMDF POS=(11,05),LENGTH=30,ATTRB=(ASKIP), X
INITIAL='4. Transfer'
DFHMDF POS=(13,03),LENGTH=10,ATTRB=(ASKIP), X
INITIAL='Selection:'
ACTION DFHMDF POS=(13,14),LENGTH=1,ATTRB=(UNPROT,BRT,FSET)
DFHMDF POS=(13,16),LENGTH=1,ATTRB=(ASKIP)
DFHMDF POS=(22,01),LENGTH=79,ATTRB=(ASKIP), X
INITIAL='PF3=Exit ENTER=Submit'
MSGFLD DFHMDF POS=(23,01),LENGTH=79,ATTRB=(ASKIP,BRT)
DFHMDF POS=(24,01),LENGTH=79,ATTRB=(ASKIP), X
INITIAL='ACMG V1.0 Cornerstone National Bank'
DFHMSD TYPE=FINAL
END
Account Inquiry Map
The inquiry map displays account details and a scrollable transaction list:
ACMGIMS DFHMSD TYPE=MAP,MODE=INOUT,LANG=COBOL,TIOAPFX=YES, X
STORAGE=AUTO,CTRL=(FREEKB,FRSET)
ACMGINQ DFHMDI SIZE=(24,80),LINE=1,COLUMN=1
DFHMDF POS=(01,01),LENGTH=40,ATTRB=(ASKIP,BRT), X
INITIAL='ACCOUNT INQUIRY'
IACCTNO DFHMDF POS=(01,50),LENGTH=12,ATTRB=(ASKIP)
DFHMDF POS=(03,03),LENGTH=12,ATTRB=(ASKIP), X
INITIAL='Customer:'
ICNAME DFHMDF POS=(03,16),LENGTH=30,ATTRB=(ASKIP)
DFHMDF POS=(04,03),LENGTH=12,ATTRB=(ASKIP), X
INITIAL='Acct Type:'
IACTYPE DFHMDF POS=(04,16),LENGTH=15,ATTRB=(ASKIP)
DFHMDF POS=(05,03),LENGTH=12,ATTRB=(ASKIP), X
INITIAL='Status:'
IASTATUS DFHMDF POS=(05,16),LENGTH=10,ATTRB=(ASKIP)
DFHMDF POS=(06,03),LENGTH=15,ATTRB=(ASKIP), X
INITIAL='Current Bal:'
ICURBAL DFHMDF POS=(06,19),LENGTH=16,ATTRB=(ASKIP)
DFHMDF POS=(07,03),LENGTH=15,ATTRB=(ASKIP), X
INITIAL='Available Bal:'
IAVLBAL DFHMDF POS=(07,19),LENGTH=16,ATTRB=(ASKIP)
DFHMDF POS=(09,01),LENGTH=79,ATTRB=(ASKIP), X
INITIAL='--- RECENT TRANSACTIONS -----------------------X
--'
DFHMDF POS=(10,01),LENGTH=79,ATTRB=(ASKIP), X
INITIAL='Date Type Amount Description'
* Transaction lines (10 rows)
TDATE1 DFHMDF POS=(11,01),LENGTH=10,ATTRB=(ASKIP)
TTYPE1 DFHMDF POS=(11,12),LENGTH=06,ATTRB=(ASKIP)
TAMNT1 DFHMDF POS=(11,19),LENGTH=16,ATTRB=(ASKIP)
TDESC1 DFHMDF POS=(11,36),LENGTH=40,ATTRB=(ASKIP)
* (Lines 2-10 follow the same pattern at POS rows 12-20)
TDATE2 DFHMDF POS=(12,01),LENGTH=10,ATTRB=(ASKIP)
TTYPE2 DFHMDF POS=(12,12),LENGTH=06,ATTRB=(ASKIP)
TAMNT2 DFHMDF POS=(12,19),LENGTH=16,ATTRB=(ASKIP)
TDESC2 DFHMDF POS=(12,36),LENGTH=40,ATTRB=(ASKIP)
TDATE3 DFHMDF POS=(13,01),LENGTH=10,ATTRB=(ASKIP)
TTYPE3 DFHMDF POS=(13,12),LENGTH=06,ATTRB=(ASKIP)
TAMNT3 DFHMDF POS=(13,19),LENGTH=16,ATTRB=(ASKIP)
TDESC3 DFHMDF POS=(13,36),LENGTH=40,ATTRB=(ASKIP)
* ... lines 4-10 omitted for brevity, same pattern ...
DFHMDF POS=(21,01),LENGTH=40,ATTRB=(ASKIP)
IPAGMSG DFHMDF POS=(21,45),LENGTH=30,ATTRB=(ASKIP)
DFHMDF POS=(22,01),LENGTH=79,ATTRB=(ASKIP), X
INITIAL='PF3=Menu PF7=Prev PF8=Next ENTER=Refresh'
IMSGFLD DFHMDF POS=(23,01),LENGTH=79,ATTRB=(ASKIP,BRT)
DFHMSD TYPE=FINAL
END
Main Program
IDENTIFICATION DIVISION.
PROGRAM-ID. ACMGMAIN.
*================================================================*
* CORNERSTONE NATIONAL BANK *
* ACCOUNT MANAGEMENT - MAIN CONTROLLER PROGRAM *
* *
* This program implements a four-screen CICS application *
* using pseudo-conversational design with COMMAREA state *
* management. It handles: *
* - Main Menu (account selection and action choice) *
* - Account Inquiry (with TSQ-based paging) *
* - Transaction Entry (deposit/withdrawal/transfer) *
* - Confirmation (review and commit) *
*================================================================*
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-PROGRAM-ID PIC X(08) VALUE 'ACMGMAIN'.
* COMMAREA definition
01 WS-COMMAREA.
05 CA-VERSION PIC 9(02) VALUE 01.
05 CA-EYE-CATCHER PIC X(08) VALUE 'ACMGCA '.
05 CA-CURRENT-SCREEN PIC X(04).
88 CA-MENU-SCREEN VALUE 'MENU'.
88 CA-INQ-SCREEN VALUE 'INQY'.
88 CA-TXN-SCREEN VALUE 'TXNE'.
88 CA-CNF-SCREEN VALUE 'CONF'.
05 CA-PREV-SCREEN PIC X(04).
05 CA-ACTION-CODE PIC X(01).
88 CA-ACTION-INQUIRY VALUE 'I'.
88 CA-ACTION-DEPOSIT VALUE 'D'.
88 CA-ACTION-WITHDRAWAL VALUE 'W'.
88 CA-ACTION-TRANSFER VALUE 'T'.
05 CA-ACCOUNT-NUM PIC X(12).
05 CA-CUST-NAME PIC X(30).
05 CA-ACCT-TYPE PIC X(02).
05 CA-CURRENT-BAL PIC S9(11)V99 COMP-3.
05 CA-AVAIL-BAL PIC S9(11)V99 COMP-3.
05 CA-TXN-AMOUNT PIC S9(09)V99 COMP-3.
05 CA-TXN-TARGET-ACCT PIC X(12).
05 CA-TXN-REF-NUM PIC X(16).
05 CA-TXN-TIMESTAMP PIC X(26).
05 CA-TSQ-NAME PIC X(08).
05 CA-TSQ-TOTAL-ITEMS PIC 9(05) VALUE 0.
05 CA-CURRENT-PAGE PIC 9(03) VALUE 1.
05 CA-PAGE-SIZE PIC 9(02) VALUE 10.
05 CA-MESSAGE PIC X(79).
05 CA-FILLER PIC X(50).
* Symbolic map areas (generated by BMS assembly)
* In production these would be COPY statements
01 MENU-MAPI.
05 FILLER PIC X(12).
05 ACCTNO-I PIC X(12).
05 ACTION-I PIC X(01).
01 MENU-MAPO.
05 FILLER PIC X(12).
05 ACCTNO-O PIC X(12).
05 ACTION-O PIC X(01).
05 MSGFLD-O PIC X(79).
* DB2 host variables
01 WS-DB2-FIELDS.
05 WS-DB-ACCT-NUM PIC X(12).
05 WS-DB-CUST-NAME PIC X(30).
05 WS-DB-ACCT-TYPE PIC X(02).
05 WS-DB-STATUS PIC X(01).
05 WS-DB-CURRENT-BAL PIC S9(11)V99 COMP-3.
05 WS-DB-AVAIL-BAL PIC S9(11)V99 COMP-3.
* TSQ record for transaction history
01 WS-TSQ-RECORD.
05 WS-TSQ-DATE PIC X(10).
05 WS-TSQ-TYPE PIC X(06).
05 WS-TSQ-AMOUNT PIC X(16).
05 WS-TSQ-DESC PIC X(40).
01 WS-TSQ-REC-LEN PIC S9(04) COMP
VALUE 72.
* Work fields
01 WS-RESP PIC S9(08) COMP.
01 WS-RESP2 PIC S9(08) COMP.
01 WS-CA-LENGTH PIC S9(04) COMP.
01 WS-MAP-LENGTH PIC S9(04) COMP.
01 WS-TSQ-ITEM PIC S9(04) COMP.
01 WS-START-ITEM PIC 9(05).
01 WS-LINE-IDX PIC 9(02).
01 WS-TOTAL-PAGES PIC 9(03).
01 WS-PAGE-MSG PIC X(30).
01 WS-FMT-BAL PIC -(11)9.99.
01 WS-FMT-AMT PIC -(9)9.99.
01 WS-AID-KEY PIC X(01).
01 WS-ABSTIME PIC S9(15) COMP-3.
01 WS-FORMATTED-TIME PIC X(26).
COPY DFHAID.
COPY DFHBMSCA.
LINKAGE SECTION.
01 DFHCOMMAREA PIC X(300).
PROCEDURE DIVISION.
0000-MAIN-CONTROL.
* Determine if this is first entry or a return
IF EIBCALEN = ZERO
PERFORM 1000-FIRST-TIME-ENTRY
ELSE
MOVE DFHCOMMAREA TO WS-COMMAREA
MOVE EIBAID TO WS-AID-KEY
PERFORM 0100-ROUTE-BY-STATE
END-IF
EXEC CICS RETURN
TRANSID('ACMG')
COMMAREA(WS-COMMAREA)
LENGTH(LENGTH OF WS-COMMAREA)
END-EXEC.
0100-ROUTE-BY-STATE.
* Handle CLEAR key globally -- end transaction
IF WS-AID-KEY = DFHCLEAR
PERFORM 0200-CLEANUP-AND-EXIT
END-IF
* Handle PF12 globally -- return to menu
IF WS-AID-KEY = DFHPF12
PERFORM 1000-FIRST-TIME-ENTRY
ELSE
* Route based on current screen state
EVALUATE TRUE
WHEN CA-MENU-SCREEN
PERFORM 2000-PROCESS-MENU
WHEN CA-INQ-SCREEN
PERFORM 3000-PROCESS-INQUIRY
WHEN CA-TXN-SCREEN
PERFORM 4000-PROCESS-TRANSACTION
WHEN CA-CNF-SCREEN
PERFORM 5000-PROCESS-CONFIRMATION
WHEN OTHER
PERFORM 1000-FIRST-TIME-ENTRY
END-EVALUATE
END-IF.
0200-CLEANUP-AND-EXIT.
* Delete TSQ if it exists
IF CA-TSQ-NAME NOT = SPACES
EXEC CICS DELETEQ TS
QUEUE(CA-TSQ-NAME)
RESP(WS-RESP)
END-EXEC
END-IF
EXEC CICS SEND CONTROL
ERASE
FREEKB
END-EXEC
EXEC CICS RETURN
END-EXEC.
*================================================================*
* 1000 - FIRST TIME ENTRY: DISPLAY MAIN MENU *
*================================================================*
1000-FIRST-TIME-ENTRY.
INITIALIZE WS-COMMAREA
MOVE 01 TO CA-VERSION
MOVE 'ACMGCA ' TO CA-EYE-CATCHER
MOVE 'MENU' TO CA-CURRENT-SCREEN
MOVE SPACES TO CA-MESSAGE
EXEC CICS SEND
MAP('ACMGMENU')
MAPSET('ACMGMMS')
ERASE
RESP(WS-RESP)
END-EXEC
IF WS-RESP NOT = DFHRESP(NORMAL)
PERFORM 9000-SEND-ERROR
END-IF.
*================================================================*
* 2000 - PROCESS MENU SCREEN INPUT *
*================================================================*
2000-PROCESS-MENU.
* Receive the menu map
EXEC CICS RECEIVE
MAP('ACMGMENU')
MAPSET('ACMGMMS')
INTO(MENU-MAPI)
RESP(WS-RESP)
END-EXEC
IF WS-RESP NOT = DFHRESP(NORMAL)
MOVE 'Error receiving menu input'
TO CA-MESSAGE
PERFORM 1000-FIRST-TIME-ENTRY
ELSE
* Validate account number
IF ACCTNO-I = SPACES OR ACCTNO-I = LOW-VALUES
MOVE 'Please enter an account number'
TO CA-MESSAGE
PERFORM 2900-RESEND-MENU
ELSE
MOVE ACCTNO-I TO CA-ACCOUNT-NUM
* Validate action selection
EVALUATE ACTION-I
WHEN '1'
SET CA-ACTION-INQUIRY TO TRUE
WHEN '2'
SET CA-ACTION-DEPOSIT TO TRUE
WHEN '3'
SET CA-ACTION-WITHDRAWAL TO TRUE
WHEN '4'
SET CA-ACTION-TRANSFER TO TRUE
WHEN OTHER
MOVE 'Invalid selection. Choose 1-4.'
TO CA-MESSAGE
PERFORM 2900-RESEND-MENU
END-EVALUATE
* Look up the account in DB2
PERFORM 2100-LOOKUP-ACCOUNT
END-IF
END-IF.
2100-LOOKUP-ACCOUNT.
MOVE CA-ACCOUNT-NUM TO WS-DB-ACCT-NUM
EXEC SQL
SELECT CUST_NAME, ACCT_TYPE, ACCT_STATUS,
CURRENT_BAL, AVAILABLE_BAL
INTO :WS-DB-CUST-NAME,
:WS-DB-ACCT-TYPE,
:WS-DB-STATUS,
:WS-DB-CURRENT-BAL,
:WS-DB-AVAIL-BAL
FROM ACCOUNT_MASTER
WHERE ACCT_NUMBER = :WS-DB-ACCT-NUM
END-EXEC
EVALUATE SQLCODE
WHEN 0
MOVE WS-DB-CUST-NAME TO CA-CUST-NAME
MOVE WS-DB-ACCT-TYPE TO CA-ACCT-TYPE
MOVE WS-DB-CURRENT-BAL TO CA-CURRENT-BAL
MOVE WS-DB-AVAIL-BAL TO CA-AVAIL-BAL
EVALUATE TRUE
WHEN CA-ACTION-INQUIRY
PERFORM 3100-LOAD-HISTORY-TSQ
MOVE 'INQY' TO CA-CURRENT-SCREEN
MOVE 'MENU' TO CA-PREV-SCREEN
PERFORM 3200-SEND-INQUIRY-MAP
WHEN CA-ACTION-DEPOSIT
OR CA-ACTION-WITHDRAWAL
OR CA-ACTION-TRANSFER
MOVE 'TXNE' TO CA-CURRENT-SCREEN
MOVE 'MENU' TO CA-PREV-SCREEN
PERFORM 4100-SEND-TXN-MAP
END-EVALUATE
WHEN +100
MOVE 'Account not found. Please verify.'
TO CA-MESSAGE
PERFORM 2900-RESEND-MENU
WHEN OTHER
STRING 'Database error. SQLCODE='
SQLCODE
DELIMITED BY SIZE
INTO CA-MESSAGE
PERFORM 2900-RESEND-MENU
END-EVALUATE.
2900-RESEND-MENU.
MOVE CA-MESSAGE TO MSGFLD-O
EXEC CICS SEND
MAP('ACMGMENU')
MAPSET('ACMGMMS')
FROM(MENU-MAPO)
DATAONLY
RESP(WS-RESP)
END-EXEC.
*================================================================*
* 3000 - PROCESS ACCOUNT INQUIRY (with TSQ paging) *
*================================================================*
3000-PROCESS-INQUIRY.
IF WS-AID-KEY = DFHPF3
* Return to menu
PERFORM 0300-DELETE-TSQ
PERFORM 1000-FIRST-TIME-ENTRY
ELSE IF WS-AID-KEY = DFHPF7
* Page backward
IF CA-CURRENT-PAGE > 1
SUBTRACT 1 FROM CA-CURRENT-PAGE
END-IF
PERFORM 3200-SEND-INQUIRY-MAP
ELSE IF WS-AID-KEY = DFHPF8
* Page forward
COMPUTE WS-TOTAL-PAGES =
(CA-TSQ-TOTAL-ITEMS + CA-PAGE-SIZE - 1)
/ CA-PAGE-SIZE
IF CA-CURRENT-PAGE < WS-TOTAL-PAGES
ADD 1 TO CA-CURRENT-PAGE
END-IF
PERFORM 3200-SEND-INQUIRY-MAP
ELSE
* ENTER - refresh the display
PERFORM 3200-SEND-INQUIRY-MAP
END-IF.
0300-DELETE-TSQ.
IF CA-TSQ-NAME NOT = SPACES
EXEC CICS DELETEQ TS
QUEUE(CA-TSQ-NAME)
RESP(WS-RESP)
END-EXEC
MOVE SPACES TO CA-TSQ-NAME
END-IF.
3100-LOAD-HISTORY-TSQ.
* Build a unique TSQ name using terminal ID
STRING 'AH' EIBTRMID
DELIMITED BY SIZE
INTO CA-TSQ-NAME
* Delete any existing TSQ from a prior session
EXEC CICS DELETEQ TS
QUEUE(CA-TSQ-NAME)
RESP(WS-RESP)
END-EXEC
* Query transaction history from DB2
* Write each row to the TSQ for paging support
MOVE 0 TO CA-TSQ-TOTAL-ITEMS
MOVE 1 TO CA-CURRENT-PAGE
EXEC SQL DECLARE HIST_CURSOR CURSOR FOR
SELECT POST_DATE, TXN_TYPE, TXN_AMOUNT,
DESCRIPTION
FROM TRANSACTION_HISTORY
WHERE ACCT_NUMBER = :CA-ACCOUNT-NUM
ORDER BY POST_DATE DESC
FETCH FIRST 100 ROWS ONLY
END-EXEC
EXEC SQL OPEN HIST_CURSOR END-EXEC
PERFORM UNTIL SQLCODE NOT = 0
EXEC SQL FETCH HIST_CURSOR
INTO :WS-TSQ-DATE,
:WS-TSQ-TYPE,
:WS-TSQ-AMOUNT,
:WS-TSQ-DESC
END-EXEC
IF SQLCODE = 0
EXEC CICS WRITEQ TS
QUEUE(CA-TSQ-NAME)
FROM(WS-TSQ-RECORD)
LENGTH(WS-TSQ-REC-LEN)
RESP(WS-RESP)
END-EXEC
ADD 1 TO CA-TSQ-TOTAL-ITEMS
END-IF
END-PERFORM
EXEC SQL CLOSE HIST_CURSOR END-EXEC.
3200-SEND-INQUIRY-MAP.
* This paragraph populates and sends the inquiry map
* It reads the appropriate page of data from the TSQ
* Calculate the page message
COMPUTE WS-TOTAL-PAGES =
(CA-TSQ-TOTAL-ITEMS + CA-PAGE-SIZE - 1)
/ CA-PAGE-SIZE
IF WS-TOTAL-PAGES = 0
MOVE 1 TO WS-TOTAL-PAGES
END-IF
STRING 'Page ' CA-CURRENT-PAGE
' of ' WS-TOTAL-PAGES
DELIMITED BY SIZE
INTO WS-PAGE-MSG
* Read TSQ items for the current page
COMPUTE WS-START-ITEM =
(CA-CURRENT-PAGE - 1) * CA-PAGE-SIZE + 1
PERFORM VARYING WS-LINE-IDX FROM 1 BY 1
UNTIL WS-LINE-IDX > CA-PAGE-SIZE
COMPUTE WS-TSQ-ITEM =
WS-START-ITEM + WS-LINE-IDX - 1
IF WS-TSQ-ITEM <= CA-TSQ-TOTAL-ITEMS
EXEC CICS READQ TS
QUEUE(CA-TSQ-NAME)
INTO(WS-TSQ-RECORD)
LENGTH(WS-TSQ-REC-LEN)
ITEM(WS-TSQ-ITEM)
RESP(WS-RESP)
END-EXEC
* Map TSQ data to screen fields
* (In production, this would populate the
* symbolic map output area for each line)
END-IF
END-PERFORM
* Send the map
EXEC CICS SEND
MAP('ACMGINQ')
MAPSET('ACMGIMS')
ERASE
RESP(WS-RESP)
END-EXEC.
*================================================================*
* 4000 - PROCESS TRANSACTION ENTRY *
*================================================================*
4000-PROCESS-TRANSACTION.
IF WS-AID-KEY = DFHPF3
* Return to menu
PERFORM 1000-FIRST-TIME-ENTRY
ELSE
* Receive transaction entry map
PERFORM 4200-RECEIVE-TXN-MAP
END-IF.
4100-SEND-TXN-MAP.
* Populate and send the transaction entry screen
* Display account info and prompt for amount
EXEC CICS SEND
MAP('ACMGTXN')
MAPSET('ACMGTMS')
ERASE
RESP(WS-RESP)
END-EXEC.
4200-RECEIVE-TXN-MAP.
* Receive the transaction amount from the teller
* Validate business rules
* For deposits: minimum $1.00
IF CA-ACTION-DEPOSIT
IF CA-TXN-AMOUNT < 1.00
MOVE 'Minimum deposit is $1.00'
TO CA-MESSAGE
PERFORM 4100-SEND-TXN-MAP
ELSE
MOVE 'CONF' TO CA-CURRENT-SCREEN
MOVE 'TXNE' TO CA-PREV-SCREEN
PERFORM 5100-SEND-CONFIRM-MAP
END-IF
END-IF
* For withdrawals: check available balance
IF CA-ACTION-WITHDRAWAL
IF CA-TXN-AMOUNT > CA-AVAIL-BAL
MOVE 'Insufficient funds for withdrawal'
TO CA-MESSAGE
PERFORM 4100-SEND-TXN-MAP
ELSE
MOVE 'CONF' TO CA-CURRENT-SCREEN
MOVE 'TXNE' TO CA-PREV-SCREEN
PERFORM 5100-SEND-CONFIRM-MAP
END-IF
END-IF
* For transfers: validate target account exists
IF CA-ACTION-TRANSFER
PERFORM 4300-VALIDATE-TARGET-ACCT
END-IF.
4300-VALIDATE-TARGET-ACCT.
MOVE CA-TXN-TARGET-ACCT TO WS-DB-ACCT-NUM
EXEC SQL
SELECT ACCT_STATUS
INTO :WS-DB-STATUS
FROM ACCOUNT_MASTER
WHERE ACCT_NUMBER = :WS-DB-ACCT-NUM
END-EXEC
IF SQLCODE = 0
IF WS-DB-STATUS = 'O'
MOVE 'CONF' TO CA-CURRENT-SCREEN
MOVE 'TXNE' TO CA-PREV-SCREEN
PERFORM 5100-SEND-CONFIRM-MAP
ELSE
MOVE 'Target account is not open'
TO CA-MESSAGE
PERFORM 4100-SEND-TXN-MAP
END-IF
ELSE
MOVE 'Target account not found'
TO CA-MESSAGE
PERFORM 4100-SEND-TXN-MAP
END-IF.
*================================================================*
* 5000 - PROCESS CONFIRMATION *
*================================================================*
5000-PROCESS-CONFIRMATION.
IF WS-AID-KEY = DFHPF3
* Return to transaction entry
MOVE 'TXNE' TO CA-CURRENT-SCREEN
PERFORM 4100-SEND-TXN-MAP
ELSE IF WS-AID-KEY = DFHENTER
* Teller confirmed - post the transaction
PERFORM 5200-POST-TRANSACTION
ELSE
MOVE 'Press ENTER to confirm or PF3 to cancel'
TO CA-MESSAGE
PERFORM 5100-SEND-CONFIRM-MAP
END-IF.
5100-SEND-CONFIRM-MAP.
* Display confirmation screen with transaction summary
EXEC CICS SEND
MAP('ACMGCNF')
MAPSET('ACMGCMS')
ERASE
RESP(WS-RESP)
END-EXEC.
5200-POST-TRANSACTION.
* Get timestamp for the transaction
EXEC CICS ASKTIME
ABSTIME(WS-ABSTIME)
END-EXEC
EXEC CICS FORMATTIME
ABSTIME(WS-ABSTIME)
DATESEP('/')
TIMESEP(':')
FULLDATE(CA-TXN-TIMESTAMP)
END-EXEC
* Generate reference number
STRING 'TXN' EIBTRMID WS-ABSTIME(1:9)
DELIMITED BY SIZE
INTO CA-TXN-REF-NUM
* Update account balance in DB2
EVALUATE TRUE
WHEN CA-ACTION-DEPOSIT
EXEC SQL
UPDATE ACCOUNT_MASTER
SET CURRENT_BAL =
CURRENT_BAL + :CA-TXN-AMOUNT,
AVAILABLE_BAL =
AVAILABLE_BAL + :CA-TXN-AMOUNT,
LAST_ACTIVITY = CURRENT DATE
WHERE ACCT_NUMBER = :CA-ACCOUNT-NUM
END-EXEC
WHEN CA-ACTION-WITHDRAWAL
EXEC SQL
UPDATE ACCOUNT_MASTER
SET CURRENT_BAL =
CURRENT_BAL - :CA-TXN-AMOUNT,
AVAILABLE_BAL =
AVAILABLE_BAL - :CA-TXN-AMOUNT,
LAST_ACTIVITY = CURRENT DATE
WHERE ACCT_NUMBER = :CA-ACCOUNT-NUM
END-EXEC
WHEN CA-ACTION-TRANSFER
EXEC SQL
UPDATE ACCOUNT_MASTER
SET CURRENT_BAL =
CURRENT_BAL - :CA-TXN-AMOUNT,
AVAILABLE_BAL =
AVAILABLE_BAL - :CA-TXN-AMOUNT,
LAST_ACTIVITY = CURRENT DATE
WHERE ACCT_NUMBER = :CA-ACCOUNT-NUM
END-EXEC
EXEC SQL
UPDATE ACCOUNT_MASTER
SET CURRENT_BAL =
CURRENT_BAL + :CA-TXN-AMOUNT,
AVAILABLE_BAL =
AVAILABLE_BAL + :CA-TXN-AMOUNT,
LAST_ACTIVITY = CURRENT DATE
WHERE ACCT_NUMBER =
:CA-TXN-TARGET-ACCT
END-EXEC
END-EVALUATE
IF SQLCODE = 0
EXEC CICS SYNCPOINT END-EXEC
STRING 'Transaction posted. Ref: '
CA-TXN-REF-NUM
DELIMITED BY SIZE
INTO CA-MESSAGE
PERFORM 1000-FIRST-TIME-ENTRY
ELSE
EXEC CICS SYNCPOINT ROLLBACK END-EXEC
STRING 'Transaction failed. SQLCODE='
SQLCODE '. Please retry.'
DELIMITED BY SIZE
INTO CA-MESSAGE
PERFORM 4100-SEND-TXN-MAP
END-IF.
*================================================================*
* 9000 - ERROR HANDLING *
*================================================================*
9000-SEND-ERROR.
MOVE SPACES TO CA-MESSAGE
STRING 'System error. RESP=' WS-RESP
' RESP2=' WS-RESP2
'. Contact support.'
DELIMITED BY SIZE
INTO CA-MESSAGE
EXEC CICS SEND TEXT
FROM(CA-MESSAGE)
LENGTH(LENGTH OF CA-MESSAGE)
ERASE
RESP(WS-RESP)
END-EXEC
EXEC CICS RETURN END-EXEC.
Solution Walkthrough
State Machine via COMMAREA
The application's state machine is encoded in the CA-CURRENT-SCREEN field of the COMMAREA. When CICS restarts the program after user input, the first action is to read this field and route to the appropriate handler. The CA-PREV-SCREEN field enables backward navigation: pressing PF3 always takes the teller to the screen that was displayed before the current one.
This pattern eliminates the need for separate CICS programs for each screen. All four screens are managed by a single program, reducing inter-program communication overhead and simplifying deployment.
TSQ for Transaction History Paging
The account inquiry screen displays the last 100 transactions, ten per page. Loading all 100 rows into the COMMAREA would consume significant space and would be wasteful since the teller typically views only the first page. Instead, the program writes the query results to a Temporary Storage Queue (TSQ) and reads only the current page's rows on each display.
The TSQ name is built from the terminal ID ('AH' + EIBTRMID), ensuring uniqueness across concurrent users. The TSQ is deleted when the teller leaves the inquiry screen or ends the transaction.
RESP/RESP2 Error Handling
Every CICS API call includes RESP(WS-RESP) to capture the return code. The program never uses HANDLE CONDITION or HANDLE ABEND -- it uses the modern inline error checking pattern exclusively. This makes the error handling explicit and visible at each call site, avoiding the control flow complications of the older HANDLE approach.
Syncpoint for Transaction Integrity
The confirmation handler uses EXEC CICS SYNCPOINT after a successful DB2 update and EXEC CICS SYNCPOINT ROLLBACK if the update fails. For transfers, both the debit and credit updates must succeed as a unit -- the syncpoint commits both, and the rollback reverses both.
Discussion Questions
-
The COMMAREA is 300 bytes. If the application grows to include ten more screens with additional context data, the COMMAREA might exceed its practical limits. At what point would you recommend migrating from COMMAREA to channels and containers? What changes to the program structure would this require?
-
The TSQ-based paging pattern loads all 100 transaction history rows into the TSQ at once. For accounts with thousands of transactions, this could be slow. Design an alternative approach using DB2 cursor-based paging that fetches only one page of rows at a time. What are the trade-offs between the TSQ approach and the cursor approach?
-
The transfer operation updates two account balances in separate SQL statements. If the CICS region fails between the two updates (after debiting the source but before crediting the target), what happens? How does the two-phase commit protocol protect against this scenario?
-
The program uses a single transaction code (
ACMG) for all four screens. An alternative design would use separate transaction codes for each screen with XCTL for navigation. Compare the two approaches in terms of security (transaction-level authorization), performance, and maintainability. -
The current design does not handle concurrent access. If two tellers try to post transactions to the same account simultaneously, a lost update could occur. How would you implement optimistic or pessimistic locking to prevent this? Which approach is more appropriate for a CICS environment?