    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 org.opengion.fukurou.system.OgRuntimeException ;                 // 6.4.2.0 (2016/01/29)
    019import java.util.concurrent.ConcurrentMap;                                              // 6.4.3.3 (2016/03/04)
    020import java.util.concurrent.ConcurrentHashMap;                                  // 6.4.3.1 (2016/02/12) refactoring
    021import java.util.concurrent.ConcurrentSkipListMap;                              // 6.4.3.1 (2016/02/12) refactoring
    022
    023import org.opengion.fukurou.system.DateSet;                                             // 6.4.2.0 (2016/01/29)
    024import org.opengion.fukurou.db.DBUtil;
    025import org.opengion.fukurou.db.ApplicationInfo;
    026import org.opengion.fukurou.db.Transaction;                                             // 5.9.31.1 (2018/04/13)
    027import org.opengion.fukurou.db.TransactionReal;                                 // 5.9.31.1 (2018/04/13)
    028import org.opengion.fukurou.db.ConnectionFactory;                               // 5.9.31.1 (2018/04/13)
    029import org.opengion.fukurou.db.DBFunctionName;                                  // 5.9.31.1 (2018/04/13)
    030import org.opengion.fukurou.util.StringUtil;
    031import org.opengion.hayabusa.common.HybsSystem;
    032
    033import static org.opengion.fukurou.util.StringUtil.nval;                // 6.4.3.3 (2016/03/04)
    034
    035/**
    036 * メールモジュール関係の機能の一部を他から使用するためのクラスです。
    037 *
    038 * ※MailSenderTagからGE32,34へ履歴を出力する機能を追加する際に、モジュール系の動作を本パッケージに集約しておくために作成。
    039 *   必要としている箇所のみ実装。
    040 *
    041 * @og.rev 5.9.2.3 (2015/11/27) 新規作成
    042 *
    043 * @og.group メールモジュール
    044 *
    045 * @version  4.0
    046 * @author   Takahashi Masakazu
    047 * @since    JDK1.6
    048 */
    049public class MailModuleUtil {
    050
    051//      // Ver4互換モード対応
    052//      // 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
    053//      private static final String CONTENTS = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "CONTENT" : "CONTENTS";
    054
    055//      // 6.4.1.1 (2016/01/16) selYkno → SEL_YKNO , insGE32 → INS_GE32 , insGE34 → INS_GE34 refactoring
    056//      private static final String     SEL_YKNO        = "SELECT GE32S02.NEXTVAL YKNO FROM DUAL";
    057
    058        private static final String     SEL_YKNO        = "GE32S02";            // 5.9.31.1 (2018/04/13)
    059        // 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
    060//      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)"
    061        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)"
    062                                                                                        + " VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,'1')";
    063        private static final String INS_GE34            = "INSERT INTO GE34(YKNO,DST_ID,GROUP_ID,DST_NAME,DST_ADDR,DST_KBN,FGJ,DYSET,USRSET,PGUPD)"
    064                                                                                        + " VALUES(?,?,?,?,?,?,?,?,?,?)";
    065
    066        // 内部データのカラム番号(履歴テーブル)
    067        private static final int GE32_YKNO              = 0 ;
    068        private static final int GE32_PARAKEY   = 1 ;
    069        private static final int GE32_PTN_ID    = 2;
    070        private static final int GE32_FROM_ADDR = 3;
    071        private static final int GE32_TITLE     = 4;
    072        private static final int GE32_CONTENTS  = 5;
    073        // private static final int GE32_ATTACH1        = 6;
    074        // private static final int GE32_ATTACH2        = 7;
    075        // private static final int GE32_ATTACH3        = 8;
    076        // private static final int GE32_ATTACH4        = 9;
    077        // private static final int GE32_ATTACH5        = 10;
    078        private static final int GE32_DYSET             = 11;
    079        private static final int GE32_USRSET    = 12;
    080        private static final int GE32_PGUPD     = 13;
    081        private static final int GE32_SYSTEM_ID = 14;
    082        // 内部データのカラム番号(履歴テーブル)
    083        private static final int GE34_YKNO              = 0 ;
    084        private static final int GE34_DST_ID    = 1 ;
    085        private static final int GE34_GROUP_ID  = 2 ;
    086        private static final int GE34_DST_NAME  = 3 ;
    087        private static final int GE34_DST_ADDR  = 4 ;
    088        private static final int GE34_DST_KBN   = 5 ;
    089        private static final int GE34_FGJ               = 6 ;
    090        private static final int GE34_DYSET             = 7 ;
    091        private static final int GE34_USRSET    = 8 ;
    092        private static final int GE34_PGUPD     = 9 ;
    093
    094        // アドレスマップ
    095        private static final int IDX_DST_ADDR   = 0;
    096        private static final int IDX_DST_KBN    = 1;
    097
    098        /** メール送信区分 {@value} */
    099        private static final int KBN_TO                 = 0 ;   // メール送信区分(TO)
    100        /** メール送信区分 {@value} */
    101        private static final int KBN_CC                 = 1 ;   // メール送信区分(CC)
    102        /** メール送信区分 {@value} */
    103        private static final int KBN_BCC                = 2 ;   // メール送信区分(BCC)
    104
    105        /** 6.4.3.1 (2016/02/12) PMD refactoring. TreeMap → ConcurrentSkipListMap に置き換え。  */
    106        private final ConcurrentMap<String, String[]> mailDstMap = new ConcurrentSkipListMap<>() ;                                      // 6.4.3.3 (2016/03/04)
    107
    108        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。  */
    109        private final ConcurrentMap<String, String> initParamMap = new ConcurrentHashMap<>();                                           // パラメータマップ
    110
    111        /** ﾃﾞｰﾀﾍﾞｰｽ接続ID  */
    112        protected final String DBID = HybsSystem.sys( "RESOURCE_DBID" );                                                                                        // 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対応
    113        /** ﾌｧﾝｸｼｮﾝ名ｵﾌﾞｼﾞｪｸﾄ  */
    114        protected final DBFunctionName dbName = DBFunctionName.getDBName( ConnectionFactory.getDBName( DBID ) );        // 5.9.31.1 (2018/04/13)
    115
    116        /** コネクションにアプリケーション情報を追記するかどうか指定 */
    117        private static final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;
    118
    119        /** アプリケーション情報 */
    120        private static final ApplicationInfo APP_INFO;                          // 6.4.1.1 (2016/01/16) appInfo → APP_INFO refactoring
    121
    122        static {
    123                if( USE_DB_APPLICATION_INFO ) {
    124                        APP_INFO = new ApplicationInfo();
    125                        // ユーザーID,IPアドレス,ホスト名
    126                        APP_INFO.setClientInfo( "MailModuel", HybsSystem.HOST_ADRS, HybsSystem.HOST_NAME );
    127                        // 画面ID,操作,プログラムID
    128                        APP_INFO.setModuleInfo( "MailModuel", "MailManager", "MailManager" );
    129                }
    130                else {
    131                        APP_INFO = null;
    132                }
    133        }
    134
    135        /**
    136         * デフォルトコンストラクター
    137         *
    138         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    139         */
    140        public MailModuleUtil() { super(); }            // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    141
    142        /**
    143         * 履歴テーブル(GE32)と宛先テーブル(GE34)に登録します。
    144         * 登録時に、桁数オーバーにならないように、テーブル定義の桁数を上限として、
    145         * 登録前に各項目の桁数整理を行います。
    146         *
    147         * @og.rev 5.9.3.0 (2015/12/04) 添付ファイル対応
    148         * @og.rev 6.4.2.0 (2016/01/29) DateSet.getDate( String ) を利用するように修正します。
    149         * @og.rev 6.4.3.2 (2016/02/19) Map を、 keySet() ではなく、values() に変更します。
    150         *
    151         */
    152        public void commitMailDB(){
    153                // 履歴テーブルの追加
    154                String[] insGE32Args = new String[15];
    155                final String ykno = getYkno();
    156                final String[] attachFiles = StringUtil.csv2Array( initParamMap.get( "FILES" ) ); // 5.9.3.0
    157
    158                insGE32Args[GE32_YKNO]          = ykno;
    159                insGE32Args[GE32_PARAKEY]       = initParamMap.get( "PARAKEY" );
    160                insGE32Args[GE32_PTN_ID]        = trim( initParamMap.get( "PTN_ID" ), 20 );
    161                insGE32Args[GE32_FROM_ADDR] = trim( initParamMap.get( "FROM"   ), 100);
    162                insGE32Args[GE32_TITLE]         = trim( initParamMap.get( "TITLE"  ), 300);
    163                insGE32Args[GE32_CONTENTS]      = initParamMap.get( "CONTENT" );
    164        //      insGE32Args[GE32_ATTACH1]       = "";
    165        //      insGE32Args[GE32_ATTACH2]       = "";
    166        //      insGE32Args[GE32_ATTACH3]       = "";
    167        //      insGE32Args[GE32_ATTACH4]       = "";
    168        //      insGE32Args[GE32_ATTACH5]       = "";
    169                // 5.9.3.0
    170                if( attachFiles != null ) {
    171                        final int attSize = attachFiles.length;
    172                        for( int i = 0; i < attSize; i++ ) {
    173                                insGE32Args[6 + i] = trim( attachFiles[i], 256);
    174                        }
    175                }
    176
    177                insGE32Args[GE32_DYSET]         = DateSet.getDate( "yyyyMMddHHmmss" );                                          // 6.4.2.0 (2016/01/29)
    178                insGE32Args[GE32_USRSET]        = initParamMap.get( "LOGIN_USERID" );
    179                insGE32Args[GE32_PGUPD]         = initParamMap.get( "PGID" );
    180                insGE32Args[GE32_SYSTEM_ID] = initParamMap.get( "SYSTEM_ID" );
    181                DBUtil.dbExecute( INS_GE32, insGE32Args, APP_INFO, DBID );                                                      // 5.5.5.1 (2012/08/07)
    182
    183                // 宛先テーブル追加
    184                String[] insGE34Args = new String[10];
    185                insGE34Args[GE34_YKNO]= ykno;
    186                // 6.4.3.2 (2016/02/19) Map を、 keySet() ではなく、values() に変更します。
    187                for( final String[] vals : mailDstMap.values() ) {
    188                        insGE34Args[GE34_DST_ID]        = trim( vals[IDX_DST_ADDR], 10 );
    189                        insGE34Args[GE34_GROUP_ID]      = "";
    190                        insGE34Args[GE34_DST_NAME]      = "";
    191                        insGE34Args[GE34_DST_ADDR]      = trim( vals[IDX_DST_ADDR], 100 );
    192                        insGE34Args[GE34_DST_KBN]       = vals[IDX_DST_KBN];
    193                        insGE34Args[GE34_FGJ]           = "1";
    194                        insGE34Args[GE34_DYSET]         = DateSet.getDate( "yyyyMMddHHmmss" );                          // 6.4.2.0 (2016/01/29)
    195                        insGE34Args[GE34_USRSET]        = initParamMap.get( "LOGIN_USERID" );
    196                        insGE34Args[GE34_PGUPD]         = initParamMap.get( "PGID" );
    197                        DBUtil.dbExecute( INS_GE34, insGE34Args, APP_INFO, DBID );                                              // 5.5.5.1 (2012/08/07)
    198                }
    199        }
    200
    201        /**
    202         * パラメータマップをセットします。
    203         *
    204         * @param       params  パラメータのマップ
    205         */
    206
    207        /**
    208         * パラメータからマップをセットします。
    209         *
    210         * @og.rev 5.9.3.0 (2015/11/30) files追加
    211         * @og.rev 6.4.2.0 (2016/01/29) DateSet.getDate( String ) を利用するように修正します。
    212         * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. Map → ConcurrentMap に置き換え。
    213         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap の not null制限のチェック追加
    214         *
    215         * @param systemId      システムID(not null)
    216         * @param from          FROMアドレス(not null)
    217         * @param tos           TOアドレス（CSV形式）
    218         * @param ccs           CCアドレス（CSV形式）
    219         * @param bccs          BCCアドレス（CSV形式）
    220         * @param content       本文
    221         * @param title         タイトル
    222         * @param userid        登録ユーザ
    223         * @param pgid          登録PG
    224         * @param files         添付ファイル
    225         */
    226        public void setInitParams( final String systemId, final String from, final String[] tos, final String[] ccs
    227                                                                ,final String[] bccs, final String content, final String title, final String userid, final String pgid
    228                                                                ,final String[] files ) {
    229
    230                // 6.4.3.3 (2016/03/04) ConcurrentHashMap の not null制限のチェック追加
    231                if( systemId == null || from == null ) {
    232                        final String errMsg = "systemId または、from  が null です。"
    233                                                + " systemId=" + systemId + " , from=" + from  ;
    234                        throw new OgRuntimeException( errMsg );
    235                }
    236
    237                initParamMap.clear();
    238
    239                initParamMap.put( "SYSTEM_ID"   , systemId      );
    240                initParamMap.put( "FROM"                , from          );
    241                initParamMap.put( "TO"                  , StringUtil.array2csv( tos ) );
    242                initParamMap.put( "CC"                  , StringUtil.array2csv( ccs ) );
    243                initParamMap.put( "BCC"                 , StringUtil.array2csv( bccs ) );
    244                initParamMap.put( "CONTENT"             , nval( content         , "No Content" ) );
    245                initParamMap.put( "TITLE"               , nval( title           , "No Title" ) );
    246                initParamMap.put( "DATE"                , DateSet.getDate("yyyy/MM/dd") );                              // 6.4.2.0 (2016/01/29)
    247                initParamMap.put( "TIME"                , DateSet.getDate("HH:mm:ss") );                                // 6.4.2.0 (2016/01/29)
    248                initParamMap.put( "LOGIN_USERID", nval( userid          , "No UserID" ) );
    249                initParamMap.put( "PGID"                , nval( pgid            , "No PGID" ) );
    250                initParamMap.put( "FILES"               , StringUtil.array2csv( files ) );                              // 5.9.3.0 (2015/12/04)
    251
    252                getDstMap( tos, ccs, bccs );
    253        }
    254
    255        /**
    256         * 指定の長さ以内の文字列を返します。
    257         *
    258         * @og.rev 5.9.1.3 (2015/10/30) 文字数ではなくByte数に変更
    259         *
    260         * @param       src             オリジナルの文字列
    261         * @param       maxLen  指定の長さ
    262         *
    263         * @return      指定の長さに短縮された文字列
    264         */
    265        private String trim( final String src, final int maxLen ) {
    266                String rtn = src;
    267                if( src != null && src.length() > maxLen ) {
    268                        rtn = StringUtil.cut( src, maxLen );
    269                }
    270                return rtn;
    271        }
    272
    273        /**
    274         * 要求NOを採番します。
    275         * この要求NOで履歴テーブル(GE32)と宛先テーブル(GE30)の関連付けを持たせます。
    276         *
    277         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
    278         * @og.rev 5.9.31.1 (2018/04/13) シーケンスの取り方変更
    279         * @og.rev 7.0.6.4 (2019/11/29) TransactionRealのclose漏れ対応
    280         *
    281         * @return      要求NO
    282         */
    283        private String getYkno() {
    284//              final String[][] tmp = DBUtil.dbExecute( SEL_YKNO, new String[0], APP_INFO, DBID );             // 5.5.5.1 (2012/08/07)
    285//              if( tmp == null || tmp.length == 0 ) {
    286//                      final String errMsg = "要求NO採番エラー"
    287//                                              + " SQL=" + SEL_YKNO ;          // 5.1.8.0 (2010/07/01) errMsg 修正
    288//                      throw new OgRuntimeException( errMsg );
    289//              }
    290//              return tmp[0][0];
    291
    292//              final Transaction tran = new TransactionReal( APP_INFO );
    293//              final int rtn_ykno = dbName.getSequence( SEL_YKNO,tran,DBID );
    294//              return Integer.toString( rtn_ykno );
    295
    296                try( Transaction tran = new TransactionReal( APP_INFO ) ) {                             // 7.0.6.4 (2019/11/29) try-with-resources文
    297                        return Integer.toString( dbName.getSequence( SEL_YKNO,tran,DBID ) );
    298                }
    299                catch( final Throwable ex ) {
    300                        final String errMsg = "要求NO採番エラー"
    301                                                + " SQL=" + SEL_YKNO ;          // 5.1.8.0 (2010/07/01) errMsg 修正
    302//                      throw new OgRuntimeException( errMsg );
    303                        throw new OgRuntimeException( errMsg,ex );              // 8.0.0.0 (2021/07/31) original stack trace may be lost
    304                }
    305        }
    306
    307        /**
    308         * 送信先のアドレスをセットします。
    309         *
    310         * @og.rev 6.4.3.1 (2016/02/12) インスタンス変数で初期化した、ConcurrentSkipListMap を使用します。
    311         *
    312         * @param toId  送信先TOのアドレス
    313         * @param ccId  送信先CCのアドレス
    314         * @param bccId 送信先BCCのアドレス
    315         */
    316        private void getDstMap( final String[] toId, final String[] ccId, final String[] bccId  ){
    317                // 送信先(TO、CC、BCC)のマップを初期化します。
    318                mailDstMap.clear();
    319
    320                // 送信先(TO、CC、BCC)のマップに、値をセットします。セット順ではなく、自然ソート順です。
    321                setDstAddrMap( mailDstMap , bccId, KBN_BCC );
    322                setDstAddrMap( mailDstMap , ccId,  KBN_CC  );
    323                setDstAddrMap( mailDstMap , toId,  KBN_TO  );
    324        }
    325
    326        /**
    327         * 送信先のアドレス・マップを作成します。
    328         *
    329         * @og.rev 6.4.3.1 (2016/02/12) インスタンス変数で初期化した、ConcurrentSkipListMap を使用します。
    330         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。
    331         * @og.rev 5.9.33.0 (2018/06/01) dstBufがnullの場合の処理
    332         *
    333         * @param       dstMap  設定するMapオブジェクト
    334         * @param       dstBuf  送信先配列
    335         * @param       kbn             送信区分[0:TO/1:CC/2:BCC]
    336         */
    337        private void setDstAddrMap( final ConcurrentMap<String, String[]> dstMap, final String[] dstBuf, final int kbn ){
    338                if( dstBuf != null && dstBuf.length > 0 ) {                             // 5.9.33.0 (2018/06/01)
    339                        // IDX_DST_ADDR ,IDX_DST_KBN
    340                        final String[] dstInit = { "", Integer.toString( kbn ) };
    341
    342                        final int len = dstBuf.length;
    343                        for( int i=0; i < len; i++ ){
    344                                String[] indMember = dstInit.clone();
    345                                indMember[IDX_DST_ADDR] = dstBuf[i];                    // メールアドレス
    346
    347                                dstMap.put( dstBuf[i], indMember );
    348                        }
    349                }
    350        }
    351}