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