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}