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 → 类 Kyu05DedMain(PGMパターン:SELECT条件+DB参照) * * 使用ファイル(SELECT ASSIGN → パス定数): * R01INNFIL(KYU05R01 入力 FB240B) → R01INN_FILE(COPY KYU03REC → dto.Kyu03Rec) * W01OUTFIL(KYU05W01 出力 FB200B) → W01OUT_FILE(COPY KYU04REC → dto.Kyu04Rec) * W02OUTFIL(KYU05W02 出力 VB200B) → W02OUT_FILE(COPY KYU99REC → dto.Kyu99Rec 再利用) * 使用DB2(JDBC): * TAX-TABLE :SELECT ... WHERE :WRK-TAXABLE-INCOME BETWEEN TAX-FROM AND TAX-TO * INSURANCE-TABLE:DECLARE CURSOR → FETCH全件 → WORKING-STORAGE(INSURANCE-WORK) → SEARCH * 使用SUB(CALL → 类#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"; // ==================== カウンタ領域 CUNARA(COMP-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-STORAGE(SEARCH 相当) ==================== /** 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 SUB03END(System.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 全件 LOAD(1100INSLOADSOR) insLoadPara(); // *** 初回 READ(1200R01INNSOR) readR01Para(); } /** * 段落 1100INSLOADSOR:INSURANCE-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 = 0(rs.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 6(PIC 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(); } } /** * 段落 1200R01INNSOR:R01 読込処理。 * 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; } // ELSE(SQLCODE NOT = 0)→ WRK-INCOME-TAX は 0 のまま } } catch (SQLException e) { // SQLCODE NOT = 0(実エラー含む)→ WRK-INCOME-TAX = 0(COBOL の 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. } } /** * 段落 2100WRITOUTSOR:SALARY-NET 出力処理。 * MOVE 各項目 → W01OUTREC/WRITE W01OUTREC/ADD 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); } /** * 段落 9999ABDSOR:ABEND 処理。 * 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()); } } } }