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