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}