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; 008import java.util.HashMap; 009import java.util.List; 010import 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; 018import 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 * パラメータテーブル(GE30)を監視します。 068 * 新規のデータが登録されたら、メール文を合成して送信を行います。 069 * エラーが発生した場合、エラーテーブルにエラーメッセージを書き込みます。 070 * 071 * @og.rev 6.8.5.0 (2018/01/09) PMD Variables that are final and static should be all capitals。selGE30DYSET → SQL_GE30 072 * 073 * @param systemId システムID 074 */ 075 @Override 076 public void sendDBMail( final String systemId ){ 077 // パラメータテーブルよりバッチでセットしたデータを取得します。 078 final String[][] ge30datas = DBUtil.dbExecute( SEL_GE30, new String[]{ systemId, DateSet.getDate( "yyyyMMddHHmmss" ) }, APP_INFO, DBID ); // 5.9.18.0 (2017/03/02) 079 080 // 2017/10/27 ADD SendGrid利用の追加対応 081 String timePre1Hour = ""; 082 // タイムスタンプの設定 083 timePre1Hour = getTimePre1Hour(); 084 085 final int ge30Len = ge30datas.length; 086 087 for( int i=0; i < ge30Len; i++ ) { 088 String fgj = SNED_OK; 089 try { 090 final ConcurrentMap<String, String> initParam = makeParamMap( systemId, ge30datas[i] ); // 5.9.26.0 (2017/11/02) Ver6 091 create( initParam ); 092 send(); // 合成されたメール文書、宛先で送信処理を行います。 093 errMsgList.addAll( getErrList() ); 094 } 095 catch( RuntimeException rex ) { 096 fgj = SNED_NG; 097 errMsgList.add( "メール送信失敗しました。パラメータキー:" + ge30datas[i][GE30_UNIQ] + " " + rex.getMessage() ); 098 } 099 finally { 100 if(fgj != SNED_NG){ 101 commitParamTable( ge30datas[i][GE30_UNIQ], fgj ); 102 }else{ 103 // エラーレコードの登録日時を取得 104 final String[][] rec = DBUtil.dbExecute( SQL_GE30, new String[]{ge30datas[i][GE30_UNIQ]}, APP_INFO, DBID); 105 final String DYSET = rec[0][0]; 106 107 if(DYSET.compareTo(timePre1Hour) < 0){ 108 // 登録から一定時間以上のエラーをエラーに更新 109 commitParamTable( ge30datas[i][GE30_UNIQ], fgj ); 110 } 111 else { 112 // それ以外は再送を試みる 113 commitParamTable( ge30datas[i][GE30_UNIQ], "1" ); 114 115 } 116 } 117 118 if ( ! errMsgList.isEmpty() ) { 119 writeErrorTable( ge30datas[i][GE30_UNIQ], systemId, errMsgList ); 120 errMsgList.clear(); 121 } 122 } 123 } 124 } 125 126 /** 127 * 1時間前のタイムスタンプを取得。 128 * 129 * @return タイムスタンプ(1時間前) 130 */ 131 private String getTimePre1Hour(){ 132 final Date date = new Date(); 133 final Calendar call = Calendar.getInstance(); 134 final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); 135 call.setTime(date); 136 // sendGridが一時的に使えなくなる場合を考慮 137 // 10分間は再送を試みる 138 call.add(Calendar.MINUTE, -10); 139 140 return sdf.format(call.getTime()); 141 } 142 143 // 5.9.26.0 (2017/11/02) とりあえず、拡張jar は入れていません。 144 // /** 145 // * SendGridApiを利用して、メール送信を行うメソッドです。 146 // * 147 // */ 148 // @Override 149 // public void send(){ 150 // // 宛先 151 // List<String> invalidAddrBuf = new ArrayList<String>(); 152 // setMailDst(invalidAddrBuf); 153 // 154 // try{ 155 // SendGrid sg = new SendGrid(SENDGRID_APIKEY); 156 // 157 // Request request = new Request(); 158 // request.setMethod(Method.POST); 159 // request.setEndpoint("mail/send"); 160 // 161 // // SengGrid向けJsonの設定 162 // request.setBody(makeJson()); 163 // 164 // // メール送信要求 165 // sg.api(request); 166 // 167 // // 送信結果を履歴テーブル、宛先テーブルにセットします。 168 // commitMailDB(); 169 // 170 // }catch(IOException e){ 171 // String errMsg = "送信時にエラー発生しました。" + e.getMessage(); 172 // throw new RuntimeException( errMsg,e ); 173 // } 174 // } 175 176 /** 177 * SendGrid向けのJsonを生成します。 178 * @return JSONデータ 179 */ 180 @SuppressWarnings(value={"rawtypes"}) 181 private String makeJson(){ 182 String rtnJson = ""; 183 final Map<Object,Object> jsonMap = new HashMap<Object, Object>(); 184 // 送信先の設定 185 final Map<String,List<Map<String,String>>> sendMap = new HashMap<String,List<Map<String,String>>>(); 186 sendMap.put("to", setSendList(toList)); 187 if(!ccList.isEmpty()){ 188 sendMap.put("cc", setSendList(ccList)); 189 } 190 if(!bccList.isEmpty()){ 191 sendMap.put("bcc", setSendList(bccList)); 192 } 193 jsonMap.put("personalizations", new Map[]{sendMap}); // 警告: [rawtypes] raw型が見つかりました: Map 194 // タイトル 195 jsonMap.put("subject",getTitle()); 196 // 送信元 197 jsonMap.put("from", setMap("email",getFromAddr())); 198 // 内容 199 final Map<String,String> contentMap = new HashMap<String,String>(); 200 contentMap.put("type","text/plain"); 201 contentMap.put("value",getContent()); 202 jsonMap.put("content", new Map[]{contentMap}); // 警告: [rawtypes] raw型が見つかりました: Map 203 204 // 5.9.26.0 (2017/11/02) とりあえず、拡張jar は入れていません。 205/*********** 206 ObjectMapper mapper = new ObjectMapper(); 207 208 try{ 209 rtnJson = mapper.writeValueAsString(jsonMap); 210 }catch(JsonProcessingException e){ 211 String errMsg = "JSONの生成に失敗しました。" + e; 212 throw new HybsSystemException(errMsg); 213 } 214*************/ 215 return rtnJson; 216 } 217 218 /** 219 * Map格納用メソッド。 220 * 221 * @param val1 Mapにセットするキー 222 * @param val2 Mapにセットする値 223 * @return マップ 224 */ 225 private Map<Object,Object> setMap(final Object val1, final Object val2){ 226 final Map<Object,Object> rtnMap = new HashMap<Object,Object>(); 227 rtnMap.put(val1,val2); 228 return rtnMap; 229 } 230 231 /** 232 * メール送信先リストをJSON用リストに設定。 233 * 234 * @param list メール送信先リスト 235 * @return JSON用リスト 236 */ 237 private List<Map<String,String>> setSendList(final List<String> list){ 238 // toリスト 239 final List<Map<String,String>> rtnList = new ArrayList<Map<String,String>>(); 240 for(final String str: list){ 241 final Map<String,String> map = new HashMap<String,String>(); 242 map.put("email", str); 243 rtnList.add(map); 244 } 245 return rtnList; 246 } 247 248 /** 249 * 宛先マップを元に、送信オブジェクトに宛先をセットします。 250 * セットする際に、アカウントエラーとなっているアドレスを除外します。 251 * 宛先が存在しない場合、例外を投げます。 252 * 253 * 計算方法は親クラスのprivateメソッドを流用。 254 * 値はクラス変数のリストに格納するように変更しています。 255 * 256 * @param invalidAddr 宛先のリスト 257 */ 258 private void setMailDst( final List<String> invalidAddr ){ 259 260 final Map<Integer, List<String>> tempMap = new HashMap<Integer, List<String>>(); 261 tempMap.put( Integer.valueOf( MailPattern.KBN_TO ), toList ); 262 tempMap.put( Integer.valueOf( MailPattern.KBN_CC ), ccList ); 263 tempMap.put( Integer.valueOf( MailPattern.KBN_BCC ), bccList ); 264 265 final ConcurrentMap<String, String[]> tmp = getMailDstMap(); 266 for( final String dstId : getMailDstMap().keySet()) { 267 String[] dstInfo = getMailDstMap().get( dstId ); 268 final Integer kbn = Integer.valueOf( dstInfo[MailPattern.IDX_DST_KBN] ); 269 if( !invalidAddr.contains( dstInfo[MailPattern.IDX_DST_ADDR] ) 270 && !FGJ_ADDR_ERR.equals( dstInfo[MailPattern.IDX_FGJ] )){ 271 dstInfo[MailPattern.IDX_FGJ] = FGJ_SEND_OVER; 272 273 final String name = dstInfo[MailPattern.IDX_DST_NAME]; 274 if( name != null && name.length() > 0 ) { 275 tempMap.get( kbn ).add( dstInfo[MailPattern.IDX_DST_NAME] + "<"+ dstInfo[MailPattern.IDX_DST_ADDR] + ">" ); 276 } 277 else { 278 tempMap.get( kbn ).add( dstInfo[MailPattern.IDX_DST_ADDR] ); 279 } 280 } 281 else { 282 if( FGJ_SEND_OVER.equals( dstInfo[MailPattern.IDX_FGJ] ) ) { 283 dstInfo[MailPattern.IDX_FGJ] = FGJ_ACNT_ERR; 284 } 285 } 286 } 287 288 // 宛先が全部無効の場合、例外を投げます 289 if( toList.isEmpty() && ccList.isEmpty() && bccList.isEmpty()){ 290 final String errMsg = "宛先のメールアドレスが有効ではありません。" 291 + "TO , CC , BCC のいづれにもアドレスが設定されていません。"; 292 throw new RuntimeException( errMsg ); 293 } 294 } 295 296 /** 297 * エラーテーブルにエラーメッセージを登録します。 298 * 親のprivateメソッドを流用。エラーメールの送信は行いません。 299 * 300 * @param paraKey パラメータキー(GE36.PARA_KEY) 301 * @param systemId システムID 302 * @param emList エラーメッセージリスト 303 * 304 */ 305 private void writeErrorTable( final String paraKey, final String systemId, final List<String> emList ){ 306 String[] insGE36Args = new String[6]; 307 insGE36Args[GE36_PARA_KEY] = paraKey; 308 insGE36Args[GE36_DYSET] = DateSet.getDate( "yyyyMMddHHmmss" ); 309 insGE36Args[GE36_USRSET] = "DAEMON"; 310 insGE36Args[GE36_PGUPD] = "DAEMON"; 311 insGE36Args[GE36_SYSTEM_ID] = systemId; 312 for( int i=0; i< emList.size(); i++ ){ 313 insGE36Args[GE36_ERRMSG] = trim( emList.get( i ), 4000); 314 DBUtil.dbExecute( INS_GE36, insGE36Args, APP_INFO, DBID ); 315 } 316 } 317}