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