    001/*
    002 * Copyright (c) 2009 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.hayabusa.report2;
    017
    018import java.util.ArrayList;
    019import java.util.Collections;
    020import java.util.List;
    021// import java.io.File;                                                                                         // 8.0.0.1 (2021/10/08)
    022
    023import org.opengion.fukurou.system.ThrowUtil ;                                          // 6.4.2.0 (2016/01/29)
    024import org.opengion.hayabusa.common.HybsSystem;
    025// import org.opengion.hayabusa.io.HybsFileOperationFactory;            // 8.0.1.0 (2021/10/29) ExecThread → ExecProcess
    026// import org.opengion.fukurou.model.FileOperation;                                     // 8.0.0.1 (2021/10/08)
    027// import org.opengion.fukurou.util.FileUtil;                                           // 8.0.0.1 (2021/10/08)
    028
    029// import static org.opengion.fukurou.system.HybsConst.CR ;                     // 6.1.0.0 (2014/12/26)
    030import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
    031
    032/**
    033 * 帳票要求ｽﾚｯﾄﾞの本体です｡
    034 * 外部からｽﾀｯｸされたｷｭｰを先入れ先出しの順番に処理します｡
    035 *
    036 * あるｷｭｰに対してｴﾗｰが発生すると､ｼｽﾃﾑﾘｿｰｽのRETRY_COUNTで設定された回数再処理を試みます｡
    037 * この回数分ｴﾗｰが発生した場合は､そのｷｭｰのみがｱﾌﾟﾘｴﾗｰとなります｡
    038 *
    039 * このｽﾚｯﾄﾞは一度生成されると､外部から明示的に終了の要求を起こさない限り生存し続けます｡
    040 * 終了するには､finish()ﾒｿｯﾄﾞを呼び出します｡
    041 * このﾒｿｯﾄﾞが呼ばれると､内部でｽﾀｯｸしているｷｭｰは全てｸﾘｱされるため､その時点で
    042 * 処理されているｷｭｰの処理が完了した時点で､ｽﾚｯﾄﾞが終了します｡
    043 *
    044 * @og.group 帳票ｼｽﾃﾑ
    045 *
    046 * @version  4.0
    047 * @author   Hiroki.Nakamura
    048 * @since    JDK1.6
    049 */
    050public class ExecThread extends Thread {
    051
    052        /** ｽﾃｰﾀｽの enum */
    053        private enum Status { EXECUTE, WAIT };
    054//      private static enum Status { EXECUTE, WAIT };
    055        private Status state = Status.EXECUTE;
    056
    057        private static final int RETRY_COUNT = HybsSystem.sysInt( "REPORT_RETRY_COUNT" );
    058
    059        private final List<ExecQueue> queues = Collections.synchronizedList( new ArrayList<>() );
    060
    061        private long threadStart        ;
    062        private long execStart          ;
    063        private long execEnd            ;
    064        private final boolean debug;    // 4.3.0.0 (2008/07/15) ﾃﾞﾊﾞｯｸﾞの追加
    065
    066        /**
    067         * ｺﾝｽﾄﾗｸﾀ
    068         * OOoへの接続を生成します｡
    069         *
    070         * @param       id      ｽﾚｯﾄﾞID
    071         */
    072        public ExecThread( final String id ) {
    073                // threadStart = System.currentTimeMillis();
    074                // setName( id ); // ｽﾀｯｸﾄﾚｰｽ時にｽﾚｯﾄﾞIDを出すためにｾｯﾄ
    075                this ( id , false );
    076        }
    077
    078        /**
    079         * ｺﾝｽﾄﾗｸﾀ
    080         * OOoへの接続を生成します｡
    081         *
    082         * @og.rev 4.3.0.0 (2008/07/15) ﾃﾞﾊﾞｯｸﾞﾌﾗｸﾞを追加します｡
    083         * @og.rev 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor
    084         *
    085         * @param       id                      ｽﾚｯﾄﾞID
    086         * @param       debugFlag       ﾃﾞﾊﾞｯｸﾞﾌﾗｸﾞ[true/false]
    087         */
    088        public ExecThread( final String id , final boolean debugFlag ) {
    089                super();
    090                threadStart = System.currentTimeMillis();
    091                setName( id );          // ｽﾀｯｸﾄﾚｰｽ時にｽﾚｯﾄﾞIDを出すためにｾｯﾄ
    092                debug = debugFlag;      // 4.2.5.0 (2008/06/26) ﾃﾞﾊﾞｯｸﾞ処理の追加
    093        }
    094
    095        /**
    096         * Map#compute で対応 出来るように､start() 実行後の 新規に作成した ExecThread を返します｡
    097         *
    098         * @og.rev 6.4.3.3 (2016/03/04) Map#compute で対応する｡
    099         *
    100         * @param       id                      ｽﾚｯﾄﾞID
    101         * @param       debugFlag       ﾃﾞﾊﾞｯｸﾞﾌﾗｸﾞ[true/false]
    102         * @return      startﾒｿｯﾄﾞ実行後の新規に作成したExecThreadｵﾌﾞｼﾞｪｸﾄ
    103         */
    104        public static final ExecThread startExecThread( final String id , final boolean debugFlag ) {
    105                final ExecThread oet = new ExecThread( id, debugFlag );
    106                oet.start();
    107                return oet;
    108        }
    109
    110        /**
    111         * ｷｭｰをｽﾀｯｸします｡
    112         *
    113         * @og.rev 4.3.0.0 (2008/07/15) debug追加
    114         * @param       queue   ExecQueueｵﾌﾞｼﾞｪｸﾄ
    115         *
    116         * @return      ｽﾀｯｸが受け付けられたかどうか
    117         */
    118        public boolean stackQueue( final ExecQueue queue ) {
    119                queue.addMsg( "[INFO]QUEUE STACK:THREAD-ID=" + queue.getThreadId() + ",YKNO=" + queue.getYkno() );
    120
    121                queues.add( queue );
    122
    123                queue.setExecute();
    124                if( debug ) { queue.addMsg( "[INFO]QUEUE STACKED" ); }
    125
    126                synchronized( this ) {
    127                        if( state == Status.WAIT ) {
    128                                this.interrupt();
    129                                if( debug ) { queue.addMsg( "[INFO]INTERRUPT" ); }
    130                        }
    131                }
    132                return true;
    133        }
    134
    135        /**
    136         * このｽﾚｯﾄﾞの実行を開始します｡Java仮想ﾏｼﾝは､このｽﾚｯﾄﾞのrunﾒｿｯﾄﾞを呼び出します｡
    137         *
    138         * ここでは､実行されたときのﾒｯｾｰｼﾞを表示するために､Override しています｡
    139         *
    140         * @og.rev 6.4.3.3 (2016/03/04) 処理ﾒｯｾｰｼﾞを表示します｡
    141         */
    142        @Override
    143        public void start() {
    144                System.out.println( "[INFO]THREAD CREATED:THREAD-ID=" + getName() );
    145                super.start();
    146        }
    147
    148        /**
    149         * ｽﾚｯﾄﾞ本体
    150         * ｽﾀｯｸされたｷｭｰを順番に取り出し処理を行います｡
    151         *
    152         * @og.rev 8.0.0.2 (2021/10/15) ﾛｰｶﾙﾌｧｲﾙとｸﾗｳﾄﾞﾌｧｲﾙ間の移動
    153         * @og.rev 8.0.1.0 (2021/10/29) ﾛｰｶﾙﾌｧｲﾙとｸﾗｳﾄﾞﾌｧｲﾙ間の移動は､ExecProcess#output(String...) で行う｡
    154         */
    155        @Override
    156        public void run() {
    157                while( true ) {
    158                        synchronized( this ) {
    159                                while( queues.isEmpty() ) {
    160                                        try {
    161                                                state = Status.WAIT;
    162                                                wait();
    163                                        }
    164                                        catch( final InterruptedException ex ) {
    165                                                state = Status.EXECUTE;
    166                                        }
    167                                }
    168                        }
    169
    170                        final ExecQueue queue = popQueue();
    171                        if( queue != null ) {
    172                                if( "_FINALIZE".equals( queue.getYkno() ) ) {
    173                                        if( debug ) { queue.addMsg( "[INFO]END" ); }
    174                                        break;
    175                                }
    176                                else {
    177                                        if( debug ) { queue.addMsg( "[INFO]QUEUE START" ); }
    178                                        exec( queue );
    179
    180//                                      // 8.0.0.2 (2021/10/15) ﾛｰｶﾙﾌｧｲﾙとｸﾗｳﾄﾞﾌｧｲﾙ間の移動
    181//                                      // 5.10.9.0 (2019/03/01) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ指定の場合は､ｱｯﾌﾟﾛｰﾄﾞする｡
    182//                                      // 8.0.1.0 (2021/10/29) ﾛｰｶﾙﾌｧｲﾙとｸﾗｳﾄﾞﾌｧｲﾙ間の移動は､ExecProcess#output(String...) で行う｡
    183//                                      HybsFileOperationFactory.local2cloud( () -> new File( queue.getOutputName() ) );
    184//                      //              final FileOperation cloudFile = HybsFileOperationFactory.create( queue.getOutputName() );
    185//                      //              if( cloudFile.isCloud() ) {
    186//                      //                      final File localFile = new File( queue.getOutputName() );
    187//                      //                      FileUtil.copy( localFile, cloudFile );
    188//                      //                      localFile.delete();
    189//                      //              }
    190
    191                                        // System.out.println( queue.getMsg() );
    192                                        System.out.print( queue.getMsg() ); // 4.3.0.0 (2008/07/15)
    193                                }
    194                        }
    195                }
    196        }
    197
    198        /**
    199         * ｽﾚｯﾄﾞを終了させるためのｷｭｰを追加します｡
    200         *
    201         * このﾒｿｯﾄﾞが呼ばれると､内部にｽﾀｯｸしているｷｭｰは全てｸﾘｱされます｡
    202         *
    203         * @og.rev 6.4.3.3 (2016/03/04) 処理ﾒｯｾｰｼﾞを表示します｡
    204         */
    205        public void finish() {
    206                queues.clear();
    207
    208                System.out.println( "[INFO]THREAD CREATED:THREAD-ID=" + getName() );
    209
    210                final ExecQueue qu = new ExecQueue();
    211                qu.setYkno( "_FINALIZE" );
    212                stackQueue( qu );
    213        }
    214
    215        /**
    216         * ｽﾚｯﾄﾞを終了させるためのｷｭｰを追加します｡
    217         *
    218         * このﾒｿｯﾄﾞでは､既にｽﾀｯｸされているｷｭｰはｸﾘｱされず､全て処理された後で､
    219         * ｽﾚｯﾄﾞを終了します｡
    220         *
    221         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
    222         */
    223        public void finishAfterExec() {
    224                final ExecQueue qu = new ExecQueue();
    225                qu.setYkno( "_FINALIZE" );
    226                stackQueue( qu );
    227        }
    228
    229        /**
    230         * 帳票処理を行います｡
    231         *
    232         * @og.rev 5.1.2.0 (2010/01/01) 256ｼｰﾄを超えた場合でも､正しく処理できるように対応
    233         *
    234         * @param       queue   ExecQueueｵﾌﾞｼﾞｪｸﾄ
    235         */
    236        private void exec( final ExecQueue queue ) {
    237                execStart = System.currentTimeMillis();
    238
    239                final ExecProcess oep = new ExecProcess( queue, debug );
    240                for( int i=0; i <= RETRY_COUNT; i++ ) {
    241                        try {
    242                                // 5.1.2.0 (2010/01/01) ﾃﾞｰﾀが終わるまで処理を継続する｡
    243                                while( !queue.isEnd() ) {
    244                                        oep.process();
    245                                }
    246                                queue.setComplete();
    247                                break;
    248                        }
    249                        catch( final Throwable th ) {
    250                                queue.addMsg( "[ERROR] OCCURRED!" );
    251                                queue.addMsg( ThrowUtil.ogStackTrace( th ) );                           // 6.4.2.0 (2016/01/29)
    252
    253                                if( i == RETRY_COUNT ) {
    254                                        queue.addMsg( "[ERROR]UPTO RETRY COUNT!" );
    255                                        queue.setError();
    256                                }
    257                        }
    258                }
    259
    260                execEnd = System.currentTimeMillis();
    261        }
    262
    263        /**
    264         * ｷｭｰを取り出します｡
    265         *
    266         * @return ｷｭｰ
    267         */
    268        private ExecQueue popQueue() {
    269                return queues.remove( 0 );
    270        }
    271
    272        /**
    273         * このｸﾗｽの文字列表現を返します｡
    274         *
    275         * @og.rev 4.3.0.0 (2008/07/15) debugを追加
    276         *
    277         * @return 文字列表現
    278         * @og.rtnNotNull
    279         */
    280        @Override
    281        public String toString() {
    282                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
    283                        .append( "STATE="                       ).append( state.toString() )
    284                        .append( ", START="                     ).append( HybsSystem.getDate( threadStart ) )
    285                        .append( ", POOL="                      ).append( queues.size() )
    286                        .append( ", EXEC-START="        ).append( HybsSystem.getDate( execStart ) )
    287                        .append( ", EXEC-END="          ).append( HybsSystem.getDate( execEnd ) )
    288                        .append( ", DEBUG="                     ).append( debug );              // 4.3.0.0 (2008/07/15) ﾃﾞﾊﾞｯｸﾞの追加
    289
    290                return buf.toString();
    291        }
    292}