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.Arrays;
019import java.util.Comparator;
020import java.util.Map;
021import java.util.HashMap;
022import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
023import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.1 (2016/02/12) refactoring
024import java.io.Serializable;
025
026import org.opengion.hayabusa.common.HybsSystemException;                        // 6.4.5.0 (2016/04/08)
027
028/**
029 * ユーザー単位の編集設定情報を管理するためのクラスです。
030 *
031 * 画面ID+編集名をキーとして編集設定オブジェクトの
032 * 追加、削除、参照を行います。
033 *
034 * @og.rev 5.3.6.0 (2011/06/01) 新規追加
035 *
036 * @version  5.0
037 * @author   Hiroki Nakamura
038 * @since    JDK6.0,
039 */
040public class DBEditConfigManager {
041
042        // 編集設定情報の管理オブジェクト(画面ID+編集名単位で管理)
043        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 */
044        private final ConcurrentMap<String,Map<String,DBEditConfig>> editConfigMap = new ConcurrentHashMap<>();
045
046        private static final String NAME_KEY = "EDIT_NAME_" ;                   // 6.4.5.0 (2016/04/08)
047        private static final int    NAME_LEN = NAME_KEY.length();               // 6.4.5.0 (2016/04/08)
048
049        /** EDIT_SELECTED_ + 画面ID で、設定される 選択中編集名を記録します。 */
050        private final ConcurrentMap<String,String> editSelMap = new ConcurrentHashMap<>();
051
052        private static final String SLCT_KEY = "EDIT_SELECTED_" ;               // 6.4.5.0 (2016/04/08)
053        private static final int    SLCT_LEN = SLCT_KEY.length();               // 6.4.5.0 (2016/04/08)
054
055        /**
056         * デフォルトコンストラクター
057         *
058         * 互換性を考慮し、デフォルトコンストラクターは残しておきます。
059         *
060         * @og.rev 6.0.2.2 (2014/10/03) 新規追加
061         */
062        public DBEditConfigManager() { super(); }               // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
063
064        /**
065         * 引数付コンストラクター
066         *
067         * UserInfo の Map&lt;String,String&gt; attribute から、EDIT_NAME_ で始まるキーワードを
068         * 取り出して、DBEditConfig オブジェクトを作成します。
069         * attribute には、"EDIT_NAME_(画面ID)_(編集名)" というキー情報があるので、
070         * 画面IDと編集名を分離し、DBEditConfig の各キーと再び合成して、attribute から、
071         * 設定値を取り出します。
072         * ただし、画面IDや、編集名 にも、アンダーバーが含まれている可能性がある為、
073         * EDIT_NAME_(画面ID)_(編集名) の値である、編集名 を使用して、分離します。
074         * そのキーと値の配列を元に作成された DBEditConfig オブジェクトを、内部Map に画面IDを
075         * キーに設定します。
076         *
077         * 元々、UserInfo#makeEditConfigMap() で処理していた内容を、こちらに移植しました。
078         *
079         * @og.rev 6.0.2.2 (2014/10/03) 新規追加。DBEditConfig から、移動
080         * @og.rev 6.3.9.1 (2015/11/27) getEditKeys(String,String) は、DBEditConfigManager ⇒ DBEditConfig へ移動。
081         * @og.rev 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
082         *
083         * @param attribute     UserInfo の 属性Map
084         */
085        public DBEditConfigManager( final Map<String,String> attribute ) {
086//              final String[] keys = attribute.keySet().toArray( new String[attribute.size()] );
087                final String[] keys = attribute.keySet().toArray( new String[0] );      // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
088
089                for( final String key : keys ) {
090                        if( key == null ) { continue; }
091
092                        // 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
093                        if( key.startsWith( SLCT_KEY ) ) {
094                                final String editName = attribute.get( key );
095                                if( editName == null || editName.isEmpty() ) {
096                                        attribute.remove( key );                // editName の存在しない EDIT_SELECTED_ キーは削除します。
097                                        continue;
098                                }
099
100                                final String guikey = key.substring( SLCT_LEN );        // "EDIT_SELECTED_" の後ろが画面ID
101                                if( guikey != null && guikey.length() > 0 ) {
102                                        editSelMap.put( guikey , editName );
103                                }
104                        }
105
106                        if( key.startsWith( NAME_KEY ) ) {
107                                final String editName = attribute.get( key );
108                                if( editName == null || editName.isEmpty() ) {
109                                        attribute.remove( key );                // editName の存在しない EDIT_NAME_ キーは削除します。
110                                        continue;
111                                }
112
113                                // "EDIT_NAME_" より後ろで、editName の頭までが、画面ID
114                                // (ただし、後ろにアンダーバーが付いているので、さらに、1文字削除対象を増やす。)
115                                final int last = key.lastIndexOf(editName)-1 ;
116                                if( last < 0 ) {                                        // 一致しない場合は、キーが違うから。
117                                        attribute.remove( key );                // editName の一致しない EDIT_NAME_ キーは削除します。
118                                        continue;
119                                }
120
121                                final String guikey = key.substring( NAME_LEN,last );
122                                if( guikey != null && guikey.length() > 0 ) {
123                                        final String[] editKeys = DBEditConfig.getEditKeys( guikey, editName );
124                                        final String[] editVals = new String[editKeys.length];          // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal
125                                        for( int i=0; i<editKeys.length; i++ ) {
126                                                editVals[i] = attribute.get( editKeys[i] );
127                                        }
128                                        // Map#computeIfAbsent : 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし
129                                        editConfigMap.computeIfAbsent( guikey , k -> new HashMap<>() ).put( editName , new DBEditConfig( editVals ) );
130                                }
131                        }
132                }
133        }
134
135        /**
136         * 編集設定オブジェクトを追加します。
137         *
138         * ここでの追加はあくまでメモリ上での登録になります。
139         * 登録した内容を永続的に登録する場合は、別途DBへの登録が必要になります。
140         *
141         * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
142         *
143         * @param guikey 画面ID
144         * @param editName 編集名
145         * @param config 編集設定オブジェクト
146         */
147        public void addEditConfig( final String guikey, final String editName, final DBEditConfig config ) {
148                // 6.4.3.1 (2016/02/12) ConcurrentMap 系は、key,val ともに not null 制限です。
149                if( guikey != null && editName != null && config != null ) {
150
151                        // Map#computeIfAbsent : 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし
152                        final Map<String,DBEditConfig> confMap = editConfigMap.computeIfAbsent( guikey , k -> new HashMap<>() );
153                        final DBEditConfig oldConf = confMap.get( editName );
154
155                        // 個別設定と共通設定は、同じキーでは登録できません。
156                        if( oldConf != null && oldConf.isCommon() != config.isCommon() ) {
157                                final String errMsg = "個別設定と共通設定は、同じキーでは登録できません。";
158                                throw new HybsSystemException( errMsg );
159                        }
160                        confMap.put( editName , config );
161                }
162        }
163
164        /**
165         * 編集設定オブジェクトを削除します。
166         *
167         * ここでの追加はあくまでメモリ上での削除になります。
168         * 登録した内容を永続的に削除する場合は、別途DBへの登録が必要になります。
169         *
170         * @og.rev 6.4.3.2 (2016/02/19) ConcurrentHashMap の同期処理を使用。
171         * @og.rev 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
172         *
173         * @param guikey 画面ID
174         * @param editName 編集名
175         *
176         * @return 編集設定オブジェクト
177         */
178        public DBEditConfig deleteEditConfig( final String guikey, final String editName ) {
179                // 6.4.3.2 (2016/02/19) ConcurrentHashMap は、key,val ともに、NOT NULL制限があります。
180                if( guikey   == null || guikey.isEmpty() ||
181                        editName == null || editName.isEmpty() ) { return null; }
182
183                final Map<String,DBEditConfig> ecMap = editConfigMap.get( guikey );
184
185                return ecMap == null ? null : ecMap.remove( editName );
186        }
187
188        /**
189         * 編集設定オブジェクトを取得します。
190         *
191         * @og.rev 6.4.3.2 (2016/02/19) ConcurrentHashMap の同期処理を使用。
192         * @og.rev 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
193         *
194         * @param guikey 画面ID
195         * @param editName 編集名
196         *
197         * @return 編集設定オブジェクト
198         */
199        public DBEditConfig getEditConfig( final String guikey, final String editName ) {
200                // 6.4.3.2 (2016/02/19) ConcurrentHashMap は、key,val ともに、NOT NULL制限があります。
201                if( guikey   == null || guikey.isEmpty() ||
202                        editName == null || editName.isEmpty() ) { return null; }
203
204                final Map<String,DBEditConfig> ecMap = editConfigMap.get( guikey );
205
206                return ecMap == null ? null : ecMap.get( editName );
207        }
208
209        /**
210         * 画面IDをキーに編集設定の一覧(配列)を返します。
211         * 返される配列は、編集名順にソートされた状態で返されます。
212         *
213         * @og.rev 6.1.0.0 (2014/12/26) refactoring: null ではなく長さが0の配列を返す。
214         *
215         * @param guikey 画面ID
216         *
217         * @return 編集設定一覧(配列)
218         * @og.rtnNotNull
219         */
220        public DBEditConfig[] getEditConfigs( final String guikey ) {
221                if( guikey == null || guikey.isEmpty() ) { return new DBEditConfig[0] ; }       // 6.1.0.0 (2014/12/26)
222
223                // 8.5.5.1 (2024/02/29) PMD 7.0.0 OnlyOneReturn メソッドには終了ポイントが 1 つだけ必要
224                final DBEditConfig[] configs;
225
226                final Map<String,DBEditConfig> map = editConfigMap.get( guikey );
227//              if( map == null ) { return new DBEditConfig[0]; }                                                       // 6.1.0.0 (2014/12/26)
228                if( map == null ) { configs = new DBEditConfig[0]; }                                            // 6.1.0.0 (2014/12/26)
229                else {
230//                      final DBEditConfig[] configs = map.values().toArray( new DBEditConfig[map.size()] );    // 6.0.2.5 (2014/10/31) refactoring
231//                      final DBEditConfig[] configs = map.values().toArray( new DBEditConfig[0] );     // 6.0.2.5 (2014/10/31) refactoring  // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
232                        configs = map.values().toArray( new DBEditConfig[0] );                                  // 6.0.2.5 (2014/10/31) refactoring     // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
233                        // 6.0.2.5 (2014/10/31) findBugs対応:名前付き static 内部クラスにリファクタリングできるかもしれません。
234                        Arrays.sort( configs , new EditConfigComparator() );
235                }
236                return configs;
237        }
238
239        /**
240         * 指定の画面IDに対して選択済みの編集名を返します。
241         *
242         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
243         * @og.rev 6.0.2.2 (2014/10/03) EDIT_NAME_SELECTED_ を、EDIT_SELECTED_ に変更
244         * @og.rev 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
245         *
246         * @param guikey 画面ID
247         *
248         * @return 選択済み編集名
249         */
250        public String getSelectedEdit( final String guikey ) {
251                return editSelMap.get( SLCT_KEY + guikey );
252        }
253
254        /**
255         * DBEditConfig  比較用の Comparator 実装です。
256         * 名前なしclass から、名前あり staticクラスに格上げです。
257         *
258         * @og.rev 6.0.2.5 (2014/10/31) findBugs対応:新規追加
259         */
260        private static final class EditConfigComparator implements Comparator<DBEditConfig>, Serializable {
261                private static final long serialVersionUID = 602520141024L ;
262
263                /**
264                 * デフォルトのコンストラクタ
265                 *
266                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
267                 */
268                public EditConfigComparator() {
269                        super();
270                }
271
272                /**
273                 * DBEditConfig  比較メソッド
274                 * インタフェース Comparable の 実装です。
275                 *
276                 * @og.rev 6.0.2.5 (2014/10/31) findBugs対応:新規追加
277                 *
278                 * @param c1 比較対象の最初のオブジェクト
279                 * @param c2 比較対象の 2 番目のオブジェクト
280                 * @return      最初の引数が 2 番目の引数より小さい場合は負の整数、両方が等しい場合は 0、最初の引数が 2 番目の引数より大きい場合は正の整数
281                 */
282                @Override       // Comparator
283                public int compare( final DBEditConfig c1, final DBEditConfig c2 ) {
284                        return c1 == null ? -1 : c1.getEditName().compareTo( c2.getEditName() ) ;
285                }
286        }
287}