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