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 * 1時間前のタイムスタンプを取得。 141 * 142 * @return タイムスタンプ(1時間前) 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}