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.fukurou.util;
017
018import java.util.Map ;
019import java.util.LinkedHashMap ;
020import java.util.Collections;                                                                           // 6.4.3.1 (2016/02/12) refactoring
021import java.util.Locale;
022import java.util.Iterator;
023
024import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.1.0.0 (2014/12/26) refactoring
025import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
026
027/**
028 * EnumType.java は、共通的に使用される 文字型選択フィールドを簡素化するクラスです。
029 * JDK5.0 より導入された enum に類似の機能を提供しますが、内部的により特化した
030 * 機能を提供します。
031 * 具体的には、デバッグ情報の簡易出力や、文字列入力時の包含関係チェック、
032 * デフォルト値(初期値)の登録などです。
033 * 初期値には、String,int,boolean の3タイプが指定できます。
034 *
035 * @version  4.0
036 * @author       Kazuhiko Hasegawa
037 * @since    JDK5.0,
038 */
039public final class EnumType<T extends Comparable<T>> {  // 4.3.3.6 (2008/11/15) Generics警告対応
040
041        /** 8つ分のスペースです。 */
042        private static final String SPACE = "    " ;
043
044        /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理を行います。  */
045        private final Map<String,Types<T>> typemap = Collections.synchronizedMap( new LinkedHashMap<>() );
046
047        private final String title  ;
048        private final T      defVal ;
049
050        /**
051         * タイトルと初期値を指定して構築する コンストラクター
052         * nval メソッドを使用する場合に、利用します。
053         *
054         * @param title タイトル
055         * @param val 初期値
056         */
057        public EnumType( final String title,final T val ) {
058                this.title = title ;
059                defVal = val ;
060        }
061
062        /**
063         * キーとその説明(メッセージ)を追加します。
064         * 内部キャッシュ(Map)に追加します。
065         * 通常のメソッド名なら、put か add ですが、return に
066         * 自分自身を記述できるため、初期設定(コンストラクタ)+値設定を
067         * 連続して記述することが出来る append メソッドにちなんで命名しています。
068         *
069         * @param key キー
070         * @param msg メッセージ
071         *
072         * @return      自分自身
073         */
074        public EnumType<T> append( final T key, final String msg ) {
075                typemap.put( String.valueOf( key ).toUpperCase( Locale.JAPAN ),new Types<T>( key,msg ) );
076                return this ;
077        }
078
079        /**
080         * 文字列相当の設定値より、対応する T オブジェクトを返します。
081         * T は、インスタンス作成時に、new EnumType&lt;T&gt; で指定するオブジェクトです。
082         * 引数の文字列は、 String.valueOf( T ) で得られる文字列です。
083         * 引数が、null か、長さゼロの文字列の場合は、コンストラクタで指定した
084         * 初期値が返されます。
085         * T に Boolean や Integer を指定している場合は、アンボクシング機能により、
086         * boolean や int に自動的にキャストされます。
087         *
088         * @param       strKey 文字列相当の設定値
089         *
090         * @return      strKeyに対応するオブジェクト
091         * @throws IllegalArgumentException 引数がMapに存在しなかった場合(nullはOK)
092         */
093        public T nval( final String strKey ) {
094                if( strKey != null && strKey.length() > 0 ) {
095                        final String upKey = strKey.toUpperCase( Locale.JAPAN );
096                        if( typemap.containsKey( upKey ) ) {
097                                final Types<T> type = typemap.get( upKey );
098                                return type.getKey();
099                        }
100                        else {
101                                final String errMsg = title + " 範囲設定エラー"
102                                                        + CR + "引数 [" + strKey + "] は、内部にマップされていません。"
103                                                        + CR + toString() ;
104                                throw new IllegalArgumentException( errMsg );
105                        }
106                }
107                return defVal ;
108        }
109
110        /**
111         * 初期値を返します。
112         * T に Boolean や Integer を指定している場合は、アンボクシング機能により、
113         * boolean や int に自動的にキャストされます。
114         *
115         * @return      初期値オブジェクト
116         */
117        public T getDefault() {
118                return defVal ;
119        }
120
121        /**
122         * 設定した T が存在しているかどうかを返します。
123         * 内部に値を取り込んだ後で使用する、存在チェックです。
124         * 通常、nval で 取り込んだ後は、チェック不要です。
125         * 引数が null の場合は、false を返します。
126         *
127         * @param key T 設定した Tオブジェクト
128         *
129         * @return      存在する:true / 存在しない:false
130         */
131        public boolean contains( final T key ) {
132                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
133                return key != null && typemap.containsKey( String.valueOf( key ).toUpperCase( Locale.JAPAN ) );
134
135        }
136
137        /**
138         * 内部の文字列表現を返します。
139         *
140         * @return      内部の文字列表現
141         * @og.rtnNotNull
142         */
143        @Override
144        public String toString() {
145                // 4.3.3.6 (2008/11/15) Generics警告対応 , toArray から、Iterator に、変更
146                final Iterator<Types<T>> ite = typemap.values().iterator();
147                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
148                buf.append( CR );
149                while( ite.hasNext() ) {
150                        buf.append( SPACE ).append( ite.next() ).append( CR );
151                }
152                return buf.toString();
153        }
154
155        /**
156         * 内部オブジェクトを管理する為の インナークラス
157         * キーオブジェクトとその説明のペアを管理します。
158         *
159         * @version  4.0
160         * @author       Kazuhiko Hasegawa
161         * @since    JDK5.0,
162         */
163        private static final class Types<T> {
164                private final T key ;
165                private final String msg ;
166
167                /**
168                 * キーと説明を指定したコンストラクタ
169                 *
170                 * @param key T キーオブジェクト
171                 * @param       msg     説明
172                 * @throws IllegalArgumentException キーオブジェクトがnullの場合
173                 */
174                public Types( final T key,final String msg ) {
175                        if( key == null ) {
176                                final String errMsg = "key には null をセットできません。" ;
177                                throw new IllegalArgumentException( errMsg );
178                        }
179
180                        this.key = key;
181                        this.msg = msg;
182                }
183
184                /**
185                 * キーオブジェクトを返します。
186                 *
187                 * @return キーオブジェクト
188                 */
189                public T getKey() { return key; }
190
191                /**
192                 * 説明を返します。
193                 *
194                 * @return 説明文字列
195                 */
196                public String getMsg() { return msg; }
197
198                /**
199                 * 内部の文字列表現を返します。
200                 *
201                 * @return      内部の文字列表現
202                 * @og.rtnNotNull
203                 */
204                @Override
205                public String toString() {
206                        return key + " : " + msg ;
207                }
208        }
209}