    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.plugin.daemon;
    017
    018import java.util.Arrays;
    019import java.util.Date;
    020import java.util.LinkedHashMap;
    021import java.util.LinkedHashSet;
    022import java.util.Map;
    023import java.util.Set;
    024
    025import org.opengion.fukurou.db.DBUtil;
    026import org.opengion.fukurou.mail.MailTX;
    027import org.opengion.fukurou.transfer.TransferConfig;
    028import org.opengion.fukurou.transfer.TransferProcess;
    029import org.opengion.fukurou.util.ApplicationInfo;
    030import org.opengion.fukurou.util.HybsTimerTask;
    031import org.opengion.fukurou.util.LogWriter;
    032import org.opengion.fukurou.util.StringUtil;
    033import org.opengion.hayabusa.common.HybsSystem;
    034import org.opengion.hayabusa.common.HybsSystemException;
    035
    036/**
    037 * 【伝送システム】各読取方法、実行方法に応じて伝送処理を行うためのデーモンです。
    038 *
    039 * 読取、及び実行における具体的な処理については、{@link org.opengion.fukurou.transfer}パッケージ内の
    040 * 各実装クラスのドキュメントを参照して下さい。
    041 *
    042 * なお、各処理の実行について、トランザクションは、読取対象の単位になります。
    043 * 同じ読取対象で、異なる実行方法、実行対象を定義した場合、同じデータに対して複数回処理が行われます。
    044 * しかし、この場合においても、トランザクションは読取対象の単位で生成されるため、複数回の処理の内、
    045 * 1回でもエラーが発生した場合は、同じ読取対象でそれまでに処理した分についてもrollbackされます。
    046 *
    047 * 発生したエラーをメールで通知する場合は以下の設定を行う必要があります。
    048 * [システムリソース]
    049 *  COMMON_MAIL_SERVER
    050 *  ERROR_MAIL_FROM_USER
    051 * [伝送定義マスタ]
    052 *  エラー送信先
    053 * ※伝送定義マスタ読取時にエラーが発生した場合は、システムリソースの"ERROR_MAIL_TO_USERS"で
    054 *   設定さえたユーザーにメールが送信されます。
    055 *
    056 * ※処理中に何らかのエラーが1度でも発生した場合、このデーモンは停止します。
    057 *
    058 * このクラスは、HybsTimerTask を継承した タイマータスククラスです。
    059 * startDaemon() がタイマータスクによって、呼び出されます。
    060 *
    061 * @og.rev 5.4.1.0 (2011/11/01) 伝送システム対応
    062 * @og.group デーモン
    063 *
    064 * @version  5.0
    065 * @author   Hiroki Nakamura
    066 * @since    JDK6.0,
    067 */
    068public class Daemon_Transfer extends HybsTimerTask {
    069        //* このプログラムのVERSION文字列を設定します。   {@value} */
    070        private static final String VERSION = "5.5.5.1 (2012/08/07)" ;
    071
    072        // 伝送定義マスタ検索用SQL
    073        private static final String GE62_SELECT =
    074                "SELECT A.KBREAD,A.READOBJ,A.READPRM,A.KBEXEC,A.EXECDBID,A.EXECOBJ,A.EXECPRM,A.ERROR_SENDTO" +
    075                " FROM GE62 A" +
    076                " WHERE A.FGJ = '1'";
    077
    078        // コネクションにアプリケーション情報を追記するかどうか指定
    079        private static final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;
    080
    081        // HTTP接続時のプロキシホスト
    082        private static final String HTTP_PROXY_HOST = HybsSystem.sys( "HTTP_PROXY_HOST" );
    083
    084        // HTTP接続時のプロキシポート
    085        private static final int HTTP_PROXY_PORT = HybsSystem.sysInt( "HTTP_PROXY_PORT" );
    086
    087        // 呼び出し元ホストコード
    088        private static final String HFROM = HybsSystem.sys( "TRANSFER_HOST_CODE" );
    089
    090        // ループカウンタを24回に設定
    091        private static final int LOOP_COUNTER = 24;
    092
    093        private boolean running = true;
    094        private int loopCnt             = 0;
    095
    096        private String ge62Select = null;
    097        private String dmnName = null;
    098
    099        private ApplicationInfo appInfo = null;
    100        private boolean debug = false;
    101
    102        protected final String DBID = HybsSystem.sys( "RESOURCE_DBID" );                // 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対応
    103
    104        /**
    105         * このタイマータスクによって初期化されるアクションです。
    106         * パラメータを使用した初期化を行います。
    107         *
    108         */
    109        @Override
    110        public void initDaemon() {
    111                debug = StringUtil.nval( getValue( "DEBUG" ),debug );
    112
    113                dmnName = getName();
    114
    115                StringBuilder buf = new StringBuilder();
    116                buf.append( GE62_SELECT );
    117
    118                // システムIDは必須指定
    119                String systemId = getValue( "SYSTEM_ID" );
    120                if( StringUtil.isNull( systemId ) ) {
    121                        String errMsg = "システムID方法は必須指定です。" ;
    122                        throw new HybsSystemException( errMsg );
    123                }
    124                else {
    125                        buf.append( " AND A.SYSTEM_ID='" ).append( systemId ).append( "'" );
    126                }
    127
    128                // 読取方法は必須指定
    129                String kbRead = getValue( "KBREAD" );
    130                if( StringUtil.isNull( kbRead ) ) {
    131                        String errMsg = "読取方法は必須指定です。" ;
    132                        throw new HybsSystemException( errMsg );
    133                }
    134                else {
    135                        buf.append( " AND A.KBREAD='" ).append( kbRead ).append( "'" );
    136                }
    137
    138                // デーモングループは必須指定
    139                String dmnGroup = getValue( "DMN_GRP" );
    140                if( StringUtil.isNull( dmnGroup ) ) {
    141                        String errMsg = "デーモングループは必須指定です。" ;
    142                        throw new HybsSystemException( errMsg );
    143                }
    144                else {
    145                        buf.append( " AND A.DMN_GRP='" ).append( dmnGroup ).append( "'" );
    146                }
    147
    148                buf.append( " ORDER BY A.READOBJ,A.KBEXEC,A.EXECOBJ" );
    149
    150                ge62Select = buf.toString() ;
    151
    152                if( debug ) {
    153                        System.out.println( "DMN_NAME=[" + dmnName + "]" );
    154                        System.out.println( "QUERY=[" + ge62Select + "]" );
    155                }
    156
    157                if( USE_DB_APPLICATION_INFO ) {
    158                        appInfo = new ApplicationInfo();
    159                        // ユーザーID,IPアドレス,ホスト名
    160                        appInfo.setClientInfo( systemId,HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME );
    161                        // 画面ID,操作,プログラムID
    162                        appInfo.setModuleInfo( "TransferDaemon",dmnName,dmnName );
    163                }
    164                else {
    165                        appInfo = null;
    166                }
    167        }
    168
    169        /**
    170         * タイマータスクのデーモン処理の開始ポイントです。
    171         *
    172         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
    173         */
    174        @Override
    175        protected void startDaemon() {
    176                if( loopCnt % LOOP_COUNTER == 0 ) {
    177                        loopCnt = 1;
    178                        System.out.println();
    179                        System.out.print( toString() + " " + new Date()  + " " );
    180                }
    181                else {
    182                        System.out.print( "." );
    183                        loopCnt++ ;
    184                }
    185
    186                // 伝送DB読取
    187                String[][] vals  = null;
    188                GE62Data ge62Data = new GE62Data();
    189                try {
    190                        vals = DBUtil.dbExecute( ge62Select,null,appInfo,DBID );                // 5.5.5.1 (2012/08/07)
    191                        if( vals != null && vals.length > 0 ) {
    192                                for( int row=0; running && row<vals.length; row++ ) {
    193                                        ge62Data.addData( vals[row] );
    194                                }
    195                        }
    196                }
    197                catch( Throwable ex ) {
    198                        String header = "伝送読取エラー：DMN_NAME=[" + dmnName + "] , DMN_HOST=[" + HybsSystem.HOST_NAME + "] , QUERY=[" + ge62Select + "]";
    199                        String errMsg = header + HybsSystem.CR + StringUtil.stringStackTrace( ex ) ;
    200                        System.out.println( errMsg );
    201                        LogWriter.log( errMsg );
    202                        String errorSendto = HybsSystem.sys( "ERROR_MAIL_TO_USERS" );
    203                        sendMail( header, errMsg, errorSendto );
    204                }
    205
    206                // 処理実行
    207                // 読取対象の単位で処理を実行します。(トランザクションもこの単位になります)
    208                for( String tranKey : ge62Data.getTranSet() ) {
    209                        TransferProcess proc = null;
    210                        try {
    211                                proc = new TransferProcess( ge62Data.getConfSet( tranKey ) );
    212                                proc.setDmnName( dmnName );
    213                                proc.setAppInfo( appInfo );
    214                                if( debug ) {
    215                                        proc.setDebug();
    216                                }
    217
    218                                proc.process();
    219                        }
    220                        catch( Throwable ex ) {
    221                                // エラーが発生した場合はデーモンを停止します。
    222                                cancel();
    223
    224                                // 最後に処理した伝送設定オブジェクトを下にエラーを出力します。
    225                                String header = "伝送エラー：DMN_NAME=[" + dmnName + "] , DMN_HOST=[" + HybsSystem.HOST_NAME + "]";
    226                                String errorSendto = null;
    227                                if( proc != null ) {                            // 5.5.2.6 (2012/05/25) findbugs対応
    228                                        TransferConfig config = proc.getLastConfig();
    229                                        if( config != null ) {
    230                                                header += " , CONFIG=[" + config.toString() + "]";
    231                                                errorSendto = config.getErrorSendto();
    232                                        }
    233                                }
    234
    235                                String errMsg = header + HybsSystem.CR + StringUtil.stringStackTrace( ex ) ;
    236                                System.out.println( errMsg );
    237                                LogWriter.log( errMsg );
    238                                sendMail( header, errMsg, errorSendto );
    239                        }
    240                }
    241        }
    242
    243        /**
    244         * このタイマータスクのcancel() メソッドをオーバーライドします。
    245         * HybsTimerTaskManager#cancelTask( int ) を実行します。
    246         *
    247         * @return      スケジュールされている 1 回以上実行されない場合に true
    248         * @see java.util.TimerTask#cancel()
    249         */
    250        @Override
    251        public boolean cancel() {
    252                running = false;
    253                return super.cancel();
    254        }
    255
    256        /**
    257         * エラー情報のメール送信を行います。
    258         * エラーメールは、システムパラメータ の COMMON_MAIL_SERVER(メールサーバー)と
    259         * ERROR_MAIL_FROM_USER(エラーメール発信元)と、ERROR_MAIL_TO_USERS(エラーメール受信者)
    260         * がすべて設定されている場合に、送信されます。
    261         *
    262         * @param       inHeader        ヘッダーメッセージ
    263         * @param       inErrMsg        エラーメッセージ
    264         * @param       errorSendto     エラー送信先
    265         */
    266        protected void sendMail( final String inHeader, final String inErrMsg, final String errorSendto ) {
    267
    268                String   host = HybsSystem.sys( "COMMON_MAIL_SERVER" );
    269                String   from = HybsSystem.sys( "ERROR_MAIL_FROM_USER" );
    270                String[] to = StringUtil.csv2Array( errorSendto );
    271
    272                if( host != null && from != null && to.length > 0 ) {
    273                        try {
    274                                MailTX tx = new MailTX( host );
    275                                tx.setFrom( from );
    276                                tx.setTo( to );
    277                                tx.setSubject( inHeader );
    278                                tx.setMessage( inErrMsg );
    279                                tx.sendmail();
    280                        }
    281                        catch( Throwable ex ) {
    282                                String errMsg = "エラー時メール送信に失敗しました。" + HybsSystem.CR
    283                                                        + " SUBJECT:" + inHeader                                + HybsSystem.CR
    284                                                        + " HOST:" + host                                               + HybsSystem.CR
    285                                                        + " FROM:" + from                                               + HybsSystem.CR
    286                                                        + " TO:"   + Arrays.toString( to )              + HybsSystem.CR
    287                                                        + ex.getMessage();
    288                                LogWriter.log( errMsg );
    289                                LogWriter.log( ex );
    290                        }
    291                }
    292        }
    293
    294        /**
    295         * 伝送定義マスタから読み出したデータを管理します。
    296         */
    297        private static class GE62Data {
    298
    299                // トランザクションを生成するキーのセット(読取対象単位)
    300                private final Set<String> tranSet = new LinkedHashSet<String>();
    301                // トランザクションキー(読取対象)に対する、設定オブジェクトのセット
    302                private final Map<String,Set<TransferConfig>> tran2ConfSet = new LinkedHashMap<String,Set<TransferConfig>>();
    303
    304                /**
    305                 * GE62読取データを追加します。
    306                 *
    307                 * @param data GE62読取データ
    308                 */
    309                private void addData( final String[] data ) {
    310                        String kbRead           = data[0];
    311                        String readObj          = data[1];
    312                        String readPrm          = data[2];
    313                        String kbExec           = data[3];
    314                        String execDbid         = data[4];
    315                        String execObj          = data[5];
    316                        String execPrm          = data[6];
    317                        String errorSendto      = data[7];
    318
    319                        String tranKey = readObj;
    320                        tranSet.add( tranKey );
    321
    322                        Set<TransferConfig> confSet = tran2ConfSet.get( tranKey );
    323                        if( confSet == null ) {
    324                                confSet = new LinkedHashSet<TransferConfig>();
    325                        }
    326                        TransferConfig conf = new TransferConfig(
    327                                                                                kbRead, readObj, readPrm
    328                                                                                , kbExec, execDbid, execObj, execPrm
    329                                                                                , errorSendto, HFROM, HTTP_PROXY_HOST, HTTP_PROXY_PORT );
    330                        confSet.add( conf );
    331                        tran2ConfSet.put( tranKey, confSet );
    332                }
    333
    334                /**
    335                 * トランザクション生成キー(読取対象)のセットを返します。
    336                 *
    337                 * @return トランザクション生成キー(読取対象)のセット
    338                 */
    339                private Set<String> getTranSet() {
    340                        return tranSet;
    341                }
    342
    343                /**
    344                 * トランザクション生成キー(読取対象)に対する設定オブジェクトのセットを返します。
    345                 *
    346                 * @param tranKey トランザクション生成キー(読取対象)
    347                 * @return 設定オブジェクトのセット
    348                 */
    349                private Set<TransferConfig> getConfSet( final String tranKey ) {
    350                        return tran2ConfSet.get( tranKey );
    351                }
    352        }
    353}