    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.mail;
    017
    018import java.util.ArrayList;
    019import java.util.List;
    020import java.util.Arrays;
    021import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
    022import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.3 (2016/03/04)
    023
    024import org.opengion.fukurou.db.DBUtil;
    025import org.opengion.fukurou.mail.MailTX;
    026import org.opengion.fukurou.system.LogWriter;
    027import org.opengion.fukurou.system.DateSet;                                                     // 6.4.2.0 (2016/01/29)
    028import org.opengion.fukurou.util.StringUtil;
    029import org.opengion.hayabusa.common.HybsSystem;
    030import static org.opengion.fukurou.system.HybsConst.CR ;                        // 6.1.0.0 (2014/12/26)
    031import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
    032
    033/**
    034 * パッチによるメール送信の実装クラスです。
    035 * 送信デーモンはパラメータテーブル(GE30)を監視して、新規のデータが登録されたら、
    036 * そのデータをパラメータとしてメール合成処理メソッドに渡して合成を行って送信します。
    037 * 最後に、処理結果を受取って、パラメータテーブルの状況フラグを送信済/送信エラーに更新します。
    038 * エラーが発生した場合、エラーテーブルにエラーメッセージを書き込みます。
    039 *
    040 * @og.rev 5.9.26.0 (2017/11/02) 子クラスで利用する定数をprivateからprotectedに変更
    041 * @og.group メールモジュール
    042 *
    043 * @version  4.0
    044 * @author   Sen.Li
    045 * @since    JDK1.6
    046 */
    047public class MailManager_DB extends DefaultMailManager {
    048//      // 5.9.26.0 (2017/11/02) 子クラスで利用定数を、privateからprotectedに変更
    049//      // 5.2.0.0 (2010/09/01) Ver4互換モード対応
    050//      // 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
    051//      private static final String H_TXT = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "HEADER" : "H_TXT";
    052//      private static final String F_TXT = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "FOOTER" : "F_TXT";
    053
    054        // 5.2.0.0 (2010/09/01) Ver4互換モード対応
    055        // 6.4.1.1 (2016/01/16) selGE30 → SEL_GE30 , insGE36 → INS_GE36 , updGE30 → UPD_GE30 refactoring
    056        // 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
    057//      protected static final String   SEL_GE30        = "SELECT  UNIQ,PTN_ID,FROM_ID,TO_ID,CC_ID,BCC_ID,"+H_TXT+","+F_TXT
    058//      // 5.9.32.0 (2018/05/01) 送信件数制限
    059//      protected static final String   SEL_GE30        = "SELECT  UNIQ,PTN_ID,FROM_ID,TO_ID,CC_ID,BCC_ID,H_TXT,F_TXT"
    060//                                                                              + ",PARAM0,PARAM1,PARAM2,PARAM3,PARAM4,PARAM5,PARAM6,PARAM7,PARAM8,PARAM9"
    061//                                                                              + ",ATTACH1,ATTACH2,ATTACH3,ATTACH4,ATTACH5"
    062//                                                                              + " FROM GE30"
    063//                                                                              + " WHERE SYSTEM_ID =? AND FGJ='1'"
    064//                                                                              + " AND (SNDTIME IS NULL OR SNDTIME <= ? )";    // 5.9.18.0 (2017/03/02)
    065
    066        // 5.9.32.0 (2018/05/02) 1回辺りの送信件数制限 0以下の場合は制限なし
    067        private static final String SEND_LIMIT = HybsSystem.sysInt( "MAIL_DAEMON_LIMIT" ) < 1 ? "" : " WHERE MAILDB.ROW_NUM <= " + HybsSystem.sys( "MAIL_DAEMON_LIMIT" );
    068
    069        // 5.9.32.0 (2018/05/01) 送信件数制限
    070        /** GE30 検索文 */
    071        protected static final String   SEL_GE30        = "SELECT * FROM ("
    072//                      +"SELECT  UNIQ,PTN_ID,FROM_ID,TO_ID,CC_ID,BCC_ID,"+H_TXT+","+F_TXT
    073                        +"SELECT  UNIQ,PTN_ID,FROM_ID,TO_ID,CC_ID,BCC_ID,H_TXT,F_TXT"
    074                        +",PARAM0,PARAM1,PARAM2,PARAM3,PARAM4,PARAM5,PARAM6,PARAM7,PARAM8,PARAM9"
    075                        +",ATTACH1,ATTACH2,ATTACH3,ATTACH4,ATTACH5"
    076                        +",row_number() over (order by uniq) as ROW_NUM " // 5.9.32.0 (2018/05/02)
    077                        + " FROM GE30"
    078                        + " WHERE SYSTEM_ID =? AND FGJ='1'"
    079                        + " AND (SNDTIME IS NULL OR SNDTIME <= ? )"
    080//                      + ") as MAILDB "
    081                        + ") MAILDB " // 5.10.7.0 (2019/01/11) asはoracleでエラーになるので除外
    082                        + SEND_LIMIT;
    083
    084        /** GE36 ｲﾝｻｰﾄ文 */
    085        protected static final String INS_GE36 = "INSERT INTO GE36(PARA_KEY,ERRMSG,DYSET,USRSET,PGUPD,SYSTEM_ID,FGJ)"
    086                                                                                + " VALUES(?,?,?,?,?,?,'1')";
    087
    088        private static final String     UPD_GE30        = "UPDATE GE30 SET FGJ= ? WHERE UNIQ = ? ";
    089
    090        /** 送信状態 */ protected static final String       SNED_OK = "2";
    091        /** 送信状態 */ protected static final String       SNED_NG = "8";
    092
    093        /** GE30 カラム番号 {@value} */
    094        protected static final int GE30_UNIQ    = 0 ;
    095        private static final int GE30_PTN_ID    = 1 ;
    096        private static final int GE30_FROM_ID   = 2 ;
    097        private static final int GE30_TO_ID             = 3 ;
    098        private static final int GE30_CC_ID             = 4 ;
    099        private static final int GE30_BCC_ID    = 5 ;
    100        private static final int GE30_H_TXT             = 6 ;           // 5.0.3.0 (2009/11/04) HEADER ⇒ H_TXT
    101        private static final int GE30_F_TXT             = 7 ;           // 5.0.3.0 (2009/11/04) FOOTER ⇒ F_TXT
    102        private static final int GE30_PARAM0    = 8 ;
    103        private static final int GE30_PARAM1    = 9 ;
    104        private static final int GE30_PARAM2    = 10 ;
    105        private static final int GE30_PARAM3    = 11 ;
    106        private static final int GE30_PARAM4    = 12 ;
    107        private static final int GE30_PARAM5    = 13 ;
    108        private static final int GE30_PARAM6    = 14 ;
    109        private static final int GE30_PARAM7    = 15 ;
    110        private static final int GE30_PARAM8    = 16 ;
    111        private static final int GE30_PARAM9    = 17 ;
    112        private static final int GE30_ATTACH1   = 18 ;
    113        private static final int GE30_ATTACH2   = 19 ;
    114        private static final int GE30_ATTACH3   = 20 ;
    115        private static final int GE30_ATTACH4   = 21 ;
    116        private static final int GE30_ATTACH5   = 22 ;
    117
    118        /** GE36 ｶﾗﾑ */ protected static final int GE36_PARA_KEY        = 0 ;
    119        /** GE36 ｶﾗﾑ */ protected static final int GE36_ERRMSG          = 1 ;
    120        /** GE36 ｶﾗﾑ */ protected static final int GE36_DYSET           = 2 ;
    121        /** GE36 ｶﾗﾑ */ protected static final int GE36_USRSET          = 3 ;
    122        /** GE36 ｶﾗﾑ */ protected static final int GE36_PGUPD           = 4 ;
    123        /** GE36 ｶﾗﾑ */ protected static final int GE36_SYSTEM_ID       = 5 ;
    124        /** GE36 ｶﾗﾑ */ protected final List<String>     errMsgList     = new ArrayList<>();
    125
    126        /**
    127         * デフォルトコンストラクター
    128         *
    129         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    130         */
    131        public MailManager_DB() { super(); }            // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    132
    133        /**
    134         * バッチより呼出のメインメソッドです。
    135         * パラメータテーブル(GE30)を監視します。
    136         * 新規のデータが登録されたら、メール文を合成して送信を行います。
    137         * エラーが発生した場合、エラーテーブルにエラーメッセージを書き込みます。
    138         *
    139         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
    140         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。
    141         * @og.rev 5.9.18.0 (2017/03/02) SNDTIME対応
    142         *
    143         * @param systemId システムID
    144         */
    145        public void sendDBMail( final String systemId ){
    146                // パラメータテーブルよりバッチでセットしたデータを取得します。
    147                final String[][] ge30datas = DBUtil.dbExecute( SEL_GE30, new String[]{ systemId, DateSet.getDate( "yyyyMMddHHmmss" ) }, APP_INFO, DBID );       // 5.9.18.0 (2017/03/02)
    148
    149                final int ge30Len = ge30datas.length;
    150                for( int i=0; i<ge30Len; i++ ) {
    151                        String fgj = SNED_OK;
    152                        try {
    153                                final ConcurrentMap<String, String> initParam = makeParamMap( systemId, ge30datas[i] );
    154                                create( initParam );
    155                                send();                                                         // 合成されたメール文書、宛先で送信処理を行います。
    156                                errMsgList.addAll( getErrList() );
    157                        }
    158                        catch( final RuntimeException rex ) {
    159                                fgj = SNED_NG;
    160                                errMsgList.add( "メール送信失敗しました。パラメータキー：" + ge30datas[i][GE30_UNIQ] + " " + rex.getMessage() );
    161                        }
    162                        finally {
    163                                commitParamTable( ge30datas[i][GE30_UNIQ], fgj );
    164                                if( ! errMsgList.isEmpty() ) {
    165                                        writeErrorTable( ge30datas[i][GE30_UNIQ], systemId, errMsgList );
    166                                        errMsgList.clear();
    167                                }
    168                        }
    169                }
    170        }
    171
    172        /**
    173         * パラメータテーブルに登録したデータをパラメータマップにセットします。
    174         *
    175         * @og.rev 6.4.2.0 (2016/01/29) DateSet.getDate( String ) を利用するように修正します。
    176         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。
    177         * @og.rev 5.9.26.0 (2017/11/02) 子クラスでの利用対応。privateをprotectedに変更。
    178         *
    179         * @param       systemId        システムID
    180         * @param       ge30Data        パラメータテーブルのデータ配列
    181         *
    182         * @return      データをセットしたマップ
    183         */
    184        protected ConcurrentMap<String, String> makeParamMap( final String systemId, final String[] ge30Data ){                         // 6.4.3.3 (2016/03/04) ここは可変長はまずいでしょ。
    185                ConcurrentMap<String,String> paramMap = null;
    186                if( ge30Data != null && ge30Data.length > 0 ) {         // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    187                        paramMap = new ConcurrentHashMap<>();
    188                        paramMap.put( "SYSTEM_ID"       , systemId    );
    189                        paramMap.put( "PARAKEY"         , ge30Data[GE30_UNIQ]    );
    190                        paramMap.put( "PTN_ID"          , ge30Data[GE30_PTN_ID]  );
    191                        paramMap.put( "FROM"            , ge30Data[GE30_FROM_ID] );
    192                        paramMap.put( "TO"                      , ge30Data[GE30_TO_ID]   );
    193                        paramMap.put( "CC"                      , ge30Data[GE30_CC_ID]   );
    194                        paramMap.put( "BCC"                     , ge30Data[GE30_BCC_ID]  );
    195                        paramMap.put( "H_TXT"           , ge30Data[GE30_H_TXT]   );                     // 5.0.3.0 (2009/11/04) HEADER ⇒ H_TXT
    196                        paramMap.put( "F_TXT"           , ge30Data[GE30_F_TXT]   );                     // 5.0.3.0 (2009/11/04) FOOTER ⇒ F_TXT
    197                        paramMap.put( "PARAM0"          , ge30Data[GE30_PARAM0]  );
    198                        paramMap.put( "PARAM1"          , ge30Data[GE30_PARAM1]  );
    199                        paramMap.put( "PARAM2"          , ge30Data[GE30_PARAM2]  );
    200                        paramMap.put( "PARAM3"          , ge30Data[GE30_PARAM3]  );
    201                        paramMap.put( "PARAM4"          , ge30Data[GE30_PARAM4]  );
    202                        paramMap.put( "PARAM5"          , ge30Data[GE30_PARAM5]  );
    203                        paramMap.put( "PARAM6"          , ge30Data[GE30_PARAM6]  );
    204                        paramMap.put( "PARAM7"          , ge30Data[GE30_PARAM7]  );
    205                        paramMap.put( "PARAM8"          , ge30Data[GE30_PARAM8]  );
    206                        paramMap.put( "PARAM9"          , ge30Data[GE30_PARAM9]  );
    207                        paramMap.put( "ATTACH1"         , ge30Data[GE30_ATTACH1] );
    208                        paramMap.put( "ATTACH2"         , ge30Data[GE30_ATTACH2] );
    209                        paramMap.put( "ATTACH3"         , ge30Data[GE30_ATTACH3] );
    210                        paramMap.put( "ATTACH4"         , ge30Data[GE30_ATTACH4] );
    211                        paramMap.put( "ATTACH5"         , ge30Data[GE30_ATTACH5] );
    212                        paramMap.put( "DATE"            , DateSet.getDate("yyyy/MM/dd") );              // 6.4.2.0 (2016/01/29)
    213                        paramMap.put( "TIME"            , DateSet.getDate("HH:mm:ss") );                // 6.4.2.0 (2016/01/29)
    214                        paramMap.put( "LOGIN_USERID", "DAEMON" );
    215                        paramMap.put( "LOGIN_USERNAME", "DAEMON" );
    216                        paramMap.put( "PGID", "DAEMON" );
    217                }
    218                return paramMap;
    219        }
    220
    221        /**
    222         * 送信後、パラメータテーブルの状況フラグを更新します。
    223         * 送信エラーなしの場合はフラグを’送信済(2)’、エラーの場合’送信エラー(8)’に更新します。
    224         *
    225         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
    226         * @og.rev 5.9.26.0 (2017/11/02) 子クラスでの利用対応。privateをprotectedに変更。
    227         *
    228         * @param       uniq    ユニークキー
    229         * @param       fgj             状況フラグ[2:送信済/8:エラー]
    230         */
    231        protected void commitParamTable( final String uniq, final String fgj ){
    232                final String[] updGE30Args = { fgj, uniq };
    233                DBUtil.dbExecute( UPD_GE30, updGE30Args, APP_INFO, DBID );              // 5.5.5.1 (2012/08/07)
    234        }
    235
    236        /**
    237         * エラーテーブルにエラーメッセージを登録します。
    238         *
    239         * @og.rev 4.4.0.1 (2009/08/08) メール送信追加
    240         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
    241         * @og.rev 6.4.2.0 (2016/01/29) DateSet.getDate( String ) を利用するように修正します。
    242         *
    243         * @param       paraKey         パラメータキー(GE36.PARA_KEY)
    244         * @param       systemId        システムID
    245         * @param       emList          エラーメッセージリスト
    246         *
    247         */
    248        private void writeErrorTable( final String paraKey, final String systemId, final List<String> emList ){
    249                String[] insGE36Args = new String[6];
    250                insGE36Args[GE36_PARA_KEY]      = paraKey;
    251                insGE36Args[GE36_DYSET]         = DateSet.getDate( "yyyyMMddHHmmss" );  // 6.4.2.0 (2016/01/29)
    252                insGE36Args[GE36_USRSET]        = "DAEMON";
    253                insGE36Args[GE36_PGUPD]         = "DAEMON";
    254                insGE36Args[GE36_SYSTEM_ID] = systemId;
    255                for( int i=0; i< emList.size(); i++ ){
    256                        insGE36Args[GE36_ERRMSG] = trim( emList.get( i ), 4000);
    257                        DBUtil.dbExecute( INS_GE36, insGE36Args, APP_INFO, DBID );              // 5.5.5.1 (2012/08/07)
    258                }
    259
    260                sendMail( paraKey, systemId, emList ); // 4.4.0.1 (2009/08/08)
    261        }
    262
    263        /**
    264         * エラー情報のメール送信を行います。
    265         * エラーメールは、システムパラメータ の COMMON_MAIL_SERVER(メールサーバー)と
    266         * ERROR_MAIL_FROM_USER(エラーメール発信元)と、ERROR_MAIL_TO_USERS(エラーメール受信者)
    267         * がすべて設定されている場合に、送信されます。
    268         *
    269         * @og.rev 4.4.0.1 (2009/08/08) 追加
    270         * @og.rev 5.4.3.2 (2012/01/06) 認証対応
    271         * @og.rev 6.0.3.0 (2014/11/13) Ver6用キーワード変更
    272         * @og.rev 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。
    273         * @og.rev 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。
    274         * @og.rev 5.9.29.2 (2018/02/16) STARTTLS対応(ｷｰﾜｰﾄﾞをVer5 にあわせます)
    275         *
    276         * @param       paraKey         メールキー
    277         * @param       systemId        システムID
    278         * @param       emList          エラーメッセージリスト
    279         */
    280        private void sendMail( final String paraKey, final String systemId, final List<String> emList ) {
    281
    282                final String    host            = HybsSystem.sys( "COMMON_MAIL_SERVER" );
    283                final String    from            = HybsSystem.sys( "ERROR_MAIL_FROM_USER" );
    284                final String    charset         = HybsSystem.sys( "MAIL_DEFAULT_CHARSET" );
    285                final String    smtpPort        = HybsSystem.sys( "SMTP_PORT" );                                // 5.4.3.2 (2012/01/06)
    286                final String    authType        = HybsSystem.sys( "MAIL_SEND_AUTH" );                   // 6.0.3.0 (2014/11/13) Ver6用キーワード変更
    287                final String    authPort        = HybsSystem.sys( "MAIL_SEND_AUTH_PORT" );              // 5.8.1.1 (2014/11/14)
    288                final String    authUser        = HybsSystem.sys( "MAIL_SEND_AUTH_USER" );              // 5.4.3.2 (2012/01/06)
    289                final String    authPass        = HybsSystem.sys( "MAIL_SEND_AUTH_PASSWORD" );  // 5.4.3.2 (2012/01/06)
    290                final boolean   useSSL          = HybsSystem.sysBool( "MAIL_SEND_USE_SSL" );    // 6.3.8.0 (2015/09/11)
    291                final boolean   useTLS          = HybsSystem.sysBool( "MAIL_SEND_USE_STARTTLS" );        // 5.9.29.2(2018/02/16)
    292
    293                final String[] to = StringUtil.csv2Array( HybsSystem.sys( "ERROR_MAIL_TO_USERS" ) );
    294                if( host != null && from != null && to.length > 0 ) {
    295                        final String subject = "SYSTEM_ID=[" + systemId + "] , PARA_KEY=[" + paraKey + "] , "
    296                                                   + "DMN_HOST=[" + HybsSystem.HOST_NAME + "]" ;
    297                        final StringBuilder inErrMsg = new StringBuilder( BUFFER_MIDDLE )
    298                                .append( emList.size() ).append( "件のエラーがありました。" )               // 6.0.2.5 (2014/10/31) char を append する。
    299                                .append( CR );
    300                        for( int i=0; i< emList.size(); i++ ){
    301                                inErrMsg.append( i+1 )
    302                                        .append( "-----" )
    303                                        .append( CR )
    304                                        .append( emList.get( i ) )
    305                                        .append( CR );
    306                        }
    307                        try {
    308                                //MailTX tx = new MailTX( host );
    309//                              final MailTX tx = new MailTX( host, charset, smtpPort, authType, authPort, authUser, authPass, useSSL );        // 6.3.8.0 (2015/09/11)
    310                                final MailTX tx = new MailTX( host, charset, smtpPort, authType, authPort, authUser, authPass, useTLS, useSSL );        // 5.9.29.2
    311                                tx.setFrom( from );
    312                                tx.setTo( to );
    313                                tx.setSubject( "メールモジュール送信エラー：" + subject );
    314                                tx.setMessage( inErrMsg.toString() );
    315                                tx.sendmail();
    316                        }
    317                        catch( final Throwable ex ) {
    318                                final String errMsg = "エラー時メール送信に失敗しました。" + CR
    319                                                        + " SUBJECT:" + subject                                 + CR
    320                                                        + " HOST:" + host                                               + CR
    321                                                        + " FROM:" + from                                               + CR
    322                                                        + " TO:"   + Arrays.toString( to )              + CR
    323                                                        + ex.getMessage();              // 5.1.8.0 (2010/07/01) errMsg 修正
    324                                LogWriter.log( errMsg );
    325                                LogWriter.log( ex );
    326                        }
    327                }
    328        }
    329}