001/*
002 * Copyright (c) 2017 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.fukurou.fileexec;
017
018import java.util.concurrent.ConcurrentMap;
019import java.util.concurrent.ConcurrentHashMap;
020import java.util.StringJoiner;
021import java.util.Arrays;
022import java.util.List;
023import java.nio.file.Path;
024
025import org.opengion.fukurou.util.StringUtil;
026
027/**
028 * AppliExec は、アプリケーションの実行を行う共通の処理クラスです。
029 *
030 *<pre>
031 *
032 * ここでは、GE72の処理IDに応じた方法で実行します。
033 *
034 *</pre>
035 *
036 * @og.rev 7.0.0.0 (2017/07/07) 新規作成
037 *
038 * @version  7.0
039 * @author   Kazuhiko Hasegawa
040 * @since    JDK1.8,
041 */
042public final class AppliExec {
043        private static final XLogger LOGGER= XLogger.getLogger( AppliExec.class.getSimpleName() );              // ログ出力
044
045        /** GE72 テーブルのカラム定義の enum */
046        public enum GE72 {
047//      public static enum GE72 {
048                /** GE72 テーブルから検索するカラム名 */
049//              RUNTYPE,RUNPG,CLMS,PARAMS,DBID,TABLE_NAME,SHT_NOS,FILE_ENC,SKIP_CNT ;
050                /** GE72 カラム */ EXECID,
051                /** GE72 カラム */ RUNTYPE,
052                /** GE72 カラム */ RUNPG,
053                /** GE72 カラム */ CLMS,
054                /** GE72 カラム */ PARAMS,
055                /** GE72 カラム */ DBID,
056                /** GE72 カラム */ TABLE_NAME,
057                /** GE72 カラム */ SHT_NOS,
058                /** GE72 カラム */ FILE_ENC,
059                /** GE72 カラム */ SKIP_CNT ;                      // 7.2.1.0 (2020/03/13) EXECID 追加
060
061                /** order by で、開始日時(ST_TIME)順に処理されるようにしておきます。 */
062                private static final String FROM_WHERE = " from GE72 where SYSTEM_ID=? and EXECID=? and FGJ='1'" ;              // 1件のみのはず
063
064                /** 列挙子のCSV形式文字列 のキャッシュ */
065                public static final String SELECT ;
066                static {
067                        final StringJoiner sj = new StringJoiner( "," , "select " , FROM_WHERE );
068                        Arrays.stream( values() ).forEachOrdered( v -> sj.add( v.name() ) );
069                        SELECT = sj.toString();
070                }
071
072                /** 列挙子の序数(カラムの並び順) */
073                public final int NO ;
074
075                /** private コンストラクター */
076                GE72() { NO = ordinal(); }
077//              private GE72() { NO = ordinal(); }
078        }               // 8.5.4.2 (2024/01/12) PMD 7.0.0 UnnecessarySemicolon
079
080        /** GE72()のユニークキーは、systemId + execId だが、GE70()のユニークキーは、systemId + rsrv_no */
081        private static final ConcurrentMap<String,AppliExec> APP_EXEC_MAP = new ConcurrentHashMap<>();
082
083        private final String[] ge72Data ;
084
085        private final RunExec runexec ;                 // これもキャッシュできますが、とりあえず動くまでは毎回作成します。
086
087        /**
088         * private コンストラクタ
089         *
090         * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
091         * @og.rev 8.5.5.1 (2024/02/29) switch式の使用
092         *
093         * @param       systemId        システムID
094         * @param       execId          処理ID
095         */
096        private AppliExec( final String systemId , final String execId ) {
097                LOGGER.debug( () -> "⑥ systemId=" + systemId + " , execId=" + execId );
098
099                final List<String[]> cmdRow = DBUtil.dbQuery( GE72.SELECT , systemId , execId );
100
101                if( cmdRow.isEmpty() ) {
102                        // MSG3001 = コマンドリストに、予約番号,取込ID,処理IDは必須です。[{0}]
103                        throw MsgUtil.throwException( "MSG3001" , "SYSTEM_ID=" + systemId + " , EXECID=" + execId );
104                }
105
106                ge72Data = cmdRow.get(0);               // 1件のみのはず
107                final String type = ge72Data[GE72.RUNTYPE.NO];
108
109                // 8.5.5.1 (2024/02/29) switch式の使用
110//              final String key ;
111//              switch( type ) {
112//                      case "0" : key = "NONE";        break;                  // なにもしない
113//                      case "1" : key = "DBIN";        break;                  // DB入力
114//      //              case "2" : key = "PLSQL";       break;                  // PL/SQLコール
115//                      case "3" : key = "BAT";         break;                  // BATファイルコール
116//      //              case "4" : key = "JSP";         break;                  // JSPファイルコール(URLコネクション)
117//                      default  : key = null;          break;                  // なにもしない(runTypeなしエラー)
118//              }
119                final String key = switch( type ) {
120                        case "0" -> "NONE";                     // なにもしない
121                        case "1" -> "DBIN";                     // DB入力
122        //              case "2" -> "PLSQL";            // PL/SQLコール
123                        case "3" -> "BAT";                      // BATファイルコール
124        //              case "4" -> "JSP";                      // JSPファイルコール(URLコネクション)
125                        default  -> null;                       // なにもしない(runTypeなしエラー)
126                };
127
128                if( key == null ) {
129                        // MSG3002 = RUNTYPEに対応するRunExec実装クラスがありません。[{0}]
130                        throw MsgUtil.throwException( "MSG3002" , "RUNTYPE=" + type + " , systemId=" + systemId + " , execId=" + execId );
131                }
132
133                runexec = (RunExec)StringUtil.newInstance( "org.opengion.fukurou.fileexec.RunExec_" + key );
134        }
135
136        /**
137         * システムIDと処理IDから、対応するAppliExecオブジェクトを返します。
138         *
139         * AppliExecオブジェクトを、動的に作成し、システムID + 予約番号 をキーにキャッシュします。
140         *
141         * 何らかの Exception が、throw された場合は、null を返します。
142         *
143         * @og.rev 7.2.1.0 (2020/03/13) APP_EXEC_MAPのキーを、systemId + rsrv_no に変更します。
144         *
145         * @param       systemId        システムID
146         * @param       rsrvNo          予約番号(文字列のまま扱います)
147         * @param       execId          処理ID
148         * @return      AppliDataオブジェクト(作成できなければ、null)
149         */
150//      public static AppliExec newInstance( final String systemId , final String execId ) {
151        public static AppliExec newInstance( final String systemId , final String rsrvNo , final String execId ) {
152//              final String mapKey = systemId + "_" + execId ;
153                final String mapKey = systemId + "_" + rsrvNo ;
154
155                return APP_EXEC_MAP.computeIfAbsent( mapKey , key -> new AppliExec( systemId,execId ) );
156        }
157
158        /**
159         * システムID + 予約番号 をキーにキャッシュからAppliExecオブジェクトを削除します。
160         *
161         * 新しい AppliExecオブジェクトを作成する際に、GE72 を再読み込みします。
162         * 何か定義変更を行った後、読み取りスレッドを停止すると同時に、キャッシュを削除すれば、
163         * 次回起動時には、DBの設定を再読み込みします。
164         *
165         * @og.rev 7.2.1.0 (2020/03/13) APP_EXEC_MAPのキーを、systemId + rsrv_no に変更します。
166         *
167         * @param       systemId        システムID
168         * @param       rsrvNo          予約番号(文字列のまま扱います)
169         */
170        public static void removeInstance( final String systemId , final String rsrvNo ) {
171                final String mapKey = systemId + "_" + rsrvNo ;
172
173                APP_EXEC_MAP.remove( mapKey );
174        }
175
176        /**
177         * GE72.RUNTYPE に基づいて、各種処理を実行します。
178         *
179         * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
180         *
181         * @param       path 処理するファイルパス
182         * @return      処理件数(正は成功、マイナスは異常時の行番号)
183         */
184        public int exec( final Path path ) {
185                return runexec.exec( path,ge72Data ) ;
186        }
187
188        /**
189         * GE72.RUNTYPE に基づいて、各種処理を実行します。
190         *
191         * @og.rev 7.2.1.0 (2020/03/13) 新規追加
192         *
193         * @param       path 処理するファイルパス
194         * @param       fgtkan 取込完了フラグ(0:取込なし , 1:処理中 , 2:済 , 7:デーモンエラー , 8:アプリエラー)
195         * @param       errMsg エラーメッセージ
196         */
197        public void endExec( final Path path , final String fgtkan , final String errMsg ) {
198                runexec.endExec( path,ge72Data,fgtkan,errMsg ) ;
199        }
200}