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.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
019import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.3 (2016/03/04)
020import org.opengion.fukurou.util.Cleanable;                                                     // 8.5.6.0 (2024/02/29)
021import org.opengion.hayabusa.common.SystemManager;                                      // 8.5.6.0 (2024/02/29)
022
023/**
024 * 帳票処理を行う各スレッドを管理するクラスです。
025 *
026 * 各スレッドは、内部的にプールされます。
027 * スレッドのIDはOOoQueue#getThreadId()で返される値です。
028 * スレッドが生成されるタイミングは、そのIDで初めてスタック要求が来た(insertQueue()が呼ばれた)時です。
029 *
030 * 指定のスレッドを終了するには、funishThread( key )を呼び出します。
031 * 全てのスレッドを終了するには、funishAllThreads()を呼び出します。
032 *
033 * 現時点での実装では、生成されたスレッドに対しての監視は行っていません。
034 * これは、特定のスレッドがフリーズした際、外部から強制終了を行おうとすると、
035 * 監視スレッドもフリーズしてしまう問題があるためです。
036 * (但し、1つのsoffice.binのプロセスに対してシリアルに対して処理している限りでは、
037 *  フリーズ問題は発生しないようです)
038 *
039 * @og.group 帳票システム
040 *
041 * @version  4.0
042 * @author   Hiroki.Nakamura
043 * @since    JDK1.6
044 */
045public final class ExecThreadManager {
046        /** 6.4.3.1 (2016/02/12) 一連の処理で同期を取りたいので、 ConcurrentHashMap は使いません。 */
047        private static final ConcurrentMap<String, ExecThread> EXEC_POOL = new ConcurrentHashMap<>();           // 6.4.3.3 (2016/03/04)
048        private static boolean debug    ;               // 4.3.0.0 (2008/07/15) デバッグ追加
049
050        /** 8.5.6.0 (2024/02/29) common/HybsContextListener から移動 */
051        static {
052                final Cleanable clr = new Cleanable() {
053                        /**
054                         * 全てのスレッドを終了します。
055                         */
056                        public void clear() {
057                                // 8.5.6.1 (2024/03/29) REP21/result2.jsp で、使用していたので復活。
058                                finishAllThreads();
059//                              EXEC_POOL.forEach( (id,oet) -> oet.finish() );
060//                              System.out.println( "[INFO]ALL THREADS FINISHED" );
061                        }
062                };
063                SystemManager.addCleanable( clr,true );         // contextDestroyed の場合のみ実行
064        }
065
066        /**
067         * デフォルトコンストラクターをprivateにして、
068         * オブジェクトの生成をさせないようにする。
069         */
070        private ExecThreadManager() {}
071
072        /**
073         * キューを該当するスレッドにスタックする。
074         *
075         * @og.rev 4.3.0.0 (2008/07/15) スレッドIDにシステムIDを付加
076         *
077         * @param       queue   ExecQueueオブジェクト
078         */
079        public static void insertQueue( final ExecQueue queue ) {
080                // 4.3.3.6 (2008/11/15) この部分は不要なので元に戻します
081                final ExecThread oet = getExecThread( queue.getThreadId() );
082                oet.stackQueue( queue );
083        }
084
085        /**
086         * キューを該当するスレッドにスタックする
087         *
088         * このメソッドでは、既に同じスレッドが存在するかどうかをチェックせずに必ず
089         * 新しいスレッドを生成し、キューを処理します。
090         * また、処理が完了した後、そのスレッドは、WAITすることなく終了します。
091         *
092         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
093         *
094         * @param       queue   ExecQueueオブジェクト
095         */
096        public static void insertQueueOnNewThread( final ExecQueue queue ) {
097                final ExecThread oet = new ExecThread( queue.getThreadId(), debug );
098                oet.start();
099                oet.stackQueue( queue );
100                oet.finishAfterExec();
101        }
102
103        /**
104         * 該当するスレッドIDを持つスレッドを取得します。
105         * スレッドプールに存在しない場合は、新規に作成されます。
106         *
107         * @og.rev 6.4.3.3 (2016/03/04) Map#compute で対応する。
108         *
109         * @param       threadId        スレッドID
110         *
111         * @return      ExecThreadスレッド
112         */
113        private static ExecThread getExecThread( final String threadId ) {
114                // Map#compute : 戻り値は、新しい値。追加有り、置換有り、削除有り
115                return EXEC_POOL.compute( threadId, (id,oet) ->
116                                        oet == null || !oet.isAlive() ? ExecThread.startExecThread( id, debug ) : oet );
117        }
118
119        /**
120         * 全てのスレッドを終了します。
121         *
122         * ※ REP21/result2.jsp で、使用。
123         *
124         * @og.rev 6.4.3.3 (2016/03/04) Map#forEach で対応する。
125         * @og.rev 8.5.6.0 (2024/02/29) common/HybsContextListener から移動。
126         * @og.rev 8.5.6.1 (2024/03/29) REP21/result2.jsp で、使用していたので復活。
127         */
128        public static void finishAllThreads() {
129                EXEC_POOL.forEach( (id,oet) -> oet.finish() );
130                System.out.println( "[INFO]ALL THREADS FINISHED" );
131        }
132
133        /**
134         * 指定のスレッドを終了します。
135         *
136         * ※ REP21/entry.jsp で、使用。
137         *
138         * @param threadId スレッドID
139         */
140        public static void finishThread( final String threadId ) {
141                        final ExecThread oet = EXEC_POOL.remove( threadId );
142                        // Map上には null はないが、キーが合わない場合は、null が戻る。
143                        if( oet != null ) {
144                                oet.finish();
145                                System.out.println( "[INFO]THREAD CREATED:THREAD-ID=" + threadId );
146                        }
147        }
148
149        /**
150         * スレッド情報のマップを返します。
151         *
152         * ※ REP21/result2.jsp で、使用。
153         *
154         * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
155         * @og.rev 6.4.3.3 (2016/03/04) 戻すMapが、not null制限つきであることを示すため、ConcurrentMap に置き換えます。
156         * @og.rev 6.4.3.3 (2016/03/04) Map#forEach で対応する。
157         *
158         * @return      スレッド情報のマップ
159         */
160        public static ConcurrentMap<String, String> getThreadInfo() {
161                final ConcurrentMap<String, String> infoMap = new ConcurrentHashMap<>();
162
163                EXEC_POOL.forEach( (id,oet) -> infoMap.put( id,oet.toString() ) );
164
165                return infoMap;
166        }
167
168        /**
169         * デバッグフラグの設定。
170         *
171         * @og.rev 4.3.0.0 (2008/07/15) デバッグ追加
172         *
173         * @param   flag デバッグフラグ [true:デバッグ/false:通常]
174         */
175        public static void setDebug ( final boolean flag ){
176                debug = flag;
177        }
178}