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