    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                        }
    070                };
    071                SystemManager.addCleanable( clr2 , true );      // コンテキスト終了時のみ呼び出す
    072        }
    073
    074        /**
    075         * デフォルトコンストラクターをprivateにして、
    076         * オブジェクトの生成をさせないようにする。
    077         */
    078        private ProcessFactory() {
    079        }
    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]OOo: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}