    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 java.util.HashMap;
    019import java.util.HashSet;
    020import java.util.Map;
    021import java.util.Set;
    022
    023import org.opengion.fukurou.util.StringUtil;
    024
    025/**
    026 * エディット設定情報を管理するためのデータ管理クラスです。
    027 * ここで管理される各パラメーターの意味は以下の通りです。
    028 * (各インデックス番号は、内部的に管理されているインデックス番号を意味します)
    029 *
    030 * ・0:エディット名
    031 *       このエディット設定オブジェクトの名称です。
    032 * ・1:表示カラム
    033 *       表示対象となるカラム一覧です。カンマ区切りで指定します。
    034 *       この一覧には、非表示のカラムも合わせて管理され、非表示カラムについては、
    035 *       カラム名の先頭に"!"をつけます。
    036 *       例) AAA,!BBB,CCC ⇒ AAA,CCCの順に表示(BBBは非表示)
    037 * ・2:集計カラム
    038 *       各値をSUMする対象となるカラムです。(カンマ区切りで複数指定が可能)
    039 *       ここで指定されたカラムは数値型である必要があります。
    040 *       SQL構文における、SUM関数の引数として指定するカラムに相当します。
    041 * ・3:グループカラム
    042 *       集計カラムの各値をグルーピングするためのカラムです。(カンマ区切りで複数指定が可能)
    043 *       SQL構文における、GROUP BYに指定するカラムに相当します。
    044 * ・4:小計カラム
    045 *       集計カラムの各値に対し、小計行を付加するためのブレイクキーを指定します。(カンマ区切りで複数指定が可能)
    046 * ・5:合計カラム
    047 *       集計カラムの各値に対し、合計行を付加するためのブレイクキーを指定します。(カンマ区切りで複数指定が可能)
    048 * ・6:総合計フラグ
    049 *       集計カラムの各値に対し、総合計行を付加するかどうかを指定します。(0以外:追加する 0:追加しない)
    050 * ・7:表示順カラム
    051 *       データの表示順をその順番にカンマ区切りで指定します。
    052 *       カラム名の先頭に"!"をつけた場合は、そのカラムは降順で表示されます。
    053 *       SQL構文における、orderby句に相当します。
    054 * ・8:共通フラグ
    055 *       このエディット設定オブジェクトが、共通(全ユーザー公開)エディットかどうかを
    056 *       指定します。(0以外:共通 0:個人のみ)
    057 *
    058 * @og.rev 5.3.6.0 (2011/06/01) 新規追加
    059 *
    060 * @version  5.0
    061 * @author   Hiroki Nakamura
    062 * @since    JDK6.0,
    063 */
    064public class DBEditConfig {
    065
    066        private static final int EDIT_KEY_NAME          = 0;
    067        private static final int EDIT_KEY_VIEW          = 1;
    068        private static final int EDIT_KEY_SUM           = 2;
    069        private static final int EDIT_KEY_GROUP         = 3;
    070        private static final int EDIT_KEY_SUBTOTAL      = 4;
    071        private static final int EDIT_KEY_TOTAL         = 5;
    072        private static final int EDIT_KEY_GRANDTOTAL= 6;
    073        private static final int EDIT_KEY_ORDERBY       = 7;
    074        private static final int EDIT_KEY_COMMON        = 8;
    075
    076        private static final String[] EDIT_KEYS
    077                = { "NAME", "VIEW", "SUM", "GROUP", "SUBTOTAL", "TOTAL", "GRANDTOTAL", "ORDERBY", "COMMON" };
    078
    079        private static final int EDIT_KEYS_LENGTH       = EDIT_KEYS.length;
    080
    081        private final String[] editVals = new String[EDIT_KEYS_LENGTH];
    082
    083        private int sumClmCount;
    084        private int groupClmCount;
    085        private int subTotalClmCount;
    086        private int totalClmCount;
    087        private final Map<String,String> orderMap = new HashMap<String,String>();
    088        private String orderByDescClms;
    089
    090        /**
    091         * コンストラクタ
    092         *
    093         * 空のエディット設定オブジェクトを構築します。
    094         */
    095        public DBEditConfig() {
    096        }
    097
    098        /**
    099         * コンストラクタ
    100         *
    101         * 各種パラメーターを指定してエディット設定オブジェクトを構築します。
    102         *
    103         * @param editName エディット名称
    104         * @param viewClms 画面表示カラム
    105         * @param sumClms 集計カラム
    106         * @param groupClms グループカラム
    107         * @param subTotalClms 小計カラム
    108         * @param totalClms 合計カラム
    109         * @param useGrandTotal 総合計行を追加するか(1:追加する 1以外:追加しない)
    110         * @param orderByClms 表示順
    111         * @param isCommon 共通エディットかどうか(1:共通 1以外:個人のみ)
    112         */
    113        public DBEditConfig( final String editName, final String viewClms
    114                                                , final String sumClms, final String groupClms
    115                                                , final String subTotalClms, final String totalClms
    116                                                , final String useGrandTotal, final String orderByClms
    117                                                , final String isCommon ) {
    118
    119                editVals[EDIT_KEY_NAME]                 = editName;
    120                editVals[EDIT_KEY_VIEW]                 = viewClms;
    121                editVals[EDIT_KEY_SUM]                  = sumClms;
    122                editVals[EDIT_KEY_GROUP]                = groupClms;
    123                editVals[EDIT_KEY_SUBTOTAL]             = subTotalClms;
    124                editVals[EDIT_KEY_TOTAL]                = totalClms;
    125                editVals[EDIT_KEY_GRANDTOTAL]   = useGrandTotal;
    126                editVals[EDIT_KEY_ORDERBY]              = orderByClms;
    127                editVals[EDIT_KEY_COMMON]               = isCommon;
    128
    129                init();
    130        }
    131
    132        /**
    133         * コンストラクタ
    134         *
    135         * 各種パラメーターを配列で指定してエディット設定オブジェクトを構築します。
    136         * 各パラメータの配列インデックスは、{@link #getEditKeys(String,String)}で返される
    137         * キー一覧の配列インデックスと一致します。
    138         * 各パラメーターの意味については、クラスのJavadoc{@link DBEditConfig}を参照して下さい。
    139         *
    140         * @param editVals 設定値(配列)
    141         * @see DBEditConfig
    142         * @see #getEditKeys(String,String)
    143         **/
    144        public DBEditConfig( final String[] editVals ) {
    145                System.arraycopy( editVals, 0, this.editVals, 0, editVals.length );
    146                init();
    147        }
    148
    149        /**
    150         * エディット設定オブジェクト作成時の初期化処理です。
    151         * コンストラクタの引数に基づき内部変数の初期設定を行います。
    152         */
    153        private void init() {
    154                sumClmCount = StringUtil.csv2Array( editVals[EDIT_KEY_SUM] ).length;
    155                groupClmCount = StringUtil.csv2Array( editVals[EDIT_KEY_GROUP] ).length;
    156                subTotalClmCount = StringUtil.csv2Array( editVals[EDIT_KEY_SUBTOTAL] ).length;
    157                totalClmCount = StringUtil.csv2Array( editVals[EDIT_KEY_TOTAL] ).length;
    158
    159                if( editVals[EDIT_KEY_ORDERBY] != null ) {
    160                        StringBuilder buf = new StringBuilder();
    161                        String[] ary = StringUtil.csv2Array( editVals[EDIT_KEY_ORDERBY] );
    162                        for( int i=0; i<ary.length ;i++ ) {
    163                                String str = ary[i];
    164                                if( str.startsWith( "!" ) ) {
    165                                        str = str.substring( 1 );
    166                                        if( buf.length() > 0 ) { buf.append( "," ); }
    167                                        buf.append( str );
    168                                }
    169                                orderMap.put( str, String.valueOf( i+1 ) );
    170                        }
    171                        orderByDescClms = buf.toString();
    172                }
    173                else {
    174                        orderByDescClms = null;
    175                }
    176        }
    177
    178        /**
    179         * キー配列から画面IDとエディット名称のペアの一覧を取り出します。
    180         *
    181         * キー配列から"EDIT_NAME_"で始まるキーを検索し、"EDIT_NAME_(画面ID)_(エディット名)"
    182         * と言う形式に基づき、画面IDとエディット名称のペアを取り出します。
    183         *
    184         * 画面IDとエディット名称は配列として保存され(インデックス番号は 0:画面ID、1:エディット名)
    185         * その一覧がされらに配列に格納されて返されます。
    186         *
    187         * @param keys キー配列
    188         *
    189         * @return 画面IDとエディット名称のペアの一覧
    190         */
    191        public static String[][] getKeySet( final String[] keys ) {
    192                if( keys == null || keys.length == 0 ) { return null; }
    193
    194                Set<String[]> keySet = new HashSet<String[]>();
    195                for( String key : keys ) {
    196                        if ( key != null && key.startsWith( "EDIT_NAME_" ) ) {
    197                                String guikeyEditName = key.substring( ( "EDIT_NAME_" ).length() );
    198                                if( guikeyEditName.indexOf( '_' ) >= 0 ) {
    199                                        String guikey = guikeyEditName.substring( 0, guikeyEditName.indexOf( '_' ) );
    200                                        String editName = guikeyEditName.substring( ( guikey + "_" ).length() );
    201                                        if( guikey != null && guikey.length() > 0 && editName != null && editName.length() > 0 ) {
    202                                                String[] set = { guikey, editName };
    203                                                keySet.add( set );
    204                                        }
    205                                }
    206                        }
    207                }
    208//              return keySet.toArray( new String[0][] );
    209                return keySet.toArray( new String[keySet.size()][] );
    210        }
    211
    212        /**
    213         * 画面ID、エディット名をキーに、エディット設定オブジェクトの各設定値の
    214         * 管理キーを指定します。
    215         *
    216         * エディット設定オブジェクトで管理される各キーに対して、
    217         * "EDIT_[KEY]_(画面ID)_(エディット名)"というキーを生成し、これを配列にして返します。
    218         *
    219         * @param guikey 画面ID
    220         * @param editName エディット名
    221         *
    222         * @return エディット設定を管理するためのキー一覧
    223         */
    224        public static String[] getEditKeys( final String guikey, final String editName ) {
    225                String[] rtn = new String[EDIT_KEYS_LENGTH];
    226                for( int i=0; i<EDIT_KEYS_LENGTH; i++ ) {
    227                        rtn[i] = "EDIT_" + EDIT_KEYS[i] + "_" + guikey + "_" + editName;
    228                }
    229                return rtn;
    230        }
    231
    232        /**
    233         * エディット設定オブジェクトの各設定値を配列にして返します。
    234         *
    235         * 配列のインデックス番号は、{@link #getEditKeys(String,String)}で生成されるキーの
    236         * インデックス番号と一致します。
    237         *
    238         * @return エディット設定オブジェクトの設定値一覧(配列)
    239         * @see #getEditKeys(String,String)
    240         */
    241        public String[] getEditVals() {
    242                String[] rtn = new String[editVals.length];
    243                System.arraycopy( editVals, 0, rtn, 0, editVals.length );
    244                return rtn;
    245        }
    246
    247        /**
    248         * エディット名を返します。
    249         *
    250         * @return エディット名
    251         */
    252        public String getEditName() {
    253                return editVals[EDIT_KEY_NAME];
    254        }
    255
    256        /**
    257         * 表示カラム名の一覧をカンマ区切りで返します。
    258         * 非表示カラムについては、カラム名の先頭に"!"をつけて返されます。
    259         * 例) AAA,!BBB,CCC ⇒ AAA,CCCの順に表示(BBBは非表示)
    260         *
    261         * @return 表示カラム名一覧(カンマ区切り)
    262         */
    263        public String getViewClms() {
    264                return editVals[EDIT_KEY_VIEW];
    265        }
    266
    267        /**
    268         * 表示カラム(CSV形式)をチェックし、変更があれば、反映したカラムを作成します。
    269         *
    270         * 表示カラムは、並び順や非表示マーカー(!)などが加味され、ユーザー、画面ごとに
    271         * データベースに記録されています。JSPソースを修正した場合、データベースに
    272         * 書き込まれた表示カラムは、反映されないため、カラム選択画面等に表示されません。
    273         * そこで、オリジナルのカラムに追加された場合は、カラムを比較することで、
    274         * 追加分のカラムを、非表示カラムとして、後ろに追記します。
    275         * 削除された場合は、ViewForm で警告表示することで、ユーザーに変更を促します。
    276         *
    277         * @og.rev 5.8.2.0 (2014/12/05) JSP修正時の追加カラム対応
    278         *
    279         * @param       orgClms         オリジナルのカラム(CSV形式)
    280         *
    281         * @return      変更後の表示カラム(CSV形式)
    282         */
    283        public String getViewClms( final String orgClms ) {
    284                String viewClms = editVals[EDIT_KEY_VIEW];
    285
    286                if( orgClms == null || orgClms.isEmpty() ) { return viewClms; }         // orgClms がなければ、viewClms を返す。
    287                // 基本的には、両者のカラムは、一致するはず。
    288                String[] vclms = viewClms.split( "," );         // 表示順、非表示処理を行ったカラム
    289                String[] fclms = orgClms.split( "," );          // 元々の表示可能カラムすべて(fullClms)
    290
    291                // 表示可能カラムすべての Set を作成します。
    292                Set<String> fset = new HashSet<String>();
    293                for( int i=0; i<fclms.length; i++ ) {                // orgClms をSet に追加します。
    294                        fset.add( fclms[i] );
    295                }
    296
    297                // 非表示カラムの内、表示可能カラムに存在しない分だけの Set を作成します。
    298                // また、表示可能カラムから、順番に、viewClms の値を削除していきます。
    299                Set<String> vset = new HashSet<String>();
    300                StringBuilder vbuf = new StringBuilder();       // 新しい viewClms 作成用
    301                for( int i=0; i<vclms.length; i++ ) {                // viewClms をSet に追加します。
    302                        String clm = vclms[i];
    303                        if( clm == null || clm.isEmpty() ) { continue; }                        // 6.0.2.5 (2014/10/31) 潜在バグ？ 先頭に"," が来るとアベンドする。
    304                        clm = clm.charAt(0) == '!' ? clm.substring(1) : clm ;           // 非表示の (!) は削除します。
    305                        if( fset.remove( clm ) ) {                              // fullSet にあれば、削除するとともに、新viewClmsを作成する。
    306                                if( vbuf.length() > 0 ) { vbuf.append(','); }        // 最初以降は、カンマで連結する。              // 6.0.2.5 (2014/10/31) char を append する。
    307                                vbuf.append( vclms[i] );                        // append するのは、(!) 付のカラム
    308                        }
    309                        else {
    310                                vset.add( clm );                                        // fullSet になければ、viewSet に追加
    311                        }
    312                }
    313
    314                // この段階で、fset、vset ともに、それぞれ独自のカラムが残っている。
    315                // どちらも、残っていなければ、正常なので、viewClms を返す。
    316                if( vset.isEmpty() && fset.isEmpty() ) { return viewClms; }
    317
    318                // fullSet にカラムが残っていれば、非表示で、新viewClmsに、追加する。
    319                if( !fset.isEmpty() ) {
    320                        String[] defClms = fset.toArray( new String[fset.size()] );
    321                        for( int i=0; i<defClms.length; i++ ) {
    322                                if( vbuf.length() > 0 ) { vbuf.append(','); }        // 6.0.2.5 (2014/10/31) 最初以降は、カンマで連結する。
    323                                vbuf.append('!').append( defClms[i] );                                          // 非表示カラムとして、後ろに追加する。
    324                        }
    325                }
    326                viewClms = vbuf.toString();
    327
    328                editVals[EDIT_KEY_VIEW] = viewClms;
    329                return viewClms;
    330        }
    331
    332        /**
    333         * 集計カラムの一覧をカンマ区切りで返します。
    334         *
    335         * @return 集計カラムの一覧(カンマ区切)
    336         */
    337        public String getSumClms() {
    338                return editVals[EDIT_KEY_SUM];
    339        }
    340
    341        /**
    342         * 集計処理を行うかどうかを返します。
    343         * これは、集計カラムが指定されているか、と同じ意味です。
    344         *
    345         * @return true:対象 false:非対象
    346         */
    347        public boolean useSum() {
    348                return ( editVals[EDIT_KEY_SUM] != null && editVals[EDIT_KEY_SUM].length() > 0 );
    349        }
    350
    351        /**
    352         * 指定されたカラムが集計対象のカラムかどうかを返します。
    353         *
    354         * @param clm カラム
    355         *
    356         * @return true:対象 false:非対象
    357         */
    358        public boolean isSumClm( final String clm ) {
    359                if( clm == null || editVals[EDIT_KEY_SUM] == null ) { return false; }
    360                return ( ( ","+editVals[EDIT_KEY_SUM]+"," ).indexOf( ","+clm+"," ) >= 0 );
    361        }
    362
    363        /**
    364         * 集計カラムのカラム数を返します。
    365         *
    366         * @return 集計カラムのカラム数
    367         */
    368        public int getSumClmCount() {
    369                return sumClmCount;
    370        }
    371
    372        /**
    373         * グループカラムの一覧をカンマ区切りで返します。
    374         *
    375         * @return グループカラムの一覧(カンマ区切)
    376         */
    377        public String getGroupClms() {
    378                return editVals[EDIT_KEY_GROUP];
    379        }
    380
    381        /**
    382         * グループ処理を行うかどうかを返します。
    383         * これは、グループカラムが指定されているか、と同じ意味です。
    384         *
    385         * @return true:対象 false:非対象
    386         */
    387        public boolean useGroup() {
    388                return ( editVals[EDIT_KEY_GROUP] != null && editVals[EDIT_KEY_GROUP].length() > 0 );
    389        }
    390
    391        /**
    392         * 指定されたカラムがグループ対象のカラムかどうかを返します。
    393         *
    394         * @param clm カラム
    395         *
    396         * @return true:対象 false:非対象
    397         */
    398        public boolean isGroupClm( final String clm ) {
    399                if( clm == null || editVals[EDIT_KEY_GROUP] == null ) { return false; }
    400                return ( ( ","+editVals[EDIT_KEY_GROUP]+"," ).indexOf( ","+clm+"," ) >= 0 );
    401        }
    402
    403        /**
    404         * グループカラムのカラム数を返します。
    405         *
    406         * @return グループカラムのカラム数
    407         */
    408        public int getGroupClmCount() {
    409                return groupClmCount;
    410        }
    411
    412        /**
    413         * 小計カラムの一覧をカンマ区切りで返します。
    414         *
    415         * @return 小計カラムの一覧(カンマ区切)
    416         */
    417        public String getSubTotalClms() {
    418                return editVals[EDIT_KEY_SUBTOTAL];
    419        }
    420
    421        /**
    422         * 小計処理を行うかどうかを返します。
    423         * これは、小計カラムが指定されているか、と同じ意味です。
    424         *
    425         * @return true:対象 false:非対象
    426         */
    427        public boolean useSubTotal() {
    428                return ( editVals[EDIT_KEY_SUBTOTAL] != null && editVals[EDIT_KEY_SUBTOTAL].length() > 0 );
    429        }
    430
    431        /**
    432         * 指定されたカラムが小計対象のカラムかどうかを返します。
    433         *
    434         * @param clm カラム
    435         *
    436         * @return true:対象 false:非対象
    437         */
    438        public boolean isSubTotalClm( final String clm ) {
    439                if( clm == null || editVals[EDIT_KEY_SUBTOTAL] == null ) { return false; }
    440                return ( ( ","+editVals[EDIT_KEY_SUBTOTAL]+"," ).indexOf( ","+clm+"," ) >= 0 );
    441        }
    442
    443        /**
    444         * 小計カラムのカラム数を返します。
    445         *
    446         * @return グループカラムのカラム数
    447         */
    448        public int getSubTotalClmCount() {
    449                return subTotalClmCount;
    450        }
    451
    452        /**
    453         * 合計カラムの一覧をカンマ区切りで返します。
    454         *
    455         * @return 合計カラムの一覧(カンマ区切)
    456         */
    457        public String getTotalClms() {
    458                return editVals[EDIT_KEY_TOTAL];
    459        }
    460
    461        /**
    462         * 合計処理を行うかどうかを返します。
    463         * これは、合計カラムが指定されているか、と同じ意味です。
    464         *
    465         * @return true:対象 false:非対象
    466         */
    467        public boolean useTotal() {
    468                return ( editVals[EDIT_KEY_TOTAL] != null && editVals[EDIT_KEY_TOTAL].length() > 0 );
    469        }
    470
    471        /**
    472         * 指定されたカラムが合計対象のカラムかどうかを返します。
    473         *
    474         * @param clm カラム
    475         *
    476         * @return true:対象 false:非対象
    477         */
    478        public boolean isTotalClm( final String clm ) {
    479                if( clm == null || editVals[EDIT_KEY_TOTAL] == null ) { return false; }
    480                return ( ( ","+editVals[EDIT_KEY_TOTAL]+"," ).indexOf( ","+clm+"," ) >= 0 );
    481        }
    482
    483        /**
    484         * 合計カラムのカラム数を返します。
    485         *
    486         * @return グループカラムのカラム数
    487         */
    488        public int getTotalClmCount() {
    489                return totalClmCount;
    490        }
    491
    492        /**
    493         * 総合計行を付加するかどうかを返します。
    494         *
    495         * @return true:対象 false:非対象
    496         */
    497        public boolean useGrandTotal() {
    498                return StringUtil.nval( editVals[EDIT_KEY_GRANDTOTAL], false );
    499        }
    500
    501        /**
    502         * 表示順カラムをカンマ区切りで返します。
    503         * カラムの並び順が表示順としての優先順になります。
    504         * また、降順で表示するカラムについては、カラム名の先頭に"!"が付加されます。
    505         *
    506         * @return 標準順カラムの一覧(カンマ区切)
    507         */
    508        public String getOrderByClms() {
    509                return editVals[EDIT_KEY_ORDERBY];
    510        }
    511
    512        /**
    513         * 指定されたカラムの表示順の優先番号を返します。
    514         * 指定カラムが標準として指定されていない場合は、""(ゼロストリング)を返します。
    515         *
    516         * @param clm カラム
    517         *
    518         * @return 表示順の優先番号
    519         */
    520        public String getOrder( final String clm ) {
    521                if( clm == null || editVals[EDIT_KEY_ORDERBY] == null ) { return ""; }
    522
    523                String rtn = orderMap.get( clm );
    524                return ( rtn == null ? "" : rtn );
    525        }
    526
    527        /**
    528         * 指定されたカラムの表示順指定が降順であるかどうかを返します。
    529         * 標準と指定されていない場合は、falseを返します。
    530         *
    531         * @param clm カラム
    532         *
    533         * @return true:降順 false:昇順
    534         */
    535        public boolean isOrderByDesc( final String clm ) {
    536                if( clm == null || orderByDescClms == null ) { return false; }
    537                return ( ( ","+orderByDescClms+"," ).indexOf( ","+clm+"," ) >= 0 );
    538        }
    539
    540        /**
    541         * 並び替え処理を行うかどうかを返します。
    542         * これは、表示順カラムが指定されているか、と同じ意味です。
    543         *
    544         * @return true:対象 false:非対象
    545         */
    546        public boolean useOrderBy() {
    547                return ( editVals[EDIT_KEY_ORDERBY] != null && editVals[EDIT_KEY_ORDERBY].length() > 0 );
    548        }
    549
    550        /**
    551         * このエディット設定オブジェクトが、共通(全ユーザー公開)エディットか
    552         * どうかを返します。
    553         *
    554         * @return 0以外:共通 0:個人のみ
    555         */
    556        public boolean isCommon() {
    557                return StringUtil.nval( editVals[EDIT_KEY_COMMON], false );
    558        }
    559}