    001package org.opengion.plugin.cloud;
    002
    003        // import java.io.IOException;                  // 5.9.26.0 (2017/11/02) SendGridApiを利用して、メール送信を行う
    004import java.text.SimpleDateFormat;
    005        // import java.util.ArrayList;
    006import java.util.Calendar;
    007import java.util.Date;
    008// import java.util.HashMap;
    009import java.util.List;
    010// import java.util.Map;
    011import java.util.concurrent.ConcurrentMap;                                              // 5.9.26.0 (2017/11/02) Ver6
    012import java.util.Locale;                                                                                // 7.2.9.4 (2020/11/20)
    013
    014import org.opengion.fukurou.system.DateSet;                                             // 5.9.26.0 (2017/11/02)
    015import org.opengion.fukurou.db.DBUtil;
    016        // import org.opengion.hayabusa.common.HybsSystem;
    017        // import org.opengion.hayabusa.common.HybsSystemException;             // 5.9.26.0 (2017/11/02) SendGridApi
    018import org.opengion.hayabusa.mail.MailManager_DB;
    019// import org.opengion.hayabusa.mail.MailPattern;
    020
    021        // 5.9.26.0 (2017/11/02) とりあえず、拡張jar は入れていません。
    022        // つまり、動きません。
    023        // import com.fasterxml.jackson.core.JsonProcessingException;
    024        // import com.fasterxml.jackson.databind.ObjectMapper;
    025        // import com.sendgrid.Method;
    026        // import com.sendgrid.Request;
    027        // import com.sendgrid.SendGrid;
    028
    029/**
    030 * パッチによるメール送信の実装クラスです。
    031 * 送信デーモンはパラメータテーブル(GE30)を監視して、新規のデータが登録されたら、
    032 * そのデータをパラメータとしてメール合成処理メソッドに渡して合成を行って送信します。
    033 * 最後に、処理結果を受取って、パラメータテーブルの状況フラグを送信済/送信エラーに更新します。
    034 * エラーが発生した場合、エラーテーブルにエラーメッセージを書き込みます。
    035 *
    036 * hayabusa.mailの標準クラスを継承して作成しています。
    037 * 基本的な動作は同じですが、メール送信にSMTPではなくsendGridのAPIを利用します。
    038 * MAIL_SENDGRID_APIKEYをシステムリソースとして登録する必要があります。
    039 *
    040 * 一時的に利用できなくなる事を想定して、
    041 * 一定時間の間（ハードコーディングで10分としている）はエラーが発生しても再送を試みるようにします。
    042 *
    043 * このクラスをコンパイルするためにはsendgrid-java-4.1.1.jar,java-http-client-4.1.0.jarが必要です。
    044 * 実行にはhamcrest-core-1.1.jar,httpclient-4.5.2.jar,httpcore-4.4.4.jar,mockito-core-1.10.19.jar,objenesis-2.1.jar
    045 * ,jackson-annotations-2.5.3.jar,jackson-core-2.5.3.jar,jackson-databind-2.5.3.jarが必要です。
    046 *
    047 * @og.group    メールモジュール
    048 *
    049 * @og.rev 5.9.26.0 (2017/11/02) 新規作成
    050 * @author              T.OTA
    051 * @since               JDK1.7
    052 *
    053 */
    054public class MailManager_DB_SendGridAPI extends MailManager_DB {
    055        // 6.8.5.0 (2018/01/09) PMD Variables that are final and static should be all capitals。selGE30DYSET → SQL_GE30
    056        private static final String     SQL_GE30        = "SELECT DYSET FROM GE30 WHERE UNIQ = ?";      // 2017/10/27 ADD 登録時刻の取得
    057//      // SendGridのAPIキー
    058//      private static final String SENDGRID_APIKEY = HybsSystem.sys("MAIL_SENDGRID_APIKEY");
    059//      // メール送信先のtoリスト
    060//      private final List<String> toList = new ArrayList<String>();
    061//      // メール送信先のccリスト
    062//      private final List<String> ccList = new ArrayList<String>();
    063//      // メール送信先のbccリスト
    064//      private final List<String> bccList = new ArrayList<String>();
    065
    066        /**
    067         * デフォルトコンストラクター
    068         *
    069         * @og.rev 6.9.7.0 (2018/05/14) PMD Each class should declare at least one constructor
    070         */
    071        public MailManager_DB_SendGridAPI() { super(); }                // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    072
    073        /**
    074         * バッチより呼出のメインメソッドです。
    075         * パラメータテーブル(GE30)を監視します。
    076         * 新規のデータが登録されたら、メール文を合成して送信を行います。
    077         * エラーが発生した場合、エラーテーブルにエラーメッセージを書き込みます。
    078         *
    079         * @og.rev 6.8.5.0 (2018/01/09) PMD Variables that are final and static should be all capitals。selGE30DYSET → SQL_GE30
    080         * @og.rev 7.2.9.4 (2020/11/20) PMD:Avoid if (x != y) ..; else ..;
    081         *
    082         * @param systemId システムID
    083         */
    084        @Override
    085        public void sendDBMail( final String systemId ){
    086                // パラメータテーブルよりバッチでセットしたデータを取得します。
    087                final String[][] ge30datas = DBUtil.dbExecute( SEL_GE30, new String[]{ systemId, DateSet.getDate( "yyyyMMddHHmmss" ) }, APP_INFO, DBID );               // 5.9.18.0 (2017/03/02)
    088
    089                // 2017/10/27 ADD SendGrid利用の追加対応
    090                String timePre1Hour = "";
    091                // タイムスタンプの設定
    092                timePre1Hour = getTimePre1Hour();
    093
    094                final int ge30Len = ge30datas.length;
    095
    096                for( int i=0; i < ge30Len; i++ ) {
    097                        String fgj = SNED_OK;
    098                        try {
    099                                final ConcurrentMap<String, String> initParam = makeParamMap( systemId, ge30datas[i] );                 // 5.9.26.0 (2017/11/02) Ver6
    100                                create( initParam );
    101                                send();                                                         // 合成されたメール文書、宛先で送信処理を行います。
    102                                errMsgList.addAll( getErrList() );
    103                        }
    104                        catch( final RuntimeException rex ) {
    105                                fgj = SNED_NG;
    106                                errMsgList.add( "メール送信失敗しました。パラメータキー：" + ge30datas[i][GE30_UNIQ] + " " + rex.getMessage() );
    107                        }
    108                        finally {
    109        //                      if(fgj != SNED_NG){
    110        //                              commitParamTable( ge30datas[i][GE30_UNIQ], fgj );
    111        //                      }else{
    112
    113                                // 7.2.9.4 (2020/11/20) PMD:Avoid if (x != y) ..; else ..;
    114                                if( SNED_NG.equals(fgj ) ){
    115                                        // エラーレコードの登録日時を取得
    116                                        final String[][] rec = DBUtil.dbExecute( SQL_GE30, new String[]{ge30datas[i][GE30_UNIQ]}, APP_INFO, DBID);
    117                                        final String DYSET = rec[0][0];
    118
    119                                        if(DYSET.compareTo(timePre1Hour) < 0){
    120                                                // 登録から一定時間以上のエラーをエラーに更新
    121                                                commitParamTable( ge30datas[i][GE30_UNIQ], fgj );
    122                                        }
    123                                        else {
    124                                                // それ以外は再送を試みる
    125                                                commitParamTable( ge30datas[i][GE30_UNIQ], "1" );
    126                                        }
    127                                }else{
    128                                        commitParamTable( ge30datas[i][GE30_UNIQ], fgj );
    129                                }
    130
    131                                if ( ! errMsgList.isEmpty() ) {
    132                                        writeErrorTable( ge30datas[i][GE30_UNIQ], systemId, errMsgList );
    133                                        errMsgList.clear();
    134                                }
    135                        }
    136                }
    137        }
    138
    139        /**
    140         * １時間前のタイムスタンプを取得。
    141         *
    142         * @return タイムスタンプ(１時間前)
    143         */
    144        private String getTimePre1Hour(){
    145                final Date date = new Date();
    146                final Calendar call = Calendar.getInstance();
    147//              final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
    148                final SimpleDateFormat sdf = new SimpleDateFormat( "yyyyMMddHHmmss",Locale.JAPAN );             // 7.2.9.4 (2020/11/20)
    149                call.setTime(date);
    150                // sendGridが一時的に使えなくなる場合を考慮
    151                // 10分間は再送を試みる
    152                call.add(Calendar.MINUTE, -10);
    153
    154                return sdf.format(call.getTime());
    155        }
    156
    157        // 5.9.26.0 (2017/11/02) とりあえず、拡張jar は入れていません。
    158        //      /**
    159        //       * SendGridApiを利用して、メール送信を行うメソッドです。
    160        //       *
    161        //       */
    162        //      @Override
    163        //      public void send(){
    164        //              // 宛先
    165        //              List<String> invalidAddrBuf     = new ArrayList<String>();
    166        //              setMailDst(invalidAddrBuf);
    167        //
    168        //              try{
    169        //                      SendGrid sg = new SendGrid(SENDGRID_APIKEY);
    170        //
    171        //                      Request request = new Request();
    172        //                      request.setMethod(Method.POST);
    173        //                      request.setEndpoint("mail/send");
    174        //
    175        //                      // SengGrid向けJsonの設定
    176        //                      request.setBody(makeJson());
    177        //
    178        //                      // メール送信要求
    179        //                      sg.api(request);
    180        //
    181        //                      // 送信結果を履歴テーブル、宛先テーブルにセットします。
    182        //                      commitMailDB();
    183        //
    184        //              }catch(IOException e){
    185        //                      String errMsg = "送信時にエラー発生しました。" + e.getMessage();
    186        //                      throw new RuntimeException( errMsg,e );
    187        //              }
    188        //      }
    189
    190//      /**
    191//       * SendGrid向けのJsonを生成します。
    192//       *
    193//       * @og.rev 6.9.8.0 (2018/05/28) FindBugs:private メソッドは決して呼び出されない
    194//       *
    195//       * @return JSONデータ
    196//       */
    197//      @SuppressWarnings(value={"rawtypes"})
    198//      private String makeJson(){
    199//              String rtnJson = "";
    200//              final Map<Object,Object> jsonMap = new HashMap<Object, Object>();
    201//              // 送信先の設定
    202//              final Map<String,List<Map<String,String>>> sendMap = new HashMap<String,List<Map<String,String>>>();
    203//              sendMap.put("to", setSendList(toList));
    204//              if(!ccList.isEmpty()){
    205//                      sendMap.put("cc", setSendList(ccList));
    206//              }
    207//              if(!bccList.isEmpty()){
    208//                      sendMap.put("bcc",  setSendList(bccList));
    209//              }
    210//              jsonMap.put("personalizations", new Map[]{sendMap});                    // 警告: [rawtypes] raw型が見つかりました: Map
    211//              // タイトル
    212//              jsonMap.put("subject",getTitle());
    213//              // 送信元
    214//              jsonMap.put("from", setMap("email",getFromAddr()));
    215//              // 内容
    216//              final Map<String,String> contentMap = new HashMap<String,String>();
    217//              contentMap.put("type","text/plain");
    218//              contentMap.put("value",getContent());
    219//              jsonMap.put("content", new Map[]{contentMap});                                  // 警告: [rawtypes] raw型が見つかりました: Map
    220//
    221//              // 5.9.26.0 (2017/11/02) とりあえず、拡張jar は入れていません。
    222///***********
    223//      //      ObjectMapper mapper = new ObjectMapper();
    224//      //
    225//      //      try{
    226//      //              rtnJson = mapper.writeValueAsString(jsonMap);
    227//      //      }catch(JsonProcessingException e){
    228//      //              String errMsg = "JSONの生成に失敗しました。" + e;
    229//      //              throw new HybsSystemException(errMsg);
    230//      //      }
    231//*************/
    232//              return rtnJson;
    233//      }
    234
    235//      /**
    236//       * Map格納用メソッド。
    237//       *
    238//       * @og.rev 6.9.8.0 (2018/05/28) FindBugs:private メソッドは決して呼び出されない
    239//       *
    240//       * @param val1 Mapにセットするキー
    241//       * @param val2 Mapにセットする値
    242//       * @return マップ
    243//       */
    244//      private Map<Object,Object> setMap(final Object val1, final Object val2){
    245//              final Map<Object,Object> rtnMap = new HashMap<Object,Object>();
    246//              rtnMap.put(val1,val2);
    247//              return rtnMap;
    248//      }
    249
    250//      /**
    251//       * メール送信先リストをJSON用リストに設定。
    252//       *
    253//       * @og.rev 6.9.8.0 (2018/05/28) FindBugs:private メソッドは決して呼び出されない
    254//       *
    255//       * @param list メール送信先リスト
    256//       * @return JSON用リスト
    257//       */
    258//      private List<Map<String,String>> setSendList(final List<String> list){
    259//              // toリスト
    260//              final List<Map<String,String>> rtnList = new ArrayList<Map<String,String>>();
    261//              for(final String str: list){
    262//                      final Map<String,String> map = new HashMap<String,String>();
    263//                      map.put("email", str);
    264//                      rtnList.add(map);
    265//              }
    266//              return rtnList;
    267//      }
    268
    269//      /**
    270//       * 宛先マップを元に、送信オブジェクトに宛先をセットします。
    271//       * セットする際に、アカウントエラーとなっているアドレスを除外します。
    272//       * 宛先が存在しない場合、例外を投げます。
    273//       *
    274//       * 計算方法は親クラスのprivateメソッドを流用。
    275//       * 値はクラス変数のリストに格納するように変更しています。
    276//       *
    277//       * @og.rev 6.9.8.0 (2018/05/28) FindBugs:private メソッドは決して呼び出されない
    278//       *
    279//       * @param invalidAddr 宛先のリスト
    280//       */
    281//      private void setMailDst( final List<String> invalidAddr ){
    282//
    283//              final Map<Integer, List<String>> tempMap = new HashMap<Integer, List<String>>();
    284//              tempMap.put( Integer.valueOf( MailPattern.KBN_TO ),  toList );
    285//              tempMap.put( Integer.valueOf( MailPattern.KBN_CC ),  ccList );
    286//              tempMap.put( Integer.valueOf( MailPattern.KBN_BCC ), bccList );
    287//
    288////            final ConcurrentMap<String, String[]> tmp = getMailDstMap();
    289//              for( final String dstId : getMailDstMap().keySet()) {
    290//                      String[] dstInfo = getMailDstMap().get( dstId );
    291//                      final Integer kbn = Integer.valueOf( dstInfo[MailPattern.IDX_DST_KBN] );
    292//                      if( !invalidAddr.contains( dstInfo[MailPattern.IDX_DST_ADDR] )
    293//                                      && !FGJ_ADDR_ERR.equals( dstInfo[MailPattern.IDX_FGJ] )){
    294//                              dstInfo[MailPattern.IDX_FGJ] = FGJ_SEND_OVER;
    295//
    296//                              final String name = dstInfo[MailPattern.IDX_DST_NAME];
    297//                              if( name != null && name.length() > 0 ) {
    298//                                      tempMap.get( kbn ).add( dstInfo[MailPattern.IDX_DST_NAME] +  "<"+ dstInfo[MailPattern.IDX_DST_ADDR] + ">" );
    299//                              }
    300//                              else {
    301//                                      tempMap.get( kbn ).add( dstInfo[MailPattern.IDX_DST_ADDR] );
    302//                              }
    303//                      }
    304//                      else {
    305//                              if( FGJ_SEND_OVER.equals( dstInfo[MailPattern.IDX_FGJ] ) ) {
    306//                                      dstInfo[MailPattern.IDX_FGJ] = FGJ_ACNT_ERR;
    307//                              }
    308//                      }
    309//              }
    310//
    311//              // 宛先が全部無効の場合、例外を投げます
    312//              if( toList.isEmpty() && ccList.isEmpty() && bccList.isEmpty()){
    313//                      final String errMsg = "宛先のメールアドレスが有効ではありません。"
    314//                                      + "TO , CC , BCC のいづれにもアドレスが設定されていません。";
    315//                      throw new RuntimeException( errMsg );
    316//              }
    317//      }
    318
    319        /**
    320         * エラーテーブルにエラーメッセージを登録します。
    321         * 親のprivateメソッドを流用。エラーメールの送信は行いません。
    322         *
    323         * @param       paraKey         パラメータキー(GE36.PARA_KEY)
    324         * @param       systemId        システムID
    325         * @param       emList          エラーメッセージリスト
    326         *
    327         */
    328        private void writeErrorTable( final String paraKey, final String systemId, final List<String> emList ){
    329                String[] insGE36Args = new String[6];
    330                insGE36Args[GE36_PARA_KEY]      = paraKey;
    331                insGE36Args[GE36_DYSET]         = DateSet.getDate( "yyyyMMddHHmmss" );
    332                insGE36Args[GE36_USRSET]        = "DAEMON";
    333                insGE36Args[GE36_PGUPD]         = "DAEMON";
    334                insGE36Args[GE36_SYSTEM_ID] = systemId;
    335                // 7.2.9.4 (2020/11/20) PMD:This for loop can be replaced by a foreach loop
    336                for( final String elm : emList ){
    337                        insGE36Args[GE36_ERRMSG] = trim( elm, 4000);
    338//              for( int i=0; i< emList.size(); i++ ){
    339//                      insGE36Args[GE36_ERRMSG] = trim( emList.get( i ), 4000);
    340                        DBUtil.dbExecute( INS_GE36, insGE36Args, APP_INFO, DBID );
    341                }
    342        }
    343}