Add JavaSrc: cobol-tna-system COBOL->Java conversion (ZAN01-06/KIN01-09/KYU01-09 + 变换规则 doc)

This commit is contained in:
opencode
2026-08-29 20:50:08 +08:00
parent c9ea370397
commit f99f6696a6
71 changed files with 15350 additions and 0 deletions
+561
View File
@@ -0,0 +1,561 @@
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UncheckedIOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import dto.Kyu03Rec;
import dto.Kyu04Rec;
import dto.Kyu99Rec;
import dto.ZanendacPar;
import dto.ZanmsgacPar;
import util.ConvUtil;
/**
* ============================================================
* 【COBOL→Java】KYU05DED 控除計算処理
* ============================================================
* PROGRAM-ID. KYU05DED → 类 Kyu05DedMainPGMパターン:SELECT条件+DB参照)
*
* 使用ファイル(SELECT ASSIGN → パス定数):
* R01INNFIL(KYU05R01 入力 FB240B) → R01INN_FILECOPY KYU03REC → dto.Kyu03Rec
* W01OUTFIL(KYU05W01 出力 FB200B) → W01OUT_FILECOPY KYU04REC → dto.Kyu04Rec
* W02OUTFIL(KYU05W02 出力 VB200B) → W02OUT_FILECOPY KYU99REC → dto.Kyu99Rec 再利用)
* 使用DB2JDBC):
* TAX-TABLE SELECT ... WHERE :WRK-TAXABLE-INCOME BETWEEN TAX-FROM AND TAX-TO
* INSURANCE-TABLEDECLARE CURSOR → FETCH全件 → WORKING-STORAGE(INSURANCE-WORK) → SEARCH
* 使用SUBCALL → 类#execute):
* SUB02MSG→Sub02MsgSub / SUB03END→Sub03EndSub
* 段落对应:
* 0000MAJCOLSOR→run() 1000ITTSOR→initPara() 1100INSLOADSOR→insLoadPara()
* 1200R01INNSOR→readR01Para() 2000MAJSOR→majPara() 2100WRITOUTSOR→writeW01Para()
* 3000STPSOR→termPara() 4000MSGOUTSOR→msgOutPara() 9999ABDSOR→abendPara()
*
* 処理要点(詳細設計書_KYU05DED 準拠):
* - 課税所得=総支給-基礎控除(50000)。所得税=課税所得×税率-控除額(ROUNDED、負は0)。
* - 社会保険料=課税所得×(健康+厚生)比率(ROUNDED)。住民税=課税所得×0.10(ROUNDED)。
* - 差引支給額=総支給-所得税-保険料-住民税。
* - 金額計算は BigDecimal.setScale(0, HALF_UP) で COBOL ROUNDED を再現(转换基准 3.2)。
* - 原COBOLの CONNECT TO 'data/SALARY.db' は SQLite 指定だが、設計書は DB2 を規定。
* 转换基准「COBOLと式様書不一致は式様書優先」により DB2 URL を採用(報告書に注記)。
*/
public class Kyu05DedMain {
// ==================== コンスタント領域 CNSARA ====================
/** 03 CNS-PRGIDX PIC X(008) VALUE 'KYU05DED'. */
private static final String CST_PRGIDX = "KYU05DED";
/** 03 CNS-MSGSTR PIC 9(003) VALUE 001. 開始メッセージ */
private static final int CST_MSGSTR = 1;
/** 03 CNS-MSGFIN PIC 9(003) VALUE 002. 終了メッセージ */
private static final int CST_MSGFIN = 2;
/** 03 CNS-MSGSUBEEK PIC 9(003) VALUE 005.(設計上予約、本処理では未使用) */
private static final int CST_MSGSUBEEK = 5;
/** 03 CNS-MSGIINKES PIC 9(003) VALUE 006. 入力件数メッセージ */
private static final int CST_MSGIINKES = 6;
/** 03 CNS-MSGOUTKES PIC 9(003) VALUE 007. 出力件数メッセージ */
private static final int CST_MSGOUTKES = 7;
/** 03 CNS-MSGKEYINF PIC 9(003) VALUE 033. コンパイル日時メッセージ */
private static final int CST_MSGKEYINF = 33;
/** 03 CNS-KN0002 PIC 9(001) VALUE 2. */
private static final int CST_KN0002 = 2;
/** 03 CNS-ABD999 PIC 9(003) VALUE 999. */
private static final int CST_ABD999 = 999;
/** 03 CNS-TAX-BASIC-DEDUCTION PIC 9(006) VALUE 050000. 基礎控除 */
private static final long CST_TAX_BASIC_DEDUCTION = 50000L;
/** 03 CNS-RESIDENT-TAX-RATE PIC 9(001)V9(02) VALUE 0.10. 住民税率 */
private static final BigDecimal CST_RESIDENT_TAX_RATE = new BigDecimal("0.10");
/** 各SQL文の定数 */
private static final String INS_SELECT_SQL =
"SELECT \"INS-INCOME-FROM\", \"INS-INCOME-TO\", \"INS-HEALTH-RATE\", \"INS-PENSION-RATE\" "
+ "FROM \"INSURANCE-TABLE\" ORDER BY \"INS-INCOME-FROM\"";
private static final String TAX_SELECT_SQL =
"SELECT \"TAX-RATE\", \"DEDUCTION\" FROM \"TAX-TABLE\" WHERE ? BETWEEN \"TAX-FROM\" AND \"TAX-TO\"";
// ==================== ファイル定義(SELECT ASSIGN 相当) ====================
/** SELECT R01INNFIL ASSIGN TO KYU05R01.FB 入力 240B */
private static final String R01INN_FILE = "data/KYU05R01.txt";
/** SELECT W01OUTFIL ASSIGN TO KYU05W01.FB 出力 200B */
private static final String W01OUT_FILE = "data/KYU05W01.txt";
/** SELECT W02OUTFIL ASSIGN TO KYU05W02.VB 出力 200B */
private static final String W02OUT_FILE = "data/KYU05W02.txt";
// ==================== DB 接続(EXEC SQL CONNECT 相当) ====================
/** DB2 接続先(設計書準拠;原COBOLの 'data/SALARY.db' は SQLite 指定のため非採用。テスト時は -Dkyu.db.url で上書き)。 */
private static final String DB_URL = System.getProperty("kyu.db.url", "jdbc:db2://localhost:50000/TESTDB");
private static final String DB_USER = "db2inst1";
private static final String DB_PASS = "password";
// ==================== カウンタ領域 CUNARACOMP-3 → long ====================
/** 03 CUN-R01INN PIC S9(009) COMP-3 VALUE ZERO. */
private long cunR01Inn;
/** 03 CUN-W01OUT PIC S9(009) COMP-3 VALUE ZERO. */
private long cunW01Out;
/** 03 CUN-W02OUT PIC S9(009) COMP-3 VALUE ZERO. */
private long cunW02Out;
// ==================== 作業領域 WRKARA ====================
/** 03 WRK-EOF PIC X(001). 読込フラグ(88 WRK-EOF-Y VALUE '1' */
private String wrkEof = "0";
/** 03 WRK-GROSS-PAYMENT PIC 9(009). */
private long wrkGrossPayment;
/** 03 WRK-TAXABLE-INCOME PIC 9(009). */
private long wrkTaxableIncome;
/** 03 WRK-INCOME-TAX PIC 9(009). */
private long wrkIncomeTax;
/** 03 WRK-INSURANCE PIC 9(009). */
private long wrkInsurance;
/** 03 WRK-RESIDENT-TAX PIC 9(009). */
private long wrkResidentTax;
/** 03 WRK-NET-PAYMENT PIC 9(009). */
private long wrkNetPayment;
/** 88 WRK-EOF-Y VALUE '1'. */
private boolean isEof() {
return "1".equals(wrkEof);
}
// ==================== DB2 ホスト変数 DBVARA ====================
/** 03 DBV-EMP-ID PIC X(008).R01EMP-ID 設定、SQLでは未直接使用) */
private String dbvEmpId = "";
/** 03 DBV-TAX-RATE PIC 9(001)V9(04).TAX-TABLE.TAX-RATE DECIMAL(5,4) */
private BigDecimal dbvTaxRate = BigDecimal.ZERO;
/** 03 DBV-TAX-DEDUCTION PIC 9(009).TAX-TABLE.DEDUCTION DECIMAL(9,0) */
private long dbvTaxDeduction;
// ==================== 保険料率 WORKING-STORAGESEARCH 相当) ====================
/** 03 IW-COUNT PIC 9(004).OCCURS DEPENDING ON */
private int iwCount;
/** 最大 200 件(OCCURS 1 TO 200)。 */
private static final int IW_MAX = 200;
/** 05 IW-INCOME-FROM PIC 9(009). */
private final long[] iwIncomeFrom = new long[IW_MAX];
/** 05 IW-INCOME-TO PIC 9(009). */
private final long[] iwIncomeTo = new long[IW_MAX];
/** 05 IW-HEALTH-RATE PIC V9(006).0.xxxxxx、DECIMAL(7,6) 相当) */
private final BigDecimal[] iwHealthRate = new BigDecimal[IW_MAX];
/** 05 IW-PENSION-RATE PIC V9(006). */
private final BigDecimal[] iwPensionRate = new BigDecimal[IW_MAX];
// ==================== サブプログラム連絡領域(LINKAGE COPY → DTO ====================
/** COPY ZANMSGAC.SUB02MSG用) */
private final ZanmsgacPar m00MhoPar = new ZanmsgacPar();
/** COPY ZANENDAC.SUB03END用) */
private final ZanendacPar e01AbdPar = new ZanendacPar();
// ==================== レコード(FILE SECTION → DTO ====================
/** 01 R01INNREC.FD R01INNFIL / COPY KYU03REC */
private final Kyu03Rec r01 = new Kyu03Rec();
/** 01 W01OUTREC.FD W01OUTFIL / COPY KYU04REC */
private final Kyu04Rec w01 = new Kyu04Rec();
/** 01 W02OUTREC.FD W02OUTFIL / COPY KYU99REC 再利用) */
private final Kyu99Rec w02 = new Kyu99Rec();
// ==================== ファイルハンドル / DB接続(OPEN/CLOSE 相当) ====================
private BufferedReader r01InnFil;
private PrintWriter w01OutFil;
private PrintWriter w02OutFil;
private Connection conn;
/** 入力ファイルパス。デフォルトは SELECT ASSIGN 対応の R01INN_FILE。 */
private final String r01InnFile;
// ==================== PROCEDURE DIVISION ====================
public static void main(final String[] args) {
final String inputFile = (args != null && args.length > 0) ? args[0] : R01INN_FILE;
new Kyu05DedMain(inputFile).run();
}
public Kyu05DedMain() {
this(R01INN_FILE);
}
public Kyu05DedMain(final String r01InnFile) {
this.r01InnFile = r01InnFile;
}
/**
* 段落 0000MAJCOLSOR:制御処理。
* PERFORM 1000ITTSOR → PERFORM 2000MAJSOR UNTIL EOF → PERFORM 3000STPSOR → GOBACK.
*/
private void run() {
try {
initPara();
while (!isEof()) { // PERFORM 2000MAJSOR UNTIL WRK-EOF = '1'
majPara();
}
termPara();
// EXEC SQL COMMIT END-EXEC(正常終了時)
if (conn != null) {
conn.commit();
}
} catch (SQLException e) {
// EXEC SQL WHENEVER SQLERROR 相当(DbSample パターン)
System.out.println("[db] SQLERROR code=" + e.getErrorCode() + " msg=" + e.getMessage());
rollbackQuiet(conn);
abendPara(); // MOVE 999 TO E01ABDCOD / CALL SUB03ENDSystem.exit
} finally {
closeFiles();
closeQuiet(conn);
}
}
/**
* 段落 1000ITTSOR:初期処理。
* 開始メッセージ→コンパイル日時→ワーク初期化→DB接続→INSURANCE-TABLE LOAD→OPEN→初回READ.
*/
private void initPara() throws SQLException {
// *** 開始メッセージ出力
msgOutPara(CST_MSGSTR, null, null);
// *** コンパイル日時出力 ※FUNCTION WHEN-COMPILED→起動時刻で代用
final String compiled = java.time.LocalDateTime.now()
.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
msgOutPara(CST_MSGKEYINF, compiled, "COMPILED");
// *** ワークエリア初期化 INITIALIZE WRKARA.
cunR01Inn = 0;
cunW01Out = 0;
cunW02Out = 0;
wrkEof = "0";
wrkGrossPayment = 0;
wrkTaxableIncome = 0;
wrkIncomeTax = 0;
wrkInsurance = 0;
wrkResidentTax = 0;
wrkNetPayment = 0;
dbvEmpId = "";
dbvTaxRate = BigDecimal.ZERO;
dbvTaxDeduction = 0;
iwCount = 0;
// *** DB接続 EXEC SQL CONNECT TO 'data/SALARY.db'(設計書準拠で DB2 URL を使用)
conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
conn.setAutoCommit(false); // 批処理標準(DbSample パターン)
// *** 使用ファイル OPEN INPUT R01INNFIL / OUTPUT W01OUTFIL W02OUTFIL.
openFiles();
// *** INSURANCE-TABLE 全件 LOAD1100INSLOADSOR
insLoadPara();
// *** 初回 READ1200R01INNSOR
readR01Para();
}
/**
* 段落 1100INSLOADSORINSURANCE-TABLE 全件 LOAD 処理。
* DECLARE/OPEN CURSOR → FETCH ループ → INSURANCE-WORK 配列へ格納 → CLOSE CURSOR.
* OPEN/FETCH 異常(SQLCODE NOT = 0)時は W02 に詳細を書き ABEND.
*/
private void insLoadPara() {
try {
// EXEC SQL DECLARE INS-CURSOR CURSOR FOR ... / OPEN は executeQuery で暗黙実行
try (PreparedStatement ps = conn.prepareStatement(INS_SELECT_SQL);
ResultSet rs = ps.executeQuery()) { // OPEN INS-CURSOR
// PERFORM UNTIL SQLCODE NOT = 0rs.next() == false で終了)
while (rs.next()) {
iwCount++; // ADD 1 TO IW-COUNT
final int idx = iwCount - 1; // 1-based → 0-based
// MOVE DBV-INS-* TO IW-*OW 配列へ格納)
iwIncomeFrom[idx] = rs.getLong("INS-INCOME-FROM");
iwIncomeTo[idx] = rs.getLong("INS-INCOME-TO");
// DECIMAL(7,6) → scale 6PIC V9(006) 相当)
iwHealthRate[idx] = rs.getBigDecimal("INS-HEALTH-RATE");
iwPensionRate[idx] = rs.getBigDecimal("INS-PENSION-RATE");
}
} // CLOSE INS-CURSOR(自動)
} catch (SQLException e) {
// IF SQLCODE NOT = 0 → MOVE 'INS-CURSOR OPEN ERR' TO W02ERR-DETAIL / PERFORM 9999ABDSOR
w02.reset();
w02.setErrDetail("INS-CURSOR OPEN ERR");
writeW02();
abendPara();
}
}
/**
* 段落 1200R01INNSORR01 読込処理。
* READ AT END → SET WRK-EOF-Y / NOT AT END → ADD 1 TO CUN-R01INN.
*/
private void readR01Para() {
try {
final String line = r01InnFil.readLine();
if (line == null) {
// AT END: SET WRK-EOF-Y TO TRUE.
wrkEof = "1";
} else {
// NOT AT END: MOVE R01INNREC … / ADD 1 TO CUN-R01INN.
r01.setRecordLine(line);
cunR01Inn++;
}
} catch (IOException e) {
throw new UncheckedIOException(e); // READ異常 ≈ ABEND
}
}
/**
* 段落 2000MAJSOR:主処理。
* 課税所得→所得税(SELECT BETWEEN)→社会保険料(SEARCH)→住民税→差引支給額→W01出力→次READ.
*/
private void majPara() {
// MOVE R01GROSS-PAYMENT TO WRK-GROSS-PAYMENT.
wrkGrossPayment = r01.getGrossPayment();
// MOVE R01EMP-ID TO DBV-EMP-ID.
dbvEmpId = r01.getEmpId();
// *** 課税所得計算(IF WRK-GROSS-PAYMENT < CNS-TAX-BASIC-DEDUCTION …)
if (wrkGrossPayment < CST_TAX_BASIC_DEDUCTION) {
// MOVE ZERO TO WRK-TAXABLE-INCOME.
wrkTaxableIncome = 0;
} else {
// COMPUTE WRK-TAXABLE-INCOME = WRK-GROSS-PAYMENT - CNS-TAX-BASIC-DEDUCTION.
wrkTaxableIncome = wrkGrossPayment - CST_TAX_BASIC_DEDUCTION;
}
// *** TAX-TABLE 参照(SELECT ... BETWEEN)→ 所得税計算
taxSelectPara();
// *** 社会保険料計算(SEARCH IW-ENTRY
insSearchPara();
// *** 住民税計算 COMPUTE WRK-RESIDENT-TAX ROUNDED = 課税所得 × 0.10.
BigDecimal resident = BigDecimal.valueOf(wrkTaxableIncome)
.multiply(CST_RESIDENT_TAX_RATE)
.setScale(0, RoundingMode.HALF_UP);
wrkResidentTax = resident.longValue();
// *** 差引支給額 COMPUTE WRK-NET-PAYMENT = 総支給 - 所得税 - 保険料 - 住民税.
wrkNetPayment = wrkGrossPayment - wrkIncomeTax - wrkInsurance - wrkResidentTax;
// *** W01 出力(2100WRITOUTSOR
writeW01Para();
// *** 次レコード読込(1200R01INNSOR
readR01Para();
}
/**
* 段落 2000MAJSOR 内:DB2 TAX-TABLE 税率取得(EXEC SQL SELECT ... BETWEEN)。
* SQLCODE = 0 の場合のみ所得税を計算(負数は 0 に補正)、それ以外は 0.
*/
private void taxSelectPara() {
wrkIncomeTax = 0; // 既定(SQLCODE NOT = 0 / エラー時は 0
try (PreparedStatement ps = conn.prepareStatement(TAX_SELECT_SQL)) {
// WHERE :WRK-TAXABLE-INCOME BETWEEN TAX-FROM AND TAX-TO
ps.setLong(1, wrkTaxableIncome);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) { // IF SQLCODE = 0
// INTO :DBV-TAX-RATE, :DBV-TAX-DEDUCTION
dbvTaxRate = rs.getBigDecimal("TAX-RATE"); // DECIMAL(5,4)
dbvTaxDeduction = rs.getLong("DEDUCTION"); // DECIMAL(9,0)
// COMPUTE WRK-INCOME-TAX ROUNDED = 課税所得 × 税率 - 控除額.
BigDecimal incomeTax = BigDecimal.valueOf(wrkTaxableIncome)
.multiply(dbvTaxRate)
.subtract(BigDecimal.valueOf(dbvTaxDeduction))
.setScale(0, RoundingMode.HALF_UP);
long it = incomeTax.longValue();
if (it < 0) {
it = 0; // IF WRK-INCOME-TAX < ZERO → MOVE ZERO.
}
wrkIncomeTax = it;
}
// ELSESQLCODE NOT = 0)→ WRK-INCOME-TAX は 0 のまま
}
} catch (SQLException e) {
// SQLCODE NOT = 0(実エラー含む)→ WRK-INCOME-TAX = 0COBOL の ELSE 分岐と同義)
wrkIncomeTax = 0;
}
}
/**
* 段落 2000MAJSOR 内:社会保険料計算(SEARCH IW-ENTRY)。
* 条件:IW-INCOME-FROM(idx) ≦ 課税所得 AND 課税所得 ≦ IW-INCOME-TO(idx)
* AT END → WRK-INSURANCE = 0.
*/
private void insSearchPara() {
boolean found = false;
// SET IW-IDX TO 1 からの SEARCH(順次スキャン:COBOL SEARCH IW-ENTRY 相当)
for (int i = 0; i < iwCount; i++) {
if (iwIncomeFrom[i] <= wrkTaxableIncome && wrkTaxableIncome <= iwIncomeTo[i]) {
// COMPUTE WRK-INSURANCE ROUNDED = 課税所得 × (健康比率 + 厚生比率).
final BigDecimal sum = iwHealthRate[i].add(iwPensionRate[i]); // 双方 scale 6
BigDecimal insurance = BigDecimal.valueOf(wrkTaxableIncome)
.multiply(sum)
.setScale(0, RoundingMode.HALF_UP);
wrkInsurance = insurance.longValue();
found = true;
break;
}
}
if (!found) {
wrkInsurance = 0; // AT END: MOVE ZERO TO WRK-INSURANCE.
}
}
/**
* 段落 2100WRITOUTSORSALARY-NET 出力処理。
* MOVE 各項目 → W01OUTRECWRITE W01OUTRECADD 1 TO CUN-W01OUT.
*/
private void writeW01Para() {
w01.reset();
// MOVE R01EMP-ID TO W01EMP-ID.
w01.setEmpId(r01.getEmpId());
// MOVE 'S' TO W01REC-TYPE.
w01.setRecType("S");
// MOVE R01EMP-NAME TO W01EMP-NAME.
w01.setEmpName(r01.getEmpName());
// MOVE R01DEPT-CODE TO W01DEPT-CODE.
w01.setDeptCode(r01.getDeptCode());
// MOVE R01BASE-SALARY TO W01GROSS-PAYMENT.(設計書:設定元 R01BASE-SALARY
w01.setGrossPayment(r01.getBaseSalary());
// MOVE WRK-INCOME-TAX TO W01INCOME-TAX.
w01.setIncomeTax(wrkIncomeTax);
// MOVE WRK-INSURANCE TO W01INSURANCE.
w01.setInsurance(wrkInsurance);
// MOVE WRK-RESIDENT-TAX TO W01RESIDENT-TAX.
w01.setResidentTax(wrkResidentTax);
// MOVE WRK-NET-PAYMENT TO W01NET-PAYMENT.
w01.setNetPayment(wrkNetPayment);
// MOVE WRK-TAXABLE-INCOME TO W01TAXABLE-INCOME.
w01.setTaxableIncome(wrkTaxableIncome);
// MOVE WRK-NET-PAYMENT TO W01PAY-AMOUNT.
w01.setPayAmount(wrkNetPayment);
writeW01();
}
/**
* 段落 3000STPSOR:終了処理。
* CLOSE → 入出力件数メッセージ×3 → 終了メッセージ.
*/
private void termPara() {
closeFiles();
msgOutPara(CST_MSGIINKES, "KYU05R01", ConvUtil.padLeftZero(cunR01Inn, 9));
msgOutPara(CST_MSGOUTKES, "KYU05W01", ConvUtil.padLeftZero(cunW01Out, 9));
msgOutPara(CST_MSGOUTKES, "KYU05W02", ConvUtil.padLeftZero(cunW02Out, 9));
msgOutPara(CST_MSGFIN, null, null);
}
/**
* 段落 4000MSGOUTSOR:メッセージ編集出力処理。
* M00UMKDATS22-03(1:1)/-04(1:1) に '2'、-05 にプログラムIDを設定し SUB02MSG を呼ぶ。
*/
private void msgOutPara(final int msgCod, final String p1, final String p2) {
m00MhoPar.reset();
m00MhoPar.setM00MsgCod(msgCod);
if (p1 != null) {
m00MhoPar.setM00Umkdats2201(p1);
}
if (p2 != null) {
m00MhoPar.setM00Umkdats2202(p2);
}
m00MhoPar.setM00Umkdats2203(ConvUtil.padRight(Integer.toString(CST_KN0002), 30));
m00MhoPar.setM00Umkdats2204(ConvUtil.padRight(Integer.toString(CST_KN0002), 30));
m00MhoPar.setM00Umkdats2205(CST_PRGIDX);
Sub02MsgSub.execute(m00MhoPar);
}
/**
* 段落 9999ABDSORABEND 処理。
* MOVE 999 TO E01ABDCOD.CALL 'SUB03END' USING E01ABDPAR.
*/
private void abendPara() {
e01AbdPar.reset();
e01AbdPar.setE01AbdCod(CST_ABD999);
Sub03EndSub.execute(e01AbdPar);
}
// ==================== ファイル操作補助(OPEN/CLOSE/WRITE 相当) ====================
/** OPEN INPUT R01INNFIL / OUTPUT W01OUTFIL W02OUTFIL. */
private void openFiles() {
try {
r01InnFil = new BufferedReader(
new InputStreamReader(new FileInputStream(r01InnFile), StandardCharsets.UTF_8));
w01OutFil = new PrintWriter(
new OutputStreamWriter(new FileOutputStream(W01OUT_FILE), StandardCharsets.UTF_8));
w02OutFil = new PrintWriter(
new OutputStreamWriter(new FileOutputStream(W02OUT_FILE), StandardCharsets.UTF_8));
} catch (IOException e) {
throw new UncheckedIOException(e); // OPEN失敗 ≈ ABEND
}
}
/** WRITE W01OUTREC.ADD 1 TO CUN-W01OUT. */
private void writeW01() {
w01OutFil.println(w01.toRecordLine());
cunW01Out++;
}
/** WRITE W02OUTREC.ADD 1 TO CUN-W02OUT. */
private void writeW02() {
w02OutFil.println(w02.toRecordLine());
cunW02Out++;
}
/** CLOSE R01INNFIL W01OUTFIL W02OUTFIL. */
private void closeFiles() {
closeQuiet(r01InnFil);
closeQuiet(w01OutFil);
closeQuiet(w02OutFil);
r01InnFil = null;
w01OutFil = null;
w02OutFil = null;
}
private static void closeQuiet(final Object handle) {
try {
if (handle instanceof BufferedReader) {
((BufferedReader) handle).close();
} else if (handle instanceof PrintWriter) {
((PrintWriter) handle).close();
}
} catch (IOException e) {
// CLOSE異常は無視(原程序も FILE STATUS 未管理)
}
}
/** EXEC SQL ROLLBACK END-EXEC(異常時) */
private static void rollbackQuiet(final Connection c) {
if (c != null) {
try {
c.rollback();
System.out.println("[db] ROLLBACK DONE");
} catch (SQLException e) {
System.out.println("[db] ROLLBACK FAILED: " + e.getMessage());
}
}
}
private static void closeQuiet(final Connection c) {
if (c != null) {
try {
c.close();
} catch (SQLException e) {
System.out.println("[db] CLOSE FAILED: " + e.getMessage());
}
}
}
}