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.io.File;
019import java.io.IOException;
020
021import org.opengion.fukurou.system.ThrowUtil;                                                   // 6.4.2.0 (2016/01/29)
022import org.opengion.fukurou.util.AbstractObjectPool;
023import org.opengion.fukurou.util.Cleanable;
024import org.opengion.fukurou.util.FileUtil;
025import org.opengion.hayabusa.common.HybsSystem;
026import org.opengion.hayabusa.common.SystemManager;
027
028/**
029 * Sofficeのプロセスを管理するファクトリクラスです。
030 * プロセスプールの実装は、AbstractObjectPoolを継承して実装されています。
031 *
032 * プロセスの初期生成数は0です。最大生成数は、システムリソースのREPORT_MAX_PROCESS_COUNTで
033 * 定義されます。また、生存時間は、REPORT_PROCESS_ALIVEで定義されています。
034 *
035 * プロセスを全て終了するには、clearメソッドを呼び出します。
036 * clearメソッドは、Cleanableインターフェースの実装として組み込まれ、SytemManagerに登録されるため、
037 * Tomcat終了時に、自動的にプロセスが終了されます。
038 * 但し、貸し出し中(処理中)のプロセスは、AbstractObjecgPoolの実装から、終了されないため、別の方法で
039 * 明示的にkillする必要があります
040 *
041 * @version  4.0
042 * @author   Hiroki Nakamura
043 * @since    JDK5.0,
044 */
045public final class ProcessFactory {
046
047        /**
048         * プロセスプール
049         */
050        private static ProcessPool pp = new ProcessPool() ;
051
052        /** Cleanable インターフェースによる初期化処理 */
053        static {
054                final Cleanable clr = new Cleanable() {
055                        public void clear() {
056                                ProcessFactory.clear();
057                        }
058                };
059                SystemManager.addCleanable( clr );
060
061                // 5.2.2.0 (2010/11/01) 循環参照解消のため、SystemManager から移動
062                final Cleanable clr2 = new Cleanable() {
063                        /**
064                         * 初期化(クリア)します。
065                         * 主に、キャッシュクリアで利用します。
066                         */
067                        public void clear() {
068//                              ProcessFactory.kill();
069//                              kill();                                 // 8.5.4.2 (2024/01/12) PMD 7.0.0 UnnecessaryFullyQualifiedName
070                        }
071                };
072                SystemManager.addCleanable( clr2 , true );      // コンテキスト終了時のみ呼び出す
073        }
074
075        /**
076         * デフォルトコンストラクターをprivateにして、
077         * オブジェクトの生成をさせないようにする。
078         */
079        private ProcessFactory() {}
080
081        /**
082         * OpenOfficeのプロセスを生成します。
083         *
084         * @return      sofficeのプロセス
085         */
086        public static SOfficeProcess newInstance() {
087                return pp.newInstance();
088        }
089
090        /**
091         * OpenOfficeのプロセスをリリースします。
092         *
093         * @param  soffice SOfficeProcessオブジェクト
094         */
095        public static void release( final SOfficeProcess soffice ) {
096                pp.release( soffice );
097        }
098
099        /**
100         * OpenOfficeのプロセスをクローズします。
101         *
102         * @param   soffice SOfficeProcessオブジェクト
103         */
104        public static void remove( final SOfficeProcess soffice ) {
105                pp.remove( soffice );
106        }
107
108        /**
109         * プールされているOpenOfficeのプロセスを全てクローズします。
110         */
111        public static void clear() {
112                pp.clear();
113        }
114
115        /**
116         * 全てのsoffice.binプロセスをKILLします。
117         * アプリケーションの終了処理で実行します。
118         * OS名がWindowsを含む場合はtaskkill、それ以外の場合はkillallします。
119         * 又、プロセス終了後にコピーされた設定ファイルを削除します。
120         *
121         * @og.rev 4.3.0.0 (2008/07/18) 追加
122         * @og.rev 4.3.0.0 (2008/07/22) 設定ファイルの削除を追加
123         * @og.rev 4.3.5.0 (2009/02/01) Exception をそれぞれのExceptionに分けて捕らえる。
124         * @og.rev 6.4.2.0 (2016/01/29) ex.printStackTrace() を、ThrowUtil#ogStackTrace(Throwable) に置き換え。
125         */
126        public static void kill() {
127                try {
128                        final String osName = HybsSystem.sys( "OS_INFO" ); //System.getProperty("os.name");
129                        if( osName.indexOf( "Windows" ) >= 0 ){
130                                // 4.3.0.0 (2008/07/18) Windoesのtaskkillを利用してsoffice.binのタスクを強制終了します。
131                                new ProcessBuilder( "cmd.exe","/c","taskkill","/F","/IM","soffice.bin" ).start().waitFor();
132                        }
133                        else{
134                                // 4.3.0.0 (2008/07/24) Windowsではない場合はkillallコマンド
135                                new ProcessBuilder( "killall","-9","-w","soffice.bin" ).start().waitFor();
136                        }
137
138                        // 4.3.0.0 (2008/07/22) 設定ファイル(SOfficeProcessでディレクトリを設定)を全削除します。
139                        FileUtil.deleteFiles( new File( SOfficeProcess.ENV_DIR ) );
140                }
141                // 6.3.9.1 (2015/11/27) Exceptionをまとめます。
142                catch( final IOException | InterruptedException | RuntimeException ex ) {
143                        System.err.println( ThrowUtil.ogStackTrace( ex ) );                             // 6.4.2.0 (2016/01/29)
144                }
145        }
146
147        /**
148         * 現在の状態を文字列で返します。
149         *
150         * @return  現在の状態
151         * @og.rtnNotNull
152         */
153        public static String information() {
154                return pp.toString();
155        }
156
157        /**
158         * ProcessPool は、AbstractObjectPool を継承した オブジェクトプールです。
159         *
160         * OpenOfficeのプロセスをプールします。
161         *
162         * @version  4.0
163         * @author   Hiroki Nakamura
164         * @since    JDK5.0,
165         */
166        protected static final class ProcessPool extends AbstractObjectPool<SOfficeProcess> {
167                // 環境ファイル作成の識別用
168                private int count       ;
169
170                /**
171                 * 初期処理を行います。
172                 */
173                protected ProcessPool() {
174                        super();                // 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor
175                        init( 0, HybsSystem.sysInt( "REPORT_MAX_PROCESS_COUNT")
176                                        , true, HybsSystem.sysInt( "REPORT_PROCESS_ALIVE" ) );
177                }
178
179                /**
180                 * soffieのプロセスオブジェクトを作成します。
181                 *
182                 * @og.rev 4.3.5.0 (2009/02/01) Exception ではなく、RuntimeException に変更
183                 * @og.rev 5.1.7.0 (2010/06/01) TCP接続対応
184                 *
185                 * @return OpenOfficeのプロセス
186                 */
187                @Override
188                protected SOfficeProcess createInstance() {
189                        SOfficeProcess soffice = null;
190                        try {
191                                // 5.1.7.0 (2010/06/01) TCP接続対応
192                                if( "TCP".equalsIgnoreCase( HybsSystem.sys( "REPORT_OOO_CONN_TYPE" ) ) ) {
193                                        soffice = new SOfficeProcessTcp( "env_" + count, HybsSystem.sysInt( "REPORT_OOO_MIN_PORT" ) );
194                                }
195                                else {
196                                        soffice = new SOfficeProcess( "env_" + count );
197                                }
198                                soffice.bootstrap();
199
200                                count++;
201                        }
202                        catch( final RuntimeException ex ) {
203                                System.out.println( "[ERROR]FACTORY:Failed to Connect Soffice! " + ex.getMessage() );
204                        }
205                        return soffice;
206                }
207
208                /**
209                 * オブジェクトプールから削除するときに呼ばれます。
210                 * このメソッドで各オブジェクトごとの終了処理を行います。
211                 *
212                 * @param soffice OpenOfficeのプロセス
213                 */
214                @Override
215                protected void objectFinal( final SOfficeProcess soffice ) {
216                        soffice.close();
217                }
218        }
219}