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