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}