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.hayabusa.mail;
017
018import java.util.List;
019import java.util.ArrayList;
020import java.util.HashMap;
021import java.util.Map;
022import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
023import java.util.concurrent.ConcurrentHashMap;                                          // 8.5.7.0 (2024/03/29)
024import java.util.stream.Collectors;                                                                     // 6.4.1.1 (2016/01/16)
025
026import jakarta.mail.Address;
027import jakarta.mail.SendFailedException;
028import jakarta.mail.internet.InternetAddress;
029
030import org.opengion.fukurou.system.OgRuntimeException ;                         // 6.4.2.0 (2016/01/29)
031import org.opengion.fukurou.system.DateSet;                                                     // 6.4.2.0 (2016/01/29)
032import org.opengion.fukurou.util.StringUtil;                                            // 5.9.1.3 (2015/10/30)
033import org.opengion.fukurou.db.DBUtil;
034import org.opengion.fukurou.db.ApplicationInfo;
035import org.opengion.fukurou.db.ConnectionFactory;                                       // 5.9.26.0 (2017/11/02)
036import org.opengion.fukurou.db.Transaction;                                                     // 5.9.26.0 (2017/11/02)
037import org.opengion.fukurou.db.TransactionReal;                                         // 5.9.26.0 (2017/11/02)
038import org.opengion.fukurou.db.DBFunctionName;                                          // 5.9.26.0 (2017/11/02)
039import org.opengion.fukurou.mail.MailTX;
040import static org.opengion.fukurou.util.StringUtil.nval;
041import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
042
043import org.opengion.hayabusa.common.HybsSystem;
044
045/**
046 * タグ mailSender2 及びバッチによる送信の共通処理部分を実装しています。
047 * 送信タグ mailSender2 もしくは送信デーモンからパラメータを受取ります。
048 * パラメータ中の定型文ID及びシステムIDで定型文マスタよりメールの定型文を取得して、
049 * パラメータ値とマージしてメール文を合成します。同時に、宛先にセットした社員ID、
050 * グループIDと定型文の宛先設定に基づき、社員マスタとグループマスタよりメールアドレス
051 * 情報を取得して送信を行います。
052 * エラーがなければ送信した内容を履歴テーブル、宛先テーブルに書き込みます。
053 * 最後に本処理の呼出元に送信結果、エラーメッセージを返します。
054 *
055 * @og.group メールモジュール
056 *
057 * @version  4.0
058 * @author   Sen.Li
059 * @since    JDK1.6
060 */
061public class DefaultMailManager {
062//      // 5.2.0.0 (2010/09/01) Ver4互換モード対応
063//      // 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
064//      private static final String CONTENTS = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "CONTENT" : "CONTENTS";
065
066        // 5.9.26.0 (2017/11/02) DB共通化のため、DBFunctionNameを使用して、シーケンスを取得するように変更
067
068        // 5.0.3.0 (2009/11/04) CONTENT ⇒ CONTENTS
069        // 5.2.0.0 (2010/09/01) Ver4互換モード対応
070        // 6.4.1.1 (2016/01/16) insGE32 → INS_GE32 , insGE34 → INS_GE34 refactoring
071        // 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
072//      private static final String     INS_GE32                = "INSERT INTO GE32(YKNO,PARA_KEY,PTN_ID,FROM_ADDR,TITLE,"+CONTENTS+",ATTACH1,ATTACH2,ATTACH3,ATTACH4,ATTACH5,DYSET,USRSET,PGUPD,SYSTEM_ID,FGJ)"
073        // 送信後履歴テーブル(GE32)
074        private static final String     INS_GE32                = "INSERT INTO GE32(YKNO,PARA_KEY,PTN_ID,FROM_ADDR,TITLE,CONTENTS,ATTACH1,ATTACH2,ATTACH3,ATTACH4,ATTACH5,DYSET,USRSET,PGUPD,SYSTEM_ID,FGJ)"
075                                                                                        + " VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,'1')";
076        // 宛先テーブル(GE34)
077        private static final String INS_GE34            = "INSERT INTO GE34(YKNO,DST_ID,GROUP_ID,DST_NAME,DST_ADDR,DST_KBN,FGJ,DYSET,USRSET,PGUPD)"
078                                                                                        + " VALUES(?,?,?,?,?,?,?,?,?,?)";
079        /** GE34(宛先テーブル) FGJ 送信待 {@value} */
080        protected static final String FGJ_SEND_WAIT     = "0";
081        /** GE34(宛先テーブル) FGJ 送信済 {@value} */
082        protected static final String FGJ_SEND_OVER     = "1";
083        /** GE34(宛先テーブル) FGJ アドレス取得エラー {@value} */
084        protected static final String FGJ_ADDR_ERR      = "7";
085        /** GE34(宛先テーブル) FGJ メールアカウントエラー {@value} */
086        protected static final String FGJ_ACNT_ERR      = "8";
087
088        /** 送信履歴テーブル(GE32) */
089        private static final int GE32_YKNO              = 0 ;
090        private static final int GE32_PARAKEY   = 1 ;
091        private static final int GE32_PTN_ID    = 2;
092        private static final int GE32_FROM_ADDR = 3;
093        private static final int GE32_TITLE             = 4;
094        private static final int GE32_CONTENTS  = 5;            // 5.0.3.0 (2009/11/04) CONTENT ⇒ CONTENTS
095        private static final int GE32_ATTACH1   = 6;
096        private static final int GE32_ATTACH2   = 7;
097        private static final int GE32_ATTACH3   = 8;
098        private static final int GE32_ATTACH4   = 9;
099        private static final int GE32_ATTACH5   = 10;
100        private static final int GE32_DYSET             = 11;
101        private static final int GE32_USRSET    = 12;
102        private static final int GE32_PGUPD             = 13;
103        private static final int GE32_SYSTEM_ID = 14;
104        /** 宛先テーブル(GE34) */
105        private static final int GE34_YKNO              = 0 ;
106        private static final int GE34_DST_ID    = 1 ;
107        private static final int GE34_GROUP_ID  = 2 ;
108        private static final int GE34_DST_NAME  = 3 ;
109        private static final int GE34_DST_ADDR  = 4 ;
110        private static final int GE34_DST_KBN   = 5 ;
111        private static final int GE34_FGJ               = 6 ;
112        private static final int GE34_DYSET             = 7 ;
113        private static final int GE34_USRSET    = 8 ;
114        private static final int GE34_PGUPD             = 9 ;
115 //     private static String           host            = HybsSystem.sys( "COMMON_MAIL_SERVER" );
116        private static String           charset         = HybsSystem.sys( "MAIL_DEFAULT_CHARSET" );
117 //     private static String           smtpPort        = HybsSystem.sys( "SMTP_PORT" );                                // 5.4.3.2 (2012/01/06)
118 //     private static String           auth            = HybsSystem.sys( "MAIL_SEND_AUTH" );                   // 5.4.3.2 (2012/01/06)
119 //     private static String           authUser        = HybsSystem.sys( "MAIL_SEND_AUTH_USER" );              // 5.4.3.2 (2012/01/06)
120 //     private static String           authPass        = HybsSystem.sys( "MAIL_SEND_AUTH_PASSWORD" );  // 5.4.3.2 (2012/01/06)
121        private boolean                         debugFlag       ;
122        private final List<String>      errAddrList     = new ArrayList<>();
123        private static final int MAX_RETRY              = 3 ;   // メールアドレスエラー発生した場合、メール再送回数
124
125        /** 5.6.6.0 (2013/07/05) host等の外部指定に対応 */
126        private String          host            = HybsSystem.sys( "COMMON_MAIL_SERVER" );               // 5.6.6.0 (2013/07/05)
127        private String          smtpPort        = HybsSystem.sys( "SMTP_PORT" );                                // 5.6.6.0 (2013/07/05)
128        private String          authType        = HybsSystem.sys( "MAIL_SEND_AUTH" );                   // 6.0.3.0 (2014/11/13) Ver6用キーワード変更
129        private String          authPort        = HybsSystem.sys( "MAIL_SEND_AUTH_PORT" );              // 5.8.1.1 (2014/11/14)
130        private String          authUser        = HybsSystem.sys( "MAIL_SEND_AUTH_USER" );              // 5.6.6.0 (2013/07/05)
131        private String          authPass        = HybsSystem.sys( "MAIL_SEND_AUTH_PASSWORD" );  // 5.6.6.0 (2013/07/05)
132        private boolean         useTLS          = HybsSystem.sysBool( "MAIL_SEND_USE_STARTTLS" );        // 5.9.29.2(2018/02/16) キーワードをVer5 にあわせます。
133
134        private final boolean useSSL    = HybsSystem.sysBool( "MAIL_SEND_USE_SSL" );    // 6.3.8.0 (2015/09/11)
135
136        // 8.5.4.2 (2024/01/12) PMD 7.0.0 OneDeclarationPerLine
137//      private String  mailTitle, mailContent, fromAddr;
138        private String  mailTitle;
139        private String  mailContent;
140        private String  fromAddr;
141
142        /** 添付ファイルをセットします(最大5個まで) */
143        private String[] attachFiles;
144
145        /** 6.4.3.1 (2016/02/12) 作成元のMapを、HashMap から ConcurrentHashMap に置き換え。 */
146        private ConcurrentMap<String, String[]> mailDstMap              ;               // 6.4.3.3 (2016/03/04)
147//      /** 6.4.3.1 (2016/02/12) 作成元のMapを、HashMap から ConcurrentHashMap に置き換え。 */
148        // 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。
149//      private ConcurrentMap<String,String>    initParamMap    ;               // パラメータマップ
150        /** 8.5.7.0 (2024/03/29) サブクラスからアクセスできるように、protected に変更 */
151        protected final ConcurrentMap<String, String> initParamMap = new ConcurrentHashMap<>();                 // パラメータマップ
152
153        /** リソース系DBID */
154        protected final String DBID = HybsSystem.sys( "RESOURCE_DBID" );                // 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対応
155
156        /** コネクションにアプリケーション情報を追記するかどうか指定 */
157        private static final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;
158
159        /** ファンクション名オブジェクト */
160        private final DBFunctionName dbName = DBFunctionName.getDBName( ConnectionFactory.getDBName( DBID ) );  // 5.9.31.1 (2018/04/13)
161
162        /** 要求番号の取得用のシーケンス */
163//      private static final String     SEL_YKNO        = "SELECT GE32S02.NEXTVAL YKNO FROM DUAL";
164        private static final String     SEL_YKNO        = "GE32S02";            // 5.9.31.1 (2018/04/13)
165
166        /** アプリケーション情報 */
167        // 6.4.1.1 (2016/01/16) DefaultMailManager.appInfo → DefaultMailManager.APP_INFO refactoring
168        protected static final ApplicationInfo APP_INFO;
169        static {
170                if( USE_DB_APPLICATION_INFO ) {
171                        APP_INFO = new ApplicationInfo();
172                        // ユーザーID,IPアドレス,ホスト名
173                        APP_INFO.setClientInfo( "MailModuel", HybsSystem.HOST_ADRS, HybsSystem.HOST_NAME );
174                        // 画面ID,操作,プログラムID
175                        APP_INFO.setModuleInfo( "MailModuel", "MailManager", "MailManager" );
176                }
177                else {
178                        APP_INFO = null;
179                }
180        }
181
182        private MailTX mail ;
183
184        /**
185         * デフォルトコンストラクター
186         *
187         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
188         */
189        public DefaultMailManager() { super(); }                // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
190
191        /**
192         * 呼出元よりパラメータマップを受取って、メールオブジェクト(mailObj)を作成します。
193         * メールオブジェクトは定型文ID及びシステムIDに基づいて定型文マスタからメールの定型文を取得して、
194         * パラメータ値とマージしてメール文の各項目を合成します。
195         * 宛先については、宛先にセットした社員ID、グループIDと定型文の宛先設定に基づき、社員マスタとグループマスタ
196         * よりメールアドレスを取得して宛先マップを作成します。
197         * まだ、添付ファイルのセット処理も行っています。
198         *
199         * @og.rev 5.6.6.0 (2013/07/05) host等の外部設定対応
200         * @og.rev 6.0.3.0 (2014/11/13) Ver6用キーワード変更
201         * @og.rev 6.4.3.1 (2016/02/12) 作成元のMapを、HashMap から ConcurrentHashMap に置き換え。
202         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。
203         * @og.rev 5.9.15.1 (2016/12/09) エラーリストのクリア
204         * @og.rev 5.9.29.2 (2018/02/16) STARTTLS対応(キーワードをVer5 にあわせます)
205         * @og.rev 8.5.7.0 (2024/03/29) initParamMap をメソッドで処理し、attachFiles を設定する。
206         *
207         * @param       params  パラメータのマップ
208         */
209        public void create( final ConcurrentMap<String, String> params ) {
210                setInitParams( params );                                                                                // 8.5.7.0 (2024/03/29)
211//              initParamMap = params;                                                                                  // 6.4.3.1 (2016/02/12)
212                final MailPattern mailObj = new MailPattern( params );
213                fromAddr = mailObj.getFromAddr();
214//              setAttachFiles( params.get( "ATTACH1" )                                                 // 8.5.7.0 (2024/03/29) setInitParams へ
215//                                        , params.get( "ATTACH2" )
216//                                        , params.get( "ATTACH3" )
217//                                        , params.get( "ATTACH4" )
218//                                        , params.get( "ATTACH5" ) );                                          // 添付ファイルのセット
219                mailDstMap      = mailObj.getDstMap();                                                          // 6.4.3.1 (2016/02/12)
220                mailTitle       = mailObj.getTitle();
221                mailContent = mailObj.getContent();
222                errAddrList.clear();                                                                                    // 5.9.15.1 (2016/12/09)
223                errAddrList.addAll( mailObj.getErrList() );
224
225                // 5.6.6.0 (2013/07/05)
226                host            = nval( mailObj.getHost()               ,host           );
227                smtpPort        = nval( mailObj.getSmtpPort()   ,smtpPort       );
228                authType        = nval( mailObj.getAuthType()   ,authType       );              // 6.0.3.0 (2014/11/13) Ver6用キーワード変更
229                authPort        = nval( mailObj.getAuthPort()   ,authPort       );              // 5.8.1.1 (2014/11/14)
230                authUser        = nval( mailObj.getAuthUser()   ,authUser       );
231                authPass        = nval( mailObj.getAuthPass()   ,authPass       );
232//              useTLS          = mailObj.getUseTLS();                  // 5.9.29.2 (2018/02/13)
233                useTLS          = HybsSystem.sysBool( "MAIL_SEND_USE_STARTTLS" );        // 5.9.29.2(2018/02/16) キーワードをVer5 にあわせます。
234        }
235
236        /**
237         * メール送信を行うメソッドです。
238         * createメソッドより合成した内容で送信を行います。アドレスエラー発生時に、
239         * ユーザー設定(addrCheck)により再送/中止します。
240         * メールサーバーに送信して、例外"SendFailedException"をキャッチできたら、
241         * メールアカウントがエラーとなるのを分かります。そして、例外のオブジェクトから
242         * エラーとなっているアカウントを取得して宛先マップから除外して、残りのアドレスに再送できます。
243         * 送信後履歴テーブル(GE32)、宛先テーブル(GE34)に送信結果を書き込みます。
244         *
245         * @og.rev 5.4.3.2 (2012/01/06) 送信時認証対応
246         * @og.rev 6.0.3.0 (2014/11/13) Ver6用キーワード変更
247         * @og.rev 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。
248         * @og.rev 5.9.29.2 (2018/02/16) STARTTLS対応(キーワードをVer5 にあわせます)
249         */
250        public void send() {
251                final List<String> invalidAddrBuf       = new ArrayList<>();
252                // mail = new MailTX( host, charset );
253//              mail = new MailTX( host, charset, smtpPort, authType, authPort,authUser, authPass , useSSL );                   // 6.3.8.0 (2015/09/11) SSL接続対応
254                mail = new MailTX( host, charset, smtpPort, authType, authPort,authUser, authPass, useTLS , useSSL );   // 5.9.29.2 (2019/02/16)
255                mail.setFrom( fromAddr );                       // 送信者アドレス
256                mail.setFilename( attachFiles );        // 添付ファイルをセットします。
257                mail.setSubject( mailTitle );           // メールタイトル
258                mail.setMessage( mailContent );         // メール本文
259                mail.setDebug( debugFlag );
260                setMailDst( invalidAddrBuf );           // 宛先をセットします。
261
262                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid instantiating new objects inside loops
263                // 実際は、エラー処理の中で作成しているだけなので、外に出す必要性は、薄い。
264                final StringBuilder errMsgBuf = new StringBuilder( BUFFER_MIDDLE );
265
266                // メール送信を行います。
267                int retryCount = MAX_RETRY;
268                while( retryCount > 0 ) {
269                        try {
270                                mail.sendmail();
271                        }
272                        catch( final RuntimeException rex ) {
273                                final Throwable cause = rex.getCause();
274                                if( cause instanceof SendFailedException ) {
275                                        final Address[] invAddress = ( (SendFailedException) cause ).getInvalidAddresses();
276                                        if( invAddress != null ) {
277                                                final int invCount = invAddress.length;
278                                                for( int i=0; i<invCount; i++ ) {
279                                                        invalidAddrBuf.add( ( (InternetAddress) invAddress[i] ).getAddress() );
280                                                }
281                                        }
282                                }
283                                else {
284                                        final String errMsg = "送信時にエラー発生しました。" + rex.getMessage();
285                                        throw new OgRuntimeException( errMsg,rex );
286                                }
287                        }
288
289                        if( invalidAddrBuf.isEmpty() ) {
290                                retryCount = -1;
291                        }
292                        else {
293                                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid instantiating new objects inside loops
294
295                                errMsgBuf.setLength(0);                         // new StringBuilder の代わり。
296                                final String errMsg = errMsgBuf.append( "アドレスエラー。ユーザーID:" )
297                                                                                                .append( getUserIds( invalidAddrBuf ) )
298                                                                                                .append( " アドレス:" )
299                                                                                                .append( invalidAddrBuf.stream().collect( Collectors.joining( "," ) ) )
300                                                                                                .toString();
301
302                                if( "true".equals( initParamMap.get( "ADDR_CHECK" ) ) ){
303                                        throw new OgRuntimeException( errMsg );
304                                }
305                                else {
306                                        // メールアカウントチェックしない場合、無効のメールアドレスを除いて再送します。
307                                        setMailDst( invalidAddrBuf );
308                                        retryCount--;
309                                        invalidAddrBuf.clear();
310                                        errAddrList.add( errMsg );
311                                }
312                        }
313                }
314                commitMailDB();         // 送信結果を履歴テーブル、宛先テーブルにセットします。
315        }
316
317        /**
318         * デバッグ情報の表示を行うかどうか[true/false]をセットします。
319         *
320         * @param   debug  [true:出力する/それ以外:しない]
321         */
322        public void setDebug( final boolean debug ) {
323                debugFlag = debug;
324        }
325
326        /**
327         * メール送信者アドレスをセットします。
328         *
329         * @param  from 送信者アドレス
330         */
331        public void setFromAddr( final String from ) {
332                fromAddr = from;
333        }
334
335        /**
336         * メールタイトルをセットします。
337         *
338         * @param  title メールタイトル
339         */
340        public void setTitle( final String title ) {
341                mailTitle = title;
342        }
343
344        /**
345         * メール本文をセットします。
346         *
347         * @param  content メール本文
348         */
349        public void setContent( final String content ) {
350                mailContent = content;
351        }
352
353        /**
354         * メール送信ホストをセットします。
355         * 初期値は、システム定数のCOMMON_MAIL_SERVER を使用します。
356         *
357         * (初期値:システム定数のCOMMON_MAIL_SERVER[={@og.value SystemData#COMMON_MAIL_SERVER}])。
358         *
359         * @og.rev 5.6.6.0 (2013/07/05)
360         *
361         * @param  hostName 送信ホスト
362         */
363        public void setHost( final String hostName ) {
364                host = nval( hostName, host );
365        }
366
367        /**
368         * メール送信ポート番号をセットします。
369         * 初期値は、システム定数のSMTP_PORT を使用します。
370         *
371         * (初期値:システム定数のSMTP_PORT[={@og.value SystemData#SMTP_PORT}])。
372         *
373         * @og.rev 5.6.6.0 (2013/07/05)
374         *
375         * @param  port SMTPポート
376         */
377        public void setPort( final String port ) {
378                smtpPort = nval( port, smtpPort );
379        }
380
381        /**
382         * メール送信時認証有無をセットします。
383         * 認証を行う場合は「POP_BEFORE_SMTP」と指定して下さい。
384         * 認証時には認証ユーザと認証パスワードを設定する必要があります。
385         * 初期値は、システム定数のMAIL_SEND_AUTH を使用します。
386         *
387         * (初期値:システム定数のMAIL_SEND_AUTH[={@og.value SystemData#MAIL_SEND_AUTH}])。
388         *
389         * @og.rev 6.0.3.0 (2014/11/13) Ver6用キーワード変更
390         *
391         * @param  type 認証方式
392         */
393        public void setAuthType( final String type ) {
394                authType = nval( type, authType );
395        }
396
397        /**
398         * メール送信認証ユーザをセットします。
399         * 初期値は、システム定数のMAIL_SEND_AUTH_USER を使用します。
400         *
401         * (初期値:システム定数のMAIL_SEND_AUTH_USER[={@og.value SystemData#MAIL_SEND_AUTH_USER}])。
402         *
403         * @og.rev 5.6.6.0 (2013/07/05)
404         *
405         * @param  user 認証ユーザ
406         */
407        public void setAuthUser( final String user ) {
408                authUser = nval( user, authUser );
409        }
410
411        /**
412         * メール送信認証パスワードをセットします。
413         * 初期値は、システム定数のMAIL_SEND_AUTH_PASSWORD を使用します。
414         *
415         * (初期値:システム定数のMAIL_SEND_AUTH_PASSWORD[={@og.value SystemData#MAIL_SEND_AUTH_PASSWORD}])。
416         *
417         * @og.rev 5.6.6.0 (2013/07/05)
418         *
419         * @param  pass 認証パスワード
420         */
421        public void setAuthPass( final String pass ) {
422                authPass = nval( pass, authPass );
423        }
424
425        /**
426         * メール送信にSTARTTLSを利用するかのフラグをセットします。
427         * 初期値は、システム定数のMAIL_SEND_USE_STARTTLS を使用します。
428         *
429         * (初期値:システム定数のMAIL_SEND_AUTH_PASSWORD[={@og.value org.opengion.hayabusa.common.SystemData#MAIL_SEND_USE_STARTTLS}])。
430         *
431         * @og.rev 5.9.29.2 (2018/02/16) STARTTLS対応(キーワードをVer5 にあわせます)
432         *
433         * @param  flg TLSの利用有無
434         */
435        public void setUseTLS( final boolean flg ) {
436                useTLS = flg;
437        }
438
439        /**
440         * メール送信者アドレスを返します。
441         *
442         * @return      送信者アドレス
443         */
444        public String getFromAddr() {
445                return fromAddr;
446        }
447
448        /**
449         * メールタイトルを返します。
450         *
451         * @return      メールタイトル
452         */
453        public String getTitle() {
454                return mailTitle;
455        }
456
457        /**
458         * メール本文を返します。
459         *
460         * @return      メール本文
461         */
462        public String getContent() {
463                return mailContent;
464        }
465
466        /**
467         * 送信結果を履歴テーブル(GE32)と宛先テーブル(GE34)に登録します。
468         * 登録時に、桁数オーバーにならないように、テーブル定義の桁数を上限として、
469         * 登録前に各項目の桁数整理を行います。
470         *
471         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
472         * @og.rev 5.9.1.3 (2015/10/30) 4000文字カットをやめる
473         * @og.rev 6.3.9.0 (2015/11/06) Map.keySet() ではなく、Map.values() を使う様に変更。
474         * @og.rev 6.4.2.0 (2016/01/29) DateSet.getDate( String ) を利用するように修正します。
475         * @og.rev 8.5.7.0 (2024/03/29) MailSendHistory の代わりに、このメソッドで処理するので、public に変更します。
476         */
477//      protected void commitMailDB(){
478        public void commitMailDB(){
479                // 履歴テーブルの追加
480                final String[] insGE32Args = new String[15];            // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal
481                final String ykno = getYkno();
482
483                insGE32Args[GE32_YKNO]          = ykno;
484                insGE32Args[GE32_PARAKEY]       = initParamMap.get( "PARAKEY" );
485                insGE32Args[GE32_PTN_ID]        = trim( initParamMap.get( "PTN_ID" ), 20 );
486                insGE32Args[GE32_FROM_ADDR] = trim( fromAddr, 100);
487                insGE32Args[GE32_TITLE]         = trim( mailTitle, 300);
488                insGE32Args[GE32_CONTENTS]      = mailContent;                                  // 5.9.1.3 (2015/10/30)
489                insGE32Args[GE32_ATTACH1]       = "";
490                insGE32Args[GE32_ATTACH2]       = "";
491                insGE32Args[GE32_ATTACH3]       = "";
492                insGE32Args[GE32_ATTACH4]       = "";
493                insGE32Args[GE32_ATTACH5]       = "";
494                if( attachFiles != null ) {
495                        final int attSize = attachFiles.length;
496                        for( int i=0; i<attSize; i++ ) {
497                                insGE32Args[6 + i] = trim( attachFiles[i], 256);
498                        }
499                }
500                insGE32Args[GE32_DYSET]         = DateSet.getDate( "yyyyMMddHHmmss" );                  // 6.4.2.0 (2016/01/29)
501                insGE32Args[GE32_USRSET]        = initParamMap.get( "LOGIN_USERID" );
502                insGE32Args[GE32_PGUPD]         = initParamMap.get( "PGID" );
503                insGE32Args[GE32_SYSTEM_ID]     = initParamMap.get( "SYSTEM_ID" );
504                DBUtil.dbExecute( INS_GE32, insGE32Args, APP_INFO, DBID );      // 5.5.5.1 (2012/08/07)
505
506                // 宛先テーブル追加
507                final String[] insGE34Args = new String[10];            // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal
508                insGE34Args[GE34_YKNO]= ykno;
509
510                // 6.3.9.0 (2015/11/06) Map.keySet() ではなく、Map.values() を使う様に変更。
511                for( final String[] dstInfo : mailDstMap.values() ) {
512                        insGE34Args[GE34_DST_ID]        = trim( dstInfo[MailPattern.IDX_DST_ID]  , 50 );        // 8.5.7.0 (2024/03/29) DB定義 X(10) → X(50)
513                        insGE34Args[GE34_GROUP_ID]      = trim( dstInfo[MailPattern.IDX_GROUP_ID], 20 );
514                        insGE34Args[GE34_DST_NAME]      = trim( dstInfo[MailPattern.IDX_DST_NAME], 20 );
515                        insGE34Args[GE34_DST_ADDR]      = trim( dstInfo[MailPattern.IDX_DST_ADDR], 100 );
516                        insGE34Args[GE34_DST_KBN]       = dstInfo[MailPattern.IDX_DST_KBN];
517                        insGE34Args[GE34_FGJ]           = dstInfo[MailPattern.IDX_FGJ];
518                        insGE34Args[GE34_DYSET]         = DateSet.getDate( "yyyyMMddHHmmss" );                  // 6.4.2.0 (2016/01/29)
519                        insGE34Args[GE34_USRSET]        = initParamMap.get( "LOGIN_USERID" );
520                        insGE34Args[GE34_PGUPD]         = initParamMap.get( "PGID" );
521                        DBUtil.dbExecute( INS_GE34, insGE34Args, APP_INFO, DBID );              // 5.5.5.1 (2012/08/07)
522                }
523        }
524
525        /**
526         * パラメータマップをセットします。
527         *
528         * @og.rev 6.4.3.1 (2016/02/12) 作成元のMapを、HashMap から ConcurrentHashMap に置き換え。
529         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。
530         * @og.rev 8.5.7.0 (2024/03/29) initParamMap をメソッドで処理し、attachFiles を設定する。
531         *
532         * @param       params  パラメータのマップ
533         */
534        protected void setInitParams( final ConcurrentMap<String, String> params ) {
535//              initParamMap = params;
536                initParamMap.clear();
537                initParamMap.putAll( params );
538
539                // 8.5.7.0 (2024/03/29) initParamMap をメソッドで処理し、attachFiles を設定する。
540                setAttachFiles( params.get( "ATTACH1" )                                                 // 8.5.7.0 (2024/03/29) setInitParams へ
541                                          , params.get( "ATTACH2" )
542                                          , params.get( "ATTACH3" )
543                                          , params.get( "ATTACH4" )
544                                          , params.get( "ATTACH5" ) );                                          // 添付ファイルのセット
545        }
546
547        /**
548         * 添付ファイル配列をセットします(最大5個まで)。
549         *
550         * @param       attachs 添付ファイルの可変長配列(ただし、最大5個まで)
551         */
552        protected void setAttachFiles( final String... attachs ) {
553                final List<String> fileList = new ArrayList<>();
554                if( attachs != null ) {
555                        for( final String attach : attachs ) {
556                                if( StringUtil.isNotNull( attach ) ) {
557                                        fileList.add( attach );
558                                }
559                        }
560                }
561                attachFiles = fileList.toArray( new String[0] );        // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
562        }
563
564//      /**
565//       * 添付ファイル配列をセットします。
566//       *
567//       * @param       attachs 添付ファイル名1
568//       * @param       attach2 添付ファイル名2
569//       * @param       attach3 添付ファイル名3
570//       * @param       attach4 添付ファイル名4
571//       * @param       attach5 添付ファイル名5
572//       */
573//      protected void setAttachFiles( final String attach1
574//                                                              , final String attach2
575//                                                              , final String attach3
576//                                                              , final String attach4
577//                                                              , final String attach5 ) {
578//              final List<String> fileList = new ArrayList<>();
579//              if( attach1 != null && attach1.length() != 0 ) { fileList.add( attach1 ); }
580//              if( attach2 != null && attach2.length() != 0 ) { fileList.add( attach2 ); }
581//              if( attach3 != null && attach3.length() != 0 ) { fileList.add( attach3 ); }
582//              if( attach4 != null && attach4.length() != 0 ) { fileList.add( attach4 ); }
583//              if( attach5 != null && attach5.length() != 0 ) { fileList.add( attach5 ); }
584////            attachFiles = fileList.toArray( new String[fileList.size()] );
585//              attachFiles = fileList.toArray( new String[0] );        // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
586//      }
587
588        /**
589         * メール宛先マップをセットします。
590         *
591         * @og.rev 6.4.3.1 (2016/02/12) 作成元のMapを、HashMap から ConcurrentHashMap に置き換え。
592         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。
593         *
594         * @param   mailDst     メール宛先マップ
595         */
596        protected void setMailDstMap( final ConcurrentMap<String, String[]> mailDst ) {
597                mailDstMap = mailDst;
598        }
599
600        /**
601         * メール宛先マップをセットします。
602         *
603         * @og.rev 6.4.3.1 (2016/02/12) 作成元のMapを、HashMap から ConcurrentHashMap に置き換え。
604         * @og.rev 6.4.3.1 (2016/02/12) ConcurrentMap 系は、key,val ともに not null 制限です。
605         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。
606         *
607         * @return      メール宛先マップ
608         */
609        protected ConcurrentMap<String, String[]> getMailDstMap() {
610                return mailDstMap;
611        }
612
613        /**
614         * 指定の長さ以内の文字列を返します。
615         *
616         * @og.rev 5.9.1.3 (2015/10/30) 文字数ではなくByte数に変更
617         *
618         * @param       src             オリジナルの文字列
619         * @param       maxLen  指定の長さ
620         *
621         * @return      指定の長さに短縮された文字列
622         */
623        protected String trim( final String src, final int maxLen ) {
624                String rtn = src;
625                if( src != null && src.length() > maxLen ) {
626                        rtn = StringUtil.cut( src, maxLen );            // 5.9.1.3 (2015/10/30)
627                }
628                return rtn;
629        }
630
631        /**
632         * アドレスチェックのエラーリストを返します。
633         *
634         * @return      エラーリスト
635         */
636        protected List<String> getErrList(){
637                return errAddrList;
638        }
639
640        /**
641         * 宛先マップを元に、送信オブジェクトに宛先をセットします。
642         * セットする際に、アカウントエラーとなっているアドレスを除外します。
643         * 宛先が存在しない場合、例外を投げます。
644         *
645         * @og.rev 4.3.7.5 (2009/07/08) 送信先名称が設定されていない場合は、アドレスを&lt;&gt;で囲わない
646         * @og.rev 6.3.9.0 (2015/11/06) Map.keySet() ではなく、Map.values() を使う様に変更。
647         *
648         * @param invalidAddr 宛先のリスト
649         */
650        private void setMailDst( final List<String> invalidAddr ){
651//              final ArrayList<String> toList = new ArrayList<>();
652//              final ArrayList<String> ccList = new ArrayList<>();
653//              final ArrayList<String> bccList = new ArrayList<>();
654                final List<String> toList = new ArrayList<>();          // 8.5.4.2 (2024/01/12) PMD 7.0.0 LooseCoupling
655                final List<String> ccList = new ArrayList<>();          // 8.5.4.2 (2024/01/12) PMD 7.0.0 LooseCoupling
656                final List<String> bccList = new ArrayList<>();         // 8.5.4.2 (2024/01/12) PMD 7.0.0 LooseCoupling
657
658                // これ、今見たけど、こんな使い方はどうかと思う。
659//              final Map<Integer, ArrayList<String>> tempMap = new HashMap<>();
660                final Map<Integer, List<String>> tempMap = new HashMap<>();                     // 8.5.4.2 (2024/01/12) PMD 7.0.0 LooseCoupling
661                tempMap.put( Integer.valueOf( MailPattern.KBN_TO ),  toList );
662                tempMap.put( Integer.valueOf( MailPattern.KBN_CC ),  ccList );
663                tempMap.put( Integer.valueOf( MailPattern.KBN_BCC ), bccList );
664
665                // 6.3.9.0 (2015/11/06) Map.keySet() ではなく、Map.values() を使う様に変更。
666                for( final String[] dstInfo : mailDstMap.values() ) {
667                        final Integer kbn = Integer.valueOf( dstInfo[MailPattern.IDX_DST_KBN] );
668                        // 6.1.1.0 (2015/01/17) PMD Avoid if(x != y) ..; else ..;
669                        if( invalidAddr.contains( dstInfo[MailPattern.IDX_DST_ADDR] )
670                                        || FGJ_ADDR_ERR.equals( dstInfo[MailPattern.IDX_FGJ] )){
671                                if( FGJ_SEND_OVER.equals( dstInfo[MailPattern.IDX_FGJ] ) ) {
672                                        dstInfo[MailPattern.IDX_FGJ] = FGJ_ACNT_ERR;
673                                }
674                        }
675                        else {
676                                dstInfo[MailPattern.IDX_FGJ] = FGJ_SEND_OVER;
677
678                                // 4.3.7.5 (2009/07/08)
679                                final String name = dstInfo[MailPattern.IDX_DST_NAME];
680                                if( name != null && name.length() > 0 ) {
681                                        tempMap.get( kbn ).add( dstInfo[MailPattern.IDX_DST_NAME] +  "<"+ dstInfo[MailPattern.IDX_DST_ADDR] + ">" );
682                                }
683                                else {
684                                        tempMap.get( kbn ).add( dstInfo[MailPattern.IDX_DST_ADDR] );
685                                }
686                        }
687                }
688
689                mail.clearTo();         // 宛先(TO)をクリア
690                mail.clearCc();         // 宛先(CC)をクリア
691                mail.clearBcc();        // 宛先(BCC)をクリア
692                boolean haveValidAddr = false ;
693                if( ! toList.isEmpty() ) {      // toのセット
694                        haveValidAddr = true;
695//                      final String[] to = toList.toArray( new String[toList.size()] );
696                        final String[] to = toList.toArray( new String[0] );    // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
697                        mail.setTo( to );
698                }
699                if( ! ccList.isEmpty() ) {      // ccのセット
700                        haveValidAddr = true;
701//                      final String[] cc = ccList.toArray( new String[ccList.size()] );
702                        final String[] cc = ccList.toArray( new String[0] );    // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
703                        mail.setCc( cc );
704                }
705                if( ! bccList.isEmpty() ) {     // bccのセット
706                        haveValidAddr = true;
707//                      final String[] bcc = bccList.toArray( new String[bccList.size()] );
708                        final String[] bcc = bccList.toArray( new String[0] );  // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
709                        mail.setBcc( bcc );
710                }
711                if( !haveValidAddr ){           // 宛先全部無効の場合、例外を投げます。
712                        final String errMsg = "宛先のメールアドレスが有効ではありません。"
713                                                + "TO , CC , BCC のいづれにもアドレスが設定されていません。"; // 5.1.8.0 (2010/07/01) errMsg 修正
714                        throw new OgRuntimeException( errMsg );
715                }
716        }
717
718        /**
719         * 要求NOを採番します。
720         * この要求NOで履歴テーブル(GE32)と宛先テーブル(GE34)の関連付けを持たせます。
721         *
722         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
723         * @og.rev 5.9.26.0 (2017/11/02) DB共通化対応
724         * @og.rev 7.0.6.4 (2019/11/29) TransactionRealのclose漏れ対応
725         *
726         * @return      要求NO
727         */
728        private String getYkno() {
729//              // 5.9.26.0 (2017/11/02) DBFnctionNameを利用して、シーケンスを取得
730//              String selYkno = "";
731//              final Transaction tran = new TransactionReal( APP_INFO );
732//              try{
733                try( Transaction tran = new TransactionReal( APP_INFO ) ) {                                     // 7.0.6.4 (2019/11/29) try-with-resources文
734//                      selYkno = String.valueOf(DBFunctionName.getDBName(ConnectionFactory.getDBName(DBID)).getSequence("GE32S02", tran));
735                        return Integer.toString( dbName.getSequence( SEL_YKNO,tran,DBID ) );    // 8.5.7.0 (2024/03/29)
736//              }finally{
737//                      tran.close();
738                }
739                catch( final Throwable ex ) {
740                        final String errMsg = "要求NO採番エラー"
741                                                + " SQL=" + SEL_YKNO ;          // 5.1.8.0 (2010/07/01) errMsg 修正
742//                      throw new OgRuntimeException( errMsg );
743                        throw new OgRuntimeException( errMsg,ex );              // 8.0.0.0 (2021/07/31) original stack trace may be lost
744                }
745//              return selYkno;
746        }
747
748        /**
749         * メールアドレスのリストよりユーザーIDを逆引きします。
750         *
751         * @og.rev 6.1.0.0 (2014/12/26) refactoring : メールアドレスのリスト件数を見てから、処理の実行を決めます。
752         * @og.rev 6.3.9.0 (2015/11/06) Map.keySet() ではなく、Map.entrySet() を使う様に変更。
753         * @og.rev 6.4.3.4 (2016/03/11) forループを、forEach メソッドに置き換えます。
754         *
755         * @param       addressList     メールアドレスのリスト(not null)
756         *
757         * @return      ユーザーID
758         * @og.rtnNotNull
759         */
760        private String getUserIds( final List<String> addressList ){
761                final int size = addressList.size() ;
762                if( size == 0 ) { return "" ; }
763
764                final Map<String,String> addressMap = new HashMap<>();
765                // 6.3.9.0 (2015/11/06) Map.keySet() ではなく、Map.entrySet() を使う様に変更。
766
767                // 6.4.3.4 (2016/03/11) forループを、forEach メソッドに置き換えます。
768                mailDstMap.forEach( (uid,inf) -> addressMap.put( inf[MailPattern.IDX_DST_ADDR], uid ) );
769
770                final StringBuilder idBuf = new StringBuilder( BUFFER_MIDDLE )
771                        .append( addressMap.get( addressList.get( 0 ) ) );              // 先に size == 0 判定は終わっている。
772                for( int i=1; i<size; i++ ) {
773                        idBuf.append( ',' ).append( addressMap.get( addressList.get( i ) ) );
774                }
775                return idBuf.toString();
776        }
777}