Files
cobol-tna-system/JavaSrc/src/Kyu05DedMain.java
T

562 lines
23 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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());
}
}
}
}