    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.db;
    017
    018import org.opengion.fukurou.system.HybsConst ;                                          // 6.1.0.0 (2014/12/26)
    019import org.opengion.fukurou.util.ErrorMessage;
    020import org.opengion.fukurou.db.Transaction;
    021import org.opengion.hayabusa.common.HybsSystemException;
    022import org.opengion.hayabusa.resource.ResourceManager;
    023
    024import java.util.Locale;
    025import java.util.Map;
    026import java.util.LinkedHashMap ;
    027import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
    028import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.1 (2016/02/12) refactoring
    029import java.util.Collections;                                                                           // 6.4.3.1 (2016/02/12) refactoring
    030
    031/**
    032 * AbstractTableFilter は、TableUpda インターフェースを継承した、DBTableModel 処理用の
    033 * Abstract実装クラスです。
    034 *
    035 * @og.rev 5.5.2.6 (2012/05/25) protected変数をprivateに変更。インターフェースにメソッド追加
    036 * @og.rev 6.4.1.1 (2016/01/16) keysMap を、サブクラスから設定させるように変更。
    037 *
    038 * @version  0.9.0  2000/10/17
    039 * @author   Kazuhiko Hasegawa
    040 * @since    JDK1.1,
    041 */
    042public abstract class AbstractTableFilter implements TableFilter {
    043        /** システムの改行コードを設定します。*/
    044        protected static final String CR                 = HybsConst.CR;                        // 6.1.0.0 (2014/12/26) refactoring
    045        /** StringBilderなどの初期値を設定します。   {@value} */
    046        protected static final int BUFFER_MIDDLE = HybsConst.BUFFER_MIDDLE;     // 6.1.0.0 (2014/12/26) refactoring
    047
    048        // 5.5.2.6 (2012/05/25) protected変数をprivateに変更。インターフェースにメソッド追加
    049        private DBTableModel    table           ;
    050        private String                  modifyType      ;
    051        private int[]                   rowNo           ;
    052        private boolean                 useDebug        ;               // 6.0.2.5 (2014/10/31) refactoring メソッドと同じなので名称変更
    053        private Transaction             tran            ;               // 5.1.9.0 (2010/08/01) 追加
    054        private String                  sql                     ;               // 4.2.4.0 (2008/06/23)
    055        private String                  dbid            ;               // 4.2.4.0 (2008/06/23)
    056        private ResourceManager resource        ;               // 4.3.7.4 (2009/07/01)
    057
    058        private int                     errCode         = ErrorMessage.OK;
    059        private ErrorMessage    errMessage      ;
    060
    061        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。  */
    062        private final ConcurrentMap<String,String> keyValMap = new ConcurrentHashMap<>();
    063
    064        // 5.6.6.0 (2013/07/05) keys の整合性チェックを行います。
    065        // 6.4.1.1 (2016/01/16) keysMap を、サブクラスから設定させるように変更
    066        /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理を行います。  */
    067        private final Map<String,String> keysMap = Collections.synchronizedMap( new LinkedHashMap<>() ) ;
    068
    069        /** 各種定数 */
    070        // 6.0.2.3 (2014/10/10) plugin.table.TableFilter_XXXX から移動
    071        protected static final String XML_START_TAG     = "<?xml version='1.0' encoding='UTF-8'?>" + CR + "<ROWSET tableName='xxx'>";
    072        protected static final String XML_END_TAG       = "</ROWSET>";
    073        protected static final String EXEC_START_TAG= "<EXEC_SQL>";
    074        protected static final String EXEC_END_TAG      = "</EXEC_SQL>";
    075
    076        /** XML形式かどうか  */
    077        // 6.0.2.3 (2014/10/10) isXml で、CR + EXEC_END_TAG のキャッシュを作成します。
    078        protected boolean       isXml           ;               // 6.0.2.3 (2014/10/10)
    079        protected String        execEndTag      ;               // 6.0.2.3 (2014/10/10)
    080
    081        /**
    082         * デフォルトコンストラクター
    083         *
    084         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    085         */
    086        protected AbstractTableFilter() { super(); }            // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    087
    088        /**
    089         * keys の整合性チェックを行うための初期設定を行います。
    090         * サブクラスのコンストラクタ内で、設定するようにしてください。
    091         *
    092         * @og.rev 6.4.1.1 (2016/01/16) keys の整合性チェック対応
    093         * @og.rev 6.4.3.1 (2016/02/12) ConcurrentMap 系は、key,val ともに not null 制限です。
    094         *
    095         * @param       key  整合性チェックを行うための keysMap に設定するキー
    096         * @param       cmnt 整合性チェックを行うための キー の説明
    097         */
    098        protected void initSet( final String key , final String cmnt ) {
    099                if( key != null && cmnt != null ) {
    100                        keysMap.put( key , cmnt );
    101                }
    102        }
    103
    104        /**
    105         * DBTableModel をセットします。
    106         *
    107         * @param       table DBTableModelオブジェクト
    108         */
    109        public void setDBTableModel( final DBTableModel table ) {
    110                this.table = table;
    111        }
    112
    113        /**
    114         * DBTableModel を取得します。
    115         *
    116         * @og.rev 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加
    117         *
    118         * @return      内部のDBTableModel
    119         */
    120        public DBTableModel getDBTableModel() {
    121                return table;
    122        }
    123
    124        /**
    125         * データ処理の方法(A:追加 C:更新 D:削除)を指定します。
    126         *
    127         * 通常は、DBTableModel に自動設定されている modifyType を元に、データ処理方法を
    128         * 選別します。(A:追加 C:更新 D:削除)
    129         * この場合、行単位で modifyType の値を取得して判別する必要がありますが、一般には
    130         * 処理対象は、全件おなじ modifyType である可能性が高いです。
    131         * また、selectedAll などで強制的に全件処理対象とする場合は、modifyType に値が
    132         * 設定さていません。その様な場合に外部より modifyType を指定します。
    133         * 初期値は、自動判定 です。
    134         *
    135         * @og.rev 5.5.2.6 (2012/05/25) 廃止
    136         *
    137         * @param  type データ処理の方法(A:追加 C:更新 D:削除)
    138         */
    139        public void setModifyType( final String type ) {
    140                modifyType = type;
    141        }
    142
    143        /**
    144         * データ処理の方法(A:追加 C:更新 D:削除)を取得します。
    145         *
    146         * 初期値は、自動判定 です。
    147         *
    148         * @og.rev 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加
    149         *
    150         * @return  データ処理の方法(A:追加 C:更新 D:削除)
    151         */
    152        public String getModifyType() {
    153                return modifyType ;
    154        }
    155
    156        /**
    157         * キーと値のペアの変数配列を受け取ります。
    158         *
    159         * ここでは、この方式以外に、パラメーターMapを受け取る方法もあります。
    160         * この受け取る時に、キーを大文字化します。TableFilter の keys は、
    161         * 大文字のみで定義しておくことで、HTMLやWindows世代の曖昧な表記方法に
    162         * 対応しています。(unixやxmlのような厳格な方が好きですけど)
    163         *
    164         * keys,vals とパラメーターMapを同時に指定した場合は、両方とも有効です。
    165         * ただし、キーが重複した場合は、不定と考えてください。
    166         *
    167         * @og.rev 5.6.6.0 (2013/07/05) keys の整合性チェックを行います。
    168         *
    169         * @param   keys キー配列
    170         * @param   vals 値配列
    171         * @see         #setParamMap( ConcurrentMap )
    172         */
    173        public void setKeysVals( final String[] keys,final String[] vals ) {
    174                if( keys != null && vals != null ) {
    175                        for( int i=0; i<keys.length; i++ ) {
    176                                // 5.6.6.0 (2013/07/05) 共通のセッターメソッド経由で登録します。
    177                                setKeyVal( keys[i],vals[i] );
    178                        }
    179                }
    180        }
    181
    182        /**
    183         * キーと値のペアを受け取り、内部の keyValMap マップに追加します。
    184         *
    185         * キーか値のどちらかが null の場合は、何もしません。つまり、val に
    186         * null をセットすることはできません。
    187         *
    188         * このメソッドは、setKeysVals( String[] ,String[] ) メソッドと、
    189         * setParamMap( Map<String,String> ) メソッドの両方から、使用します。
    190         * 処理を行うに当たり、下記の処理を行います。
    191         * １．キーを大文字化します。
    192         * ２．各クラスの keys と整合性チェックを行います。
    193         *
    194         * ただし、setKeysVals と setParamMap の登録順は、不定と考えてください。
    195         * 両方に同じキーを指定すると、どちらの値がセットされたかは、不定です。
    196         *
    197         * @og.rev 5.6.6.0 (2013/07/05) keys の整合性チェックを行います。
    198         * @og.rev 6.4.3.4 (2016/03/12) Map#forEach で対応する。
    199         * @og.rev 6.7.9.1 (2017/05/19) keysMap が、空の場合も、keyValMap に登録する。(initSet 未登録時)
    200         * @og.rev 7.0.1.0 (2018/10/15) XHTML → HTML5 対応(空要素の、"／＞" 止めを、"＞" に変更します)。
    201         *
    202         * @param   key キー文字列(null の場合は、処理しない)
    203         * @param   val 値文字列(null の場合は、処理しない)
    204         * @see         #setKeysVals( String[] ,String[] )
    205         * @see         #setParamMap( ConcurrentMap )
    206         */
    207        private void setKeyVal( final String key,final String val ) {
    208                // key か val かどちらかが null の場合は、処理を行わない。
    209                if( key == null || val == null ) { return; }
    210
    211                final String upKey = key.toUpperCase(Locale.JAPAN);
    212
    213                // 6.7.9.1 (2017/05/19) keysMap が、空の場合も、keyValMap に登録する。(initSet 未登録時)
    214                if(  keysMap.isEmpty() || keysMap.containsKey( upKey ) ) {              // keysMap は、各サブクラスで定義
    215                        keyValMap.put( upKey,val );
    216                }
    217                else {
    218//                      final String BR = "<br />" + CR ;
    219                        final String BR = "<br>" + CR ;                         // 7.0.1.0 (2018/10/15)
    220                        final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE );
    221                        // 6.0.2.5 (2014/10/31) char を append する。
    222                        errMsg.append( BR )
    223                                  .append( "指定のキーは、この tableFilter では、使用できません。" ).append( BR )
    224                                  .append( "  class=[" ).append( getClass().getName() ).append( ']' ).append( BR )
    225                                  .append( "  key  =[" ).append( key                              ).append( ']' ).append( BR )
    226                                  .append( "  ======== usage keys ======== " ).append( BR ) ;
    227                        // 6.4.3.4 (2016/03/12) Map#forEach で対応する。
    228                        keysMap.forEach( (k,v) -> { errMsg.append( ' ' ).append( k ).append( ':' ).append( v ).append( BR ); } );
    229                        errMsg.append( "  ============================ " ).append( BR );
    230
    231                        throw new HybsSystemException( errMsg.toString() );
    232                }
    233        }
    234
    235        /**
    236         * 選択された行番号の配列をセットします。
    237         *
    238         * 表示データの HybsSystem.ROW_SELECTED_KEY を元に、選ばれた 行を
    239         * 処理の対象とします。
    240         *
    241         * @param   rowNoTmp 行番号配列(可変長引数)
    242         */
    243        public void setParameterRows( final int... rowNoTmp ) {
    244                if( rowNoTmp != null && rowNoTmp.length > 0 ) {         // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    245                        final int size = rowNoTmp.length ;
    246                        rowNo = new int[size];
    247                        System.arraycopy( rowNoTmp,0,rowNo,0,size );
    248                }
    249        }
    250
    251        /**
    252         * 選択された行番号の配列を取得します。
    253         *
    254         * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を
    255         * 処理の対象とします。
    256         *
    257         * @og.rev 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加
    258         * @og.rev 6.0.2.5 (2014/10/31) null ではなく、サイズ０の配列を返すように変更。
    259         *
    260         * @return   行番号の配列(選ばれていない場合は、サイズ０の配列を返す)
    261         * @og.rtnNotNull
    262         */
    263        public int[] getParameterRows() {
    264                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
    265                return rowNo == null ? new int[0] : rowNo.clone() ;
    266        }
    267
    268        /**
    269         * アクセスログ取得の為,Transactionオブジェクトを設定します。
    270         *
    271         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応(新規追加)
    272         *
    273         * @param   tran Transactionオブジェクト
    274         */
    275        public void setTransaction( final Transaction tran ) {
    276                this.tran = tran;
    277        }
    278
    279        /**
    280         * アクセスログ取得の為,Transactionオブジェクトを取得します。
    281         *
    282         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応(新規追加)
    283         * @og.rev 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加
    284         *
    285         * @return   Transactionオブジェクト
    286         */
    287        public Transaction getTransaction() {
    288                return tran;
    289        }
    290
    291        /**
    292         * DBIDを指定します。
    293         *
    294         * @og.rev 4.2.4.0 (2008/06/23) 新規追加
    295         *
    296         * @param dbid 接続先ID
    297         */
    298        public void setDbid( final String dbid ) {
    299                this.dbid = dbid;
    300        }
    301
    302        /**
    303         * DBIDを取得します。
    304         *
    305         * @og.rev 4.2.4.0 (2008/06/23) 新規追加
    306         * @og.rev 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加
    307         *
    308         * @return DBID(接続先情報)
    309         */
    310        public String getDbid() {
    311                return dbid;
    312        }
    313
    314        /**
    315         * ボディー部分のSQLを指定します。
    316         *
    317         * @og.rev 4.2.4.0 (2008/06/23) 新規追加
    318         *
    319         * @param sql ボディー部分のSQL
    320         */
    321        public void setSql( final String sql ) {
    322                this.sql = sql;
    323        }
    324
    325        /**
    326         * ボディー部分のSQLを取得します。
    327         *
    328         * @og.rev 4.2.4.0 (2008/06/23) 新規追加
    329         * @og.rev 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加
    330         *
    331         * @return ボディー部分のSQL
    332         */
    333        public String getSql() {
    334                return sql;
    335        }
    336
    337        /**
    338         * パラメーターMapを指定します。
    339         *
    340         * keys,vals と パラメーターMapを同時に指定した場合は、両方とも有効です。
    341         * ただし、キーが重複した場合は、不定と考えてください。
    342         *
    343         * この受け取る時に、キーを大文字化します。TableFilter の keys は、
    344         * 大文字のみで定義しておくことで、HTMLやWindows世代の曖昧な表記方法に
    345         * 対応しています。(unixやxmlのような厳格な方が好きですけど)
    346         *
    347         * @og.rev 5.6.5.2 (2013/06/21) 新規追加
    348         * @og.rev 5.6.6.0 (2013/07/05) keys の整合性チェックを行います。
    349         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap を受け取ることを明確にするため、I/FをConcurrentMapに変更します。
    350         *
    351         * @param paramMap パラメーターMap
    352         * @see         #setKeysVals( String[] ,String[] )
    353         */
    354        public void setParamMap( final ConcurrentMap<String,String> paramMap ) {
    355                // 6.4.3.3 (2016/03/04) Map#forEach に変更
    356                if( paramMap != null ) {
    357                        paramMap.forEach( (k,v) -> setKeyVal( k,v ) );
    358                }
    359        }
    360
    361        /**
    362         * リソースオブジェクトを指定します。
    363         *
    364         * @og.rev 4.3.7.4 (2009/07/01) 新規追加
    365         *
    366         * @param resource リソースオブジェクト
    367         */
    368        public void setResource( final ResourceManager resource ) {
    369                this.resource = resource;
    370        }
    371
    372        /**
    373         * リソースオブジェクトを取得します。
    374         *
    375         * @og.rev 4.3.7.4 (2009/07/01) 新規追加
    376         * @og.rev 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加
    377         *
    378         * @return リソースオブジェクト
    379         */
    380        public ResourceManager getResource() {
    381                return resource;
    382        }
    383
    384        /**
    385         * デバッグ情報を出力するかどうか[true:する/false:しない]を指定します。
    386         * true でデバッグ情報を表示します。
    387         *
    388         * @param   flag  デバッグ出力するか [true:する/false:しない]
    389         */
    390        public void setDebug( final boolean flag ) {
    391                useDebug = flag;        // 6.0.2.5 (2014/10/31) refactoring メソッドと同じなので名称変更
    392        }
    393
    394        /**
    395         * デバッグ情報を出力するかどうか[true:する/false:しない]を取得します。
    396         * true でデバッグ情報を表示します。
    397         *
    398         * @og.rev 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加
    399         *
    400         * @return  デバッグ出力 [true:する/false:しない]
    401         */
    402        public boolean isDebug() {
    403                return useDebug ;       // 6.0.2.5 (2014/10/31) refactoring メソッドと同じなので名称変更
    404        }
    405
    406        /**
    407         * エラーコード を取得します。
    408         * エラーコード は、ErrorMessage クラスで規定されているコードです。
    409         *
    410         * @return   エラーコード
    411         */
    412        public int getErrorCode() {
    413                return errCode;
    414        }
    415
    416        /**
    417         * エラーメッセージオブジェクト を取得します。
    418         *
    419         * @return   エラーメッセージオブジェクト
    420         */
    421        public ErrorMessage getErrorMessage() {
    422                return errMessage;
    423        }
    424
    425        /**
    426         * タイトルとエラーコードを指定して、エラーメッセージオブジェクト を作成します。
    427         * すでに、作成済みの場合は、作成済みのオブジェクトを、まだ、未作成の場合は、
    428         * 新規に作成します。
    429         *
    430         * @param       title   タイトル
    431         * @param       code    エラーコード
    432         *
    433         * @return      エラーメッセージオブジェクト
    434         */
    435        protected ErrorMessage makeErrorMessage( final String title,final int code ) {
    436                if( errMessage == null ) {
    437                        errMessage = new ErrorMessage( title );
    438                }
    439                if( errCode < code ) { errCode = code; }
    440                return errMessage;
    441        }
    442
    443        /**
    444         *  カラム名配列(String[])より、対応するカラムNo配列(int[])を作成します。
    445         *
    446         * @param       nameArray カラム名配列
    447         *
    448         * @return      カラムNo配列(可変長引数)
    449         */
    450        protected int[] getTableColumnNo( final String... nameArray ) {
    451                int[] clmNo = new int[nameArray.length];
    452                for( int i=0; i<clmNo.length; i++ ) {
    453                        clmNo[i] = table.getColumnNo( nameArray[i] );
    454                }
    455                return clmNo;
    456        }
    457
    458        /**
    459         * 設定されたパラメータキーに対する値を取得します。
    460         * 引数、および、パラメータが null の場合は、 null を返します。
    461         *
    462         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap の not null制限のチェック追加
    463         *
    464         * @param       key     パラメータキー
    465         *
    466         * @return      パラメータ値
    467         */
    468        protected String getValue( final String key ) {
    469                return key == null ? null : keyValMap.get( key );
    470        }
    471
    472        /**
    473         * keyValMapに持っているキーの配列を取得します。
    474         * これは、サブクラスで、initSet(String,String) を行わない場合、keys には
    475         * 値を自由に設定できます。
    476         * その値を取り出すためです。
    477         *
    478         * @og.rev 6.7.9.1 (2017/05/19) 新規追加
    479         *
    480         * @return      キー値の配列(keyValMapに持っているキー)
    481         */
    482        protected String[] getKeys() {
    483                return keyValMap.keySet().toArray( new String[keyValMap.size()] );
    484        }
    485}