feat: Java 17+ rewrite of CBACT01C batch program with system analysis - #219
devin-ai-integration[bot] wants to merge 3 commits into
Conversation
- Add docs/SYSTEM_ANALYSIS.md with full business logic, data structure, I/O, dependency, and edge-case analysis of CBACT01C.cbl - Add java-app Maven project (Java 17, JUnit 5) implementing the batch account file processor with equivalent behavior - 21 JUnit tests covering end-to-end flow, transformation rules, date conversion, output formats, and error handling
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
| private static String formatDecimal(BigDecimal val) { | ||
| boolean negative = val.signum() < 0; | ||
| BigDecimal abs = val.abs(); | ||
| long unscaled = abs.movePointRight(2).longValue(); | ||
| String digits = String.format("%012d", unscaled); | ||
| return (negative ? "-" : "+") + digits; | ||
| } |
There was a problem hiding this comment.
🚩 Output record sizes differ from COBOL due to text-based sign representation
The formatDecimal method in OutAccountRecord.java:36-42, ArrayAccountRecord.java:28-34, and VbrRecord2.java:22-28 all produce 13-character strings (sign + 12 digits). In COBOL, PIC S9(10)V99 DISPLAY is 12 bytes (sign overpunched in last digit), and COMP-3 is 7 bytes (packed decimal). This means Java output record sizes differ from COBOL: e.g., VBR-REC2 is 41 chars in Java vs 39 bytes in COBOL, and ARR-ARRAY-REC is 145 chars vs 110 bytes. The test at line 407 validates the 145-char Java length. This is a consistent design choice for text-based output, but downstream consumers expecting COBOL-compatible fixed-width records will need to account for the different field widths.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Acknowledged. The 13-char format (explicit sign char + 12 digits) is a deliberate choice for the Java text-based output -- COBOL's overpunched signs and COMP-3 packed decimal don't have direct text equivalents. Downstream consumers expecting COBOL-compatible fixed-width records would need a binary serialization layer. For now this is documented in docs/SYSTEM_ANALYSIS.md (section 3.3, noting COMP-3 usage on OUT-ACCT-CURR-CYC-DEBIT).
The output switch cases were swapped: YYYYMMDD produced YYYY-MM-DD and vice versa (inherited from COBOL's inverted type-code semantics for input vs output). Now each constant produces the format its name describes. Updated the caller in AccountFileProcessor and tests.
| public String toOutputLine() { | ||
| StringBuilder sb = new StringBuilder(); | ||
| sb.append(String.format("%011d", acctId)); | ||
| for (int i = 0; i < SLOT_COUNT; i++) { | ||
| sb.append(formatDecimal(balances[i])); | ||
| sb.append(formatDecimal(debits[i])); | ||
| } | ||
| sb.append(" "); // ARR-FILLER X(04) | ||
| return sb.toString(); | ||
| } |
There was a problem hiding this comment.
🚩 COMP-3 packed-decimal fields written as text, losing binary compatibility
In the original COBOL, OUT-ACCT-CURR-CYC-DEBIT (CBACT01C.cbl:67-68) and ARR-ACCT-CURR-CYC-DEBIT (CBACT01C.cbl:76-77) use USAGE IS COMP-3 (packed decimal, 7 bytes for S9(10)V99). The Java code writes these as the same text format as all other decimal fields (13-char sign+digits). This is a fundamental format change from binary to text. If any downstream system reads these output files expecting packed-decimal binary data, it would fail. This may be intentional for the modernization (text-only output), but it's not called out in the system analysis document.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Acknowledged -- this is the same design choice noted in the previous review round. The Java version intentionally uses text-based output (sign char + digits) rather than binary packed-decimal. This is a standard approach for modernization where downstream consumers are expected to be Java/text-based rather than mainframe-native. The COMP-3 usage in the original COBOL is already documented in docs/SYSTEM_ANALYSIS.md section 3.3.
…ignedDecimal
The parser now decodes trailing overpunch characters ({,A-I for positive;
},J-R for negative) used in the production data (app/data/ASCII/acctdata.txt).
Updated test helper to generate overpunch-encoded data matching the real format.
Added tests for production data line and negative overpunch values.
| VbrRecord1 vbr1 = populateVbrRecord1(account); | ||
| VbrRecord2 vbr2 = populateVbrRecord2(account); | ||
| writeRecord(vbrcWriter, vbr1.toOutputLine(), "VBRCFILE"); | ||
| writeRecord(vbrcWriter, vbr2.toOutputLine(), "VBRCFILE"); |
There was a problem hiding this comment.
🚩 COBOL VBRC file uses RECORDING MODE V (RDW headers); Java uses plain text lines
The COBOL VBRC-FILE declaration (CBACT01C.cbl:80-84) uses RECORDING MODE IS V with RECORD IS VARYING ... DEPENDING ON WS-RECD-LEN, meaning each physical record has a 4-byte Record Descriptor Word (RDW) prefix containing the record length. The Java implementation at AccountFileProcessor.java:86-87 writes plain text lines with newline delimiters. This is a fundamental format difference — the VB1 record is 12 bytes and VB2 is 39 bytes in COBOL, but in Java they are variable-length text lines. If the VBRC output needs to be consumed by programs expecting MVS variable-length record format, this won't work.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Acknowledged. Same design intent as the COMP-3 and record-size points from earlier rounds -- the Java version produces newline-delimited text output, not MVS binary VB format with RDW headers. This is the standard approach for a modernized Java application where downstream consumers are text/CSV-based rather than mainframe-native. If binary-compatible VB output is ever needed, a RecordDescriptorWord serialization layer could be added on top of the existing record models.
Summary
Rewrites the COBOL batch program
CBACT01C.cblas a Java 17+ application and adds a full system analysis document.What CBACT01C does: Reads the VSAM KSDS account master sequentially and fans each record out to three output files in different formats -- flat fixed-length (
OUTFILE), array-structured with 5OCCURSslots (ARRYFILE), and variable-length with two record layouts per account (VBRCFILE). Key transformations: date reformatting viaCOBDATFT(YYYY-MM-DD → YYYYMMDD), default-value substitution (ACCT-CURR-CYC-DEBIT == 0→2525.00), and hardcoded array slot population.New files:
docs/SYSTEM_ANALYSIS.md-- Documents business logic flow, CVACT01Y/CODATECN copybook-to-Java type mappings, I/O operations, external dependencies (COBDATFT, CEE3ABD), and all edge cases/error handling paths.java-app/-- Maven project (Java 17, JUnit 5) with:AccountFileProcessor-- main batch driver mirroring the COBOL procedure division paragraphsAccountRecord.parse()-- parses 300-byte fixed-length lines matching CVACT01Y layout, including COBOL zoned-decimal trailing overpunch decoding ({A-Ipositive,}J-Rnegative)DateConverter-- replaces the COBDATFT assembler program; constantsYYYYMMDD/YYYY_MM_DDmatch their names for both input and outputOutAccountRecord,ArrayAccountRecord,VbrRecord1,VbrRecord2-- Java records for each output formatLink to Devin session: https://partner-workshops.devinenterprise.com/sessions/fad0316aab00417e9dec4073c66150ae
Requested by: @bsmitches