Add JavaSrc: cobol-tna-system COBOL->Java conversion (ZAN01-06/KIN01-09/KYU01-09 + 变换规则 doc)
This commit is contained in:
@@ -0,0 +1,417 @@
|
||||
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.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import dto.Kin02Rec;
|
||||
import dto.ZandatacPar;
|
||||
import dto.ZanendacPar;
|
||||
import dto.ZanmsgacPar;
|
||||
import util.ConvUtil;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 【COBOL→Java】KIN03EXP 休暇日別展開処理
|
||||
* ============================================================
|
||||
* PROGRAM-ID. KIN03EXP → 类 Kin03ExpMain(PGMパターン:キーブレイク集計)
|
||||
*
|
||||
* 使用DB(SQLite: data/kin.db):
|
||||
* C1: LEAVE_RECORDS(STATUS='1') → 日別展開元
|
||||
* C2: HOLIDAY_CALENDAR → 休日テーブル
|
||||
* 使用文件(SELECT ASSIGN → 路径常量):
|
||||
* W01OUTFIL(KIN02W01.DAT LEAVE-DAILY F80B) → W01OUT_FILE(COPY KIN02REC → dto.Kin02Rec)
|
||||
* 使用SUB(CALL → 类#execute):
|
||||
* SUB01DAT→Sub01DatSub / SUB02MSG→Sub02MsgSub / SUB03END→Sub03EndSub
|
||||
* 段落对应:
|
||||
* 0000MAJCOLSOR→run() 1000ITTSOR→initPara() 1100C1INITSOR→initC1()
|
||||
* 1100C1FETCHSOR→fetchC1() 1200HDINNSOR→loadHolidays() 2000MAJSOR→majPara()
|
||||
* 2100-PROCESS-EMP→majPara内 2200-EXPAND-DATE→expandDate() 2300-DATE-ADD-1→LocalDate.plusDays
|
||||
* 3000STPSOR→termPara() 4000MSGOUTSOR→msgOutPara() 9999ABDSOR→abendPara()
|
||||
*
|
||||
* ※COBOLはカーソル/SQLエラーを EOF 扱い(ABENDしない)。ABENDは SUB01DAT失敗・W01 OPEN失敗のみ。
|
||||
* ※INTEGER-OF-DATE/MOD 7 の曜日判定は Java LocalDate.getDayOfWeek() に読替(土日=週末除外、意味等価)。
|
||||
* ※SEARCH ALL(ASC KEY) は TreeSet.contains に読替(昇順ロード維持、結果等価)。
|
||||
* ※2300-DATE-ADD-1 の月末/閏年計算は LocalDate.plusDays(1) に読替(意味等価)。
|
||||
*/
|
||||
public class Kin03ExpMain {
|
||||
|
||||
// ==================== コンスタント領域 CNSARA ====================
|
||||
|
||||
private static final String CST_PRGIDX = "KIN03EXP";
|
||||
private static final int CST_MSGSTR = 1;
|
||||
private static final int CST_MSGFIN = 2;
|
||||
private static final int CST_MSGSUBEEK = 5;
|
||||
private static final int CST_MSGIINKES = 6;
|
||||
private static final int CST_MSGOUTKES = 7;
|
||||
private static final int CST_MSGKEYINF = 33;
|
||||
private static final int CST_KN0002 = 2;
|
||||
private static final int CST_ABD999 = 999;
|
||||
|
||||
// ==================== ファイル・DB定義 ====================
|
||||
|
||||
/** SELECT W01OUTFIL ASSIGN TO "KIN02W01.DAT". */
|
||||
private static final String W01OUT_FILE = "data/KIN02W01.DAT";
|
||||
/** EXEC SQL CONNECT TO 'data/kin.db'. */
|
||||
private static final String DB_URL = "jdbc:sqlite:data/kin.db";
|
||||
|
||||
private static final DateTimeFormatter YMD = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
// ==================== カウンタ領域 ====================
|
||||
|
||||
private long cunR01Inn;
|
||||
private long cunW01Out;
|
||||
|
||||
// ==================== 作業領域 ====================
|
||||
|
||||
private String wrkR01Eof = "0";
|
||||
/** 03 WRK-BFR-EMP-ID PIC X(008). キーブレイク用 */
|
||||
private String wrkBfrEmpId = "";
|
||||
/** 03 CUN-EMP-SUB PIC S9(009) COMP-3. 社員別小計 */
|
||||
private long empSub;
|
||||
/** 直近SQLCODE(デバッグ用、ABEND非対象) */
|
||||
private int sqlcode;
|
||||
|
||||
// ==================== DBホスト変数(C1 FETCH 結果) ====================
|
||||
|
||||
private int sqlApplId;
|
||||
private String sqlEmpId = "";
|
||||
private String sqlLeaveType = "";
|
||||
private String sqlStartDate = "";
|
||||
private String sqlStartTime = "";
|
||||
private String sqlEndDate = "";
|
||||
private String sqlEndTime = "";
|
||||
|
||||
// ==================== 休日テーブル ====================
|
||||
|
||||
/** WRK-HOLIDAY-TABLE(OCCURS 1 TO 366, ASCENDING KEY)。SEARCH ALL → TreeSet。 */
|
||||
private final TreeSet<String> hdSet = new TreeSet<String>();
|
||||
/** 03 WRK-HD-COUNT PIC 9(004). */
|
||||
private int hdCount;
|
||||
|
||||
// ==================== サブプログラム連絡領域 ====================
|
||||
|
||||
private final ZandatacPar d01UbsPar = new ZandatacPar();
|
||||
private final ZanmsgacPar m00MhoPar = new ZanmsgacPar();
|
||||
private final ZanendacPar e01AbdPar = new ZanendacPar();
|
||||
|
||||
// ==================== 入出力レコード ====================
|
||||
|
||||
/** 01 W01OUTREC.(FD W01OUTFIL)COPY KIN02REC → W01 */
|
||||
private final Kin02Rec w01 = new Kin02Rec();
|
||||
|
||||
// ==================== ハンドル ====================
|
||||
|
||||
private Connection conn;
|
||||
private PreparedStatement psC1;
|
||||
private ResultSet rsC1;
|
||||
private PreparedStatement psC2;
|
||||
private ResultSet rsC2;
|
||||
private PrintWriter w01OutFil;
|
||||
|
||||
// ==================== PROCEDURE DIVISION ====================
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Kin03ExpMain().run();
|
||||
}
|
||||
|
||||
private void run() {
|
||||
try {
|
||||
initPara();
|
||||
while (!"1".equals(wrkR01Eof)) { // PERFORM 2000MAJSOR UNTIL WRK-R01EOF='1'
|
||||
majPara();
|
||||
}
|
||||
termPara();
|
||||
} finally {
|
||||
closeAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 段落 1000ITTSOR:初期処理。
|
||||
* 開始/コンパイル時刻→WRK初期化→DB接続→運用日付→休日読込→W01 OPEN→C1初回FETCH。
|
||||
*/
|
||||
private void initPara() {
|
||||
msgOutPara(CST_MSGSTR, null, null);
|
||||
|
||||
String compiled = java.time.LocalDateTime.now()
|
||||
.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||||
msgOutPara(CST_MSGKEYINF, compiled, "COMPILED");
|
||||
|
||||
resetWork();
|
||||
|
||||
// DB接続(失敗時は conn=null → 以降のカーソルが EOF 扱い、ABENDしない)
|
||||
try {
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
conn = DriverManager.getConnection(DB_URL);
|
||||
conn.setAutoCommit(false);
|
||||
} catch (ClassNotFoundException | SQLException e) {
|
||||
conn = null; // COBOL同様、CONNECT/カーソル失敗は EOF として処理
|
||||
}
|
||||
|
||||
// 運用日付取得 CALL 'SUB01DAT'
|
||||
d01UbsPar.reset();
|
||||
Sub01DatSub.execute(d01UbsPar);
|
||||
if (d01UbsPar.getD01FkiCod() != 0) {
|
||||
// IF D01FKICOD NOT = ZERO → メッセージ + ABEND(999)
|
||||
msgOutPara(CST_MSGSUBEEK, "SUB01DAT",
|
||||
ConvUtil.padLeftZero(d01UbsPar.getD01FkiCod(), 4));
|
||||
abendPara();
|
||||
}
|
||||
|
||||
loadHolidays(); // C2: HOLIDAY_CALENDAR 全件ロード
|
||||
openW01(); // W01 OPEN(失敗時は ABEND)
|
||||
initC1(); // C1 DECLARE/OPEN/初回FETCH
|
||||
}
|
||||
|
||||
private void resetWork() {
|
||||
cunR01Inn = 0;
|
||||
cunW01Out = 0;
|
||||
wrkBfrEmpId = "";
|
||||
empSub = 0;
|
||||
sqlcode = 0;
|
||||
hdCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 段落 1200HDINNSOR:C2 HOLIDAY_CALENDAR 読込。
|
||||
* PERFORM UNTIL SQLCODE NOT = 0 → WRK-HD-COUNT++、WRK-HD-DATE格納。
|
||||
* エラー時は件数0(COBOLはループ終了のみ)。
|
||||
*/
|
||||
private void loadHolidays() {
|
||||
if (conn == null) {
|
||||
return;
|
||||
}
|
||||
try (PreparedStatement ps = conn.prepareStatement(
|
||||
"SELECT HOLIDAY_DATE FROM HOLIDAY_CALENDAR ORDER BY HOLIDAY_DATE")) {
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
hdSet.add(rs.getString("HOLIDAY_DATE"));
|
||||
hdCount++;
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// エラー時は取得済み分まで(COBOLは PERFORM UNTIL SQLCODE NOT=0 で終了)
|
||||
sqlcode = e.getErrorCode();
|
||||
}
|
||||
}
|
||||
|
||||
/** W01 OPEN(FILE STATUS 異常時は ABEND 999)。 */
|
||||
private void openW01() {
|
||||
try {
|
||||
w01OutFil = new PrintWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(W01OUT_FILE), "UTF-8"), true);
|
||||
} catch (IOException e) {
|
||||
abendPara(); // IF WS-W01-STATUS NOT = '00' → ABEND
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 段落 1100C1INITSOR:C1 DECLARE/OPEN/初回FETCH。
|
||||
* SQLCODE=0 → CUN-R01INN++、 ELSE → WRK-R01EOF='1'。
|
||||
*/
|
||||
private void initC1() {
|
||||
if (conn == null) {
|
||||
wrkR01Eof = "1";
|
||||
return;
|
||||
}
|
||||
try {
|
||||
psC1 = conn.prepareStatement(
|
||||
"SELECT APPLICATION_ID, EMP_ID, LEAVE_TYPE, START_DATE, "
|
||||
+ " START_TIME, END_DATE, END_TIME"
|
||||
+ " FROM LEAVE_RECORDS WHERE STATUS = '1'"
|
||||
+ " ORDER BY EMP_ID, START_DATE");
|
||||
rsC1 = psC1.executeQuery();
|
||||
fetchC1();
|
||||
} catch (SQLException e) {
|
||||
sqlcode = e.getErrorCode();
|
||||
wrkR01Eof = "1"; // カーソルエラーは EOF 扱い
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 段落 1100C1FETCHSOR / 1100C1INITSOR 内 FETCH。
|
||||
* SQLCODE=0 → ホスト変数格納 + CUN-R01INN++、 ELSE → WRK-R01EOF='1'。
|
||||
*/
|
||||
private void fetchC1() {
|
||||
if (rsC1 == null) {
|
||||
wrkR01Eof = "1";
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (rsC1.next()) {
|
||||
sqlApplId = rsC1.getInt("APPLICATION_ID");
|
||||
sqlEmpId = rsC1.getString("EMP_ID");
|
||||
sqlLeaveType = rsC1.getString("LEAVE_TYPE");
|
||||
sqlStartDate = rsC1.getString("START_DATE");
|
||||
sqlStartTime = rsC1.getString("START_TIME");
|
||||
sqlEndDate = rsC1.getString("END_DATE");
|
||||
sqlEndTime = rsC1.getString("END_TIME");
|
||||
cunR01Inn++;
|
||||
} else {
|
||||
wrkR01Eof = "1";
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
sqlcode = e.getErrorCode();
|
||||
wrkR01Eof = "1"; // フェッチエラーは EOF 扱い(COBOL準拠)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 段落 2000MAJSOR:主処理(社員番号キーブレイク)。
|
||||
* SQL-EMP-ID→WRK-BFR-EMP-ID、1社員分処理(2100)→社員別小計出力。
|
||||
*/
|
||||
private void majPara() {
|
||||
wrkBfrEmpId = sqlEmpId; // キー保存
|
||||
empSub = 0; // CUN-EMP-SUB 初期化
|
||||
|
||||
// 2100-PROCESS-EMP:EOF またはキー変化までループ
|
||||
while (!"1".equals(wrkR01Eof) && sqlEmpId.equals(wrkBfrEmpId)) {
|
||||
expandDate(); // 2200-EXPAND-DATE
|
||||
fetchC1(); // 次レコード FETCH
|
||||
}
|
||||
|
||||
// 社員別小計出力(キーブレイク)
|
||||
msgOutPara(CST_MSGKEYINF, wrkBfrEmpId, Long.toString(empSub), "EMP SUB");
|
||||
}
|
||||
|
||||
/**
|
||||
* 段落 2200-EXPAND-DATE:開始日〜終了日を日別展開。
|
||||
* 週末(Sat/Sun)・休日を除外し、非週末かつ非休日で W01 出力。
|
||||
*/
|
||||
private void expandDate() {
|
||||
LocalDate cur;
|
||||
LocalDate end;
|
||||
try {
|
||||
cur = LocalDate.parse(sqlStartDate, YMD);
|
||||
end = LocalDate.parse(sqlEndDate, YMD);
|
||||
} catch (DateTimeParseException e) {
|
||||
return; // 日付解析不可は当該申請をスキップ(COBOLは 0/SPACE で CONTINUE 相当)
|
||||
}
|
||||
|
||||
while (!cur.isAfter(end)) {
|
||||
DayOfWeek dow = cur.getDayOfWeek();
|
||||
if (dow != DayOfWeek.SATURDAY && dow != DayOfWeek.SUNDAY) {
|
||||
// 非週末:休日テーブル検索
|
||||
String ymd = cur.format(YMD);
|
||||
if (!hdSet.contains(ymd)) {
|
||||
w01.reset();
|
||||
w01.setEmpId(wrkBfrEmpId); // MOVE WRK-BFR-EMP-ID
|
||||
w01.setDate(Integer.parseInt(ymd)); // MOVE WRK-DATE-ALPHA
|
||||
w01.setLeaveType(sqlLeaveType); // MOVE SQL-LEAVE-TYPE
|
||||
w01.setStartTime(Integer.parseInt(sqlStartTime)); // MOVE SQL-START-TIME
|
||||
w01.setEndTime(Integer.parseInt(sqlEndTime)); // MOVE SQL-END-TIME
|
||||
w01.setApplId(sqlApplId); // MOVE NUMVAL(SQL-APPL-ID)
|
||||
writeW01();
|
||||
empSub++;
|
||||
}
|
||||
}
|
||||
cur = cur.plusDays(1); // 2300-DATE-ADD-1(LocalDate が月末/閏年を処理)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 段落 3000STPSOR:終了処理。
|
||||
* CURSOR CLOSE→W01 CLOSE→件数メッセージ×3→終了メッセージ。
|
||||
*/
|
||||
private void termPara() {
|
||||
// *** 件数メッセージ出力
|
||||
msgOutPara(CST_MSGIINKES, "LEAVE_RECORDS", Long.toString(cunR01Inn));
|
||||
msgOutPara(CST_MSGOUTKES, "KIN02W01", Long.toString(cunW01Out));
|
||||
msgOutPara(CST_MSGKEYINF, "HOLIDAYS LOADED", Long.toString(hdCount));
|
||||
|
||||
// *** 終了メッセージ出力
|
||||
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) {
|
||||
msgOutPara(msgCod, p1, p2, null);
|
||||
}
|
||||
|
||||
private void msgOutPara(final int msgCod, final String p1, final String p2, final String p3) {
|
||||
m00MhoPar.reset();
|
||||
m00MhoPar.setM00MsgCod(msgCod);
|
||||
if (p1 != null) {
|
||||
m00MhoPar.setM00Umkdats2201(p1);
|
||||
}
|
||||
if (p2 != null) {
|
||||
m00MhoPar.setM00Umkdats2202(p2);
|
||||
}
|
||||
if (p3 != null) {
|
||||
m00MhoPar.setM00Umkdats2203(p3);
|
||||
}
|
||||
String p3cur = m00MhoPar.getM00Umkdats2203();
|
||||
String newP3 = (p3cur.length() == 0) ? ConvUtil.padRight(Integer.toString(CST_KN0002), 30)
|
||||
: ("2" + p3cur.substring(1));
|
||||
m00MhoPar.setM00Umkdats2203(newP3);
|
||||
m00MhoPar.setM00Umkdats2204(ConvUtil.padRight(Integer.toString(CST_KN0002), 30));
|
||||
m00MhoPar.setM00Umkdats2205(CST_PRGIDX);
|
||||
Sub02MsgSub.execute(m00MhoPar);
|
||||
}
|
||||
|
||||
/**
|
||||
* 段落 9999ABDSOR:ABEND処理(ABENDコード 999)。
|
||||
*/
|
||||
private void abendPara() {
|
||||
e01AbdPar.reset();
|
||||
e01AbdPar.setE01AbdCod(CST_ABD999);
|
||||
Sub03EndSub.execute(e01AbdPar); // System.exit(999)
|
||||
}
|
||||
|
||||
// ==================== ファイル操作補助 ====================
|
||||
|
||||
/** WRITE W01OUTREC./ADD 1 TO CUN-W01OUT. */
|
||||
private void writeW01() {
|
||||
w01OutFil.println(w01.toRecordLine());
|
||||
cunW01Out++;
|
||||
}
|
||||
|
||||
/** CURSOR / W01 / DB 接続のクローズ(finally からも呼ばれ、冪等)。 */
|
||||
private void closeAll() {
|
||||
closeQuiet(rsC1);
|
||||
closeQuiet(psC1);
|
||||
closeQuiet(rsC2);
|
||||
closeQuiet(psC2);
|
||||
closeQuiet(w01OutFil);
|
||||
closeQuiet(conn);
|
||||
rsC1 = null;
|
||||
psC1 = null;
|
||||
rsC2 = null;
|
||||
psC2 = null;
|
||||
w01OutFil = null;
|
||||
conn = null;
|
||||
}
|
||||
|
||||
private static void closeQuiet(final Object handle) {
|
||||
try {
|
||||
if (handle instanceof ResultSet) {
|
||||
((ResultSet) handle).close();
|
||||
} else if (handle instanceof PreparedStatement) {
|
||||
((PreparedStatement) handle).close();
|
||||
} else if (handle instanceof PrintWriter) {
|
||||
((PrintWriter) handle).close();
|
||||
} else if (handle instanceof Connection) {
|
||||
((Connection) handle).close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// CLOSE異常は無視
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user