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.hayabusa.common.HybsSystemException;                        // 6.4.5.0 (2016/04/08)
019
020import java.util.Arrays;
021import java.util.Comparator;
022import java.util.Map;
023import java.util.HashMap;
024import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
025import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.1 (2016/02/12) refactoring
026import java.io.Serializable;
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
088                for( final String key : keys ) {
089                        if( key == null ) { continue; }
090
091                        // 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
092                        if( key.startsWith( SLCT_KEY ) ) {
093                                final String editName = attribute.get( key );
094                                if( editName == null || editName.isEmpty() ) {
095                                        attribute.remove( key );                // editName の存在しない EDIT_SELECTED_ キーは削除します。
096                                        continue;
097                                }
098
099                                final String guikey = key.substring( SLCT_LEN );        // "EDIT_SELECTED_" の後ろが画面ID
100                                if( guikey != null && guikey.length() > 0 ) {
101                                        editSelMap.put( guikey , editName );
102                                }
103                        }
104
105                        if( key.startsWith( NAME_KEY ) ) {
106                                final String editName = attribute.get( key );
107                                if( editName == null || editName.isEmpty() ) {
108                                        attribute.remove( key );                // editName の存在しない EDIT_NAME_ キーは削除します。
109                                        continue;
110                                }
111
112                                // "EDIT_NAME_" より後ろで、editName の頭までが、画面ID
113                                // (ただし、後ろにアンダーバーが付いているので、さらに、1文字削除対象を増やす。)
114                                final int last = key.lastIndexOf(editName)-1 ;
115                                if( last < 0 ) {                                        // 一致しない場合は、キーが違うから。
116                                        attribute.remove( key );                // editName の一致しない EDIT_NAME_ キーは削除します。
117                                        continue;
118                                }
119
120                                final String guikey = key.substring( NAME_LEN,last );
121                                if( guikey != null && guikey.length() > 0 ) {
122                                        final String[] editKeys = DBEditConfig.getEditKeys( guikey, editName );
123                                        String[] editVals = new String[editKeys.length];
124                                        for( int i=0; i<editKeys.length; i++ ) {
125                                                editVals[i] = attribute.get( editKeys[i] );
126                                        }
127                                        // Map#computeIfAbsent : 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし
128                                        editConfigMap.computeIfAbsent( guikey , k -> new HashMap<>() ).put( editName , new DBEditConfig( editVals ) );
129                                }
130                        }
131                }
132        }
133
134        /**
135         * 編集設定オブジェクトを追加します。
136         *
137         * ここでの追加はあくまでメモリ上での登録になります。
138         * 登録した内容を永続的に登録する場合は、別途DBへの登録が必要になります。
139         *
140         * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
141         *
142         * @param guikey 画面ID
143         * @param editName 編集名
144         * @param config 編集設定オブジェクト
145         */
146        public void addEditConfig( final String guikey, final String editName, final DBEditConfig config ) {
147                // 6.4.3.1 (2016/02/12) ConcurrentMap 系は、key,val ともに not null 制限です。
148                if( guikey != null && editName != null && config != null ) {
149
150                        // Map#computeIfAbsent : 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし
151                        final Map<String,DBEditConfig> confMap = editConfigMap.computeIfAbsent( guikey , k -> new HashMap<>() );
152                        final DBEditConfig oldConf = confMap.get( editName );
153
154                        // 個別設定と共通設定は、同じキーでは登録できません。
155                        if( oldConf != null && oldConf.isCommon() != config.isCommon() ) {
156                                final String errMsg = "個別設定と共通設定は、同じキーでは登録できません。";
157                                throw new HybsSystemException( errMsg );
158                        }
159                        confMap.put( editName , config );
160                }
161        }
162
163        /**
164         * 編集設定オブジェクトを削除します。
165         *
166         * ここでの追加はあくまでメモリ上での削除になります。
167         * 登録した内容を永続的に削除する場合は、別途DBへの登録が必要になります。
168         *
169         * @og.rev 6.4.3.2 (2016/02/19) ConcurrentHashMap の同期処理を使用。
170         * @og.rev 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
171         *
172         * @param guikey 画面ID
173         * @param editName 編集名
174         *
175         * @return 編集設定オブジェクト
176         */
177        public DBEditConfig deleteEditConfig( final String guikey, final String editName ) {
178                // 6.4.3.2 (2016/02/19) ConcurrentHashMap は、key,val ともに、NOT NULL制限があります。
179                if( guikey   == null || guikey.isEmpty() ||
180                        editName == null || editName.isEmpty() ) { return null; }
181
182                final Map<String,DBEditConfig> ecMap = editConfigMap.get( guikey );
183
184                return ecMap == null ? null : ecMap.remove( editName );
185        }
186
187        /**
188         * 編集設定オブジェクトを取得します。
189         *
190         * @og.rev 6.4.3.2 (2016/02/19) ConcurrentHashMap の同期処理を使用。
191         * @og.rev 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
192         *
193         * @param guikey 画面ID
194         * @param editName 編集名
195         *
196         * @return 編集設定オブジェクト
197         */
198        public DBEditConfig getEditConfig( final String guikey, final String editName ) {
199                // 6.4.3.2 (2016/02/19) ConcurrentHashMap は、key,val ともに、NOT NULL制限があります。
200                if( guikey   == null || guikey.isEmpty() ||
201                        editName == null || editName.isEmpty() ) { return null; }
202
203                final Map<String,DBEditConfig> ecMap = editConfigMap.get( guikey );
204
205                return ecMap == null ? null : ecMap.get( editName );
206        }
207
208        /**
209         * 画面IDをキーに編集設定の一覧(配列)を返します。
210         * 返される配列は、編集名順にソートされた状態で返されます。
211         *
212         * @og.rev 6.1.0.0 (2014/12/26) refactoring: null ではなく長さが0の配列を返す。
213         *
214         * @param guikey 画面ID
215         *
216         * @return 編集設定一覧(配列)
217         * @og.rtnNotNull
218         */
219        public DBEditConfig[] getEditConfigs( final String guikey ) {
220                if( guikey == null || guikey.isEmpty() ) { return new DBEditConfig[0] ; }       // 6.1.0.0 (2014/12/26)
221
222                final Map<String,DBEditConfig> map = editConfigMap.get( guikey );
223                if( map == null ) { return new DBEditConfig[0]; }                                                       // 6.1.0.0 (2014/12/26)
224
225                final DBEditConfig[] configs = map.values().toArray( new DBEditConfig[map.size()] );    // 6.0.2.5 (2014/10/31) refactoring
226                // 6.0.2.5 (2014/10/31) findBugs対応:名前付き static 内部クラスにリファクタリングできるかもしれません。
227                Arrays.sort( configs , new EditConfigComparator() );
228
229                return configs;
230        }
231
232        /**
233         * 指定の画面IDに対して選択済みの編集名を返します。
234         *
235         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
236         * @og.rev 6.0.2.2 (2014/10/03) EDIT_NAME_SELECTED_ を、EDIT_SELECTED_ に変更
237         * @og.rev 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
238         *
239         * @param guikey 画面ID
240         *
241         * @return 選択済み編集名
242         */
243        public String getSelectedEdit( final String guikey ) {
244                return editSelMap.get( SLCT_KEY + guikey );
245        }
246
247        /**
248         * DBEditConfig  比較用の Comparator 実装です。
249         * 名前なしclass から、名前あり staticクラスに格上げです。
250         *
251         * @og.rev 6.0.2.5 (2014/10/31) findBugs対応:新規追加
252         */
253        private static final class EditConfigComparator implements Comparator<DBEditConfig>, Serializable {
254                private static final long serialVersionUID = 602520141024L ;
255
256                /**
257                 * DBEditConfig  比較メソッド
258                 * インタフェース Comparable の 実装です。
259                 *
260                 * @og.rev 6.0.2.5 (2014/10/31) findBugs対応:新規追加
261                 *
262                 * @param c1 比較対象の最初のオブジェクト
263                 * @param c2 比較対象の 2 番目のオブジェクト
264                 * @return      最初の引数が 2 番目の引数より小さい場合は負の整数、両方が等しい場合は 0、最初の引数が 2 番目の引数より大きい場合は正の整数
265                 */
266                @Override       // Comparator
267                public int compare( final DBEditConfig c1, final DBEditConfig c2 ) {
268                        return c1 == null ? -1 : c1.getEditName().compareTo( c2.getEditName() ) ;
269                }
270        }
271}