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     */
016    package org.opengion.fukurou.util;
017    
018    import java.util.Set;
019    import java.util.Map;
020    import java.util.HashMap;
021    import java.util.Arrays;
022    import java.util.Locale;
023    
024    /**
025     * Attributes.java は、String 型キーにString型??Map するクラスです?
026     *
027     * HTMLのPOST/GET等?受け渡しや、String型?引数が多い場合に効果があります?
028     * 特に、getAttributes( String[] param ) による属?リスト作?は?
029     * HTMLタグの属?定義を行う上で?非常に便利に利用できます?
030     *
031     * こ?実??同期化されません?
032     *
033     * @version  4.0
034     * @author   Kazuhiko Hasegawa
035     * @since    JDK5.0,
036     */
037    public final class Attributes {
038            private final Map<String,String> attri ;
039    
040            /**
041             * ?ォルトコンストラクター
042             *
043             */
044            public Attributes() {
045                    attri = new HashMap<String,String>();
046            }
047    
048            /**
049             * Attributesオブジェク?を与えて新しく作?するコンストラクター
050             *
051             * @param att Attributesオブジェク?
052             */
053            public Attributes( final Attributes att ) {
054                    attri = new HashMap<String,String>( att.attri );
055            }
056    
057            /**
058             * マップから??ングをすべて削除しま??
059             *
060             */
061            public void clear()  {
062                    attri.clear() ;
063            }
064    
065            /**
066             * マップが??キーを???する値を返します?
067             * マップがこ?キーのマッピングを保持して???合? null
068             * を返します?戻り?の null は、???がキーのマッピング?
069             * 保持して??とを示すとはかぎりません。つまり?マップが
070             * 明示?キー?null にマップすることもあります?
071             *
072             * @param    key 関連付けられた?が返されるキー(大?小文字?同?)
073             *
074             * @return   マップが、指定されたキーにマッピングして?値?
075             *           こ?キーに対するマッピングが???にな??合? null
076             */
077            public String get( final String key ) {
078                    return attri.get( key.toLowerCase( Locale.JAPAN ) ) ;
079            }
080    
081            /**
082             * ?された値と?されたキーをこのマップに関連付けま?
083             * ?されたキーに、null を関連付けることはできません?
084             * (もちろん?"?ゼロストリング は登録できます?)
085             * なぜなら?getAttribute( String[] keys ) 等で値?null の
086             * キーは、取得できな?です?
087             * また?すでに何らか?値がセ?されて???null をセ?した
088             * 場合??前?値をなにも変更しません?
089             * 通常、?をクリアした??合?? remove( String key ) を利用してください?
090             *
091             * @param    key ?される値が関連付けられるキー(大?小文字?同?)
092             * @param    value ?されるキーに関連付けられる?
093             */
094            public void set( final String key,final String value ) {
095                    if( value != null ) {
096                            attri.put( key.toLowerCase( Locale.JAPAN ),value ) ;
097                    }
098            }
099    
100            /**
101             * ?された値と?されたキーをこのマップに関連付けま?
102             * set( String key,String value ) との違いは?value ?null
103             * の場合に、def を代わりにセ?することです?
104             * ただし?value ?null で、def ?null の場合??
105             * なにもセ?されません?
106             *
107             * @param    key ?される値が関連付けられるキー(大?小文字?同?)
108             * @param    value ?されるキーに関連付けられる?
109             * @param    def value ?null の場合にキーに関連付けられる?
110             */
111            public void set( final String key,final String value,final String def ) {
112                    if( value != null )    { attri.put( key.toLowerCase( Locale.JAPAN ),value ) ; }
113                    else if( def != null ) { attri.put( key.toLowerCase( Locale.JAPAN ),def )   ; }
114            }
115    
116            /**
117             * ?された値と?されたキーをこのマップに追?ま?
118             *
119             * マップ?身のキーは、ユニ?クである為、既存?値に対して?
120             * 新しく値を追?ます?
121             * 追?る方法?、?の??の結合です?こ?メソ?では?
122             * ?ォルト?スペ?スで結合します?
123             *
124             * 値?null また?、すでにそ?キーに同??値が関連付けられて?場合??
125             * 何もしません?
126             *
127             * @param    key   ?される値が関連付けられるキー(大?小文字?同?)
128             * @param    value ?されるキーの値に、追?れる値
129             */
130            public void add( final String key,final String value ) {
131                    add( key,value," " ) ;
132            }
133    
134            /**
135             * ?された値と?されたキーをこのマップに追?ま?
136             *
137             * マップ?身のキーは、ユニ?クである為、既存?値に対して?
138             * 新しく値を追?ます?
139             * 追?る方法?、?の??の結合です?こ?メソ?では?
140             * 引数 sepa で??を結合します?
141             *
142             * 値?null また?、sepa ?null また?、すでにそ?キーに
143             * 同??値が関連付けられて?場合?、何もしません?
144             *
145             * @param    key   ?される値が関連付けられるキー(大?小文字?同?)
146             * @param    value ?されるキーの値に、追?れる値
147             * @param    sepa  値を?結するとき???
148             */
149            public void add( final String key,final String value,final String sepa ) {
150                    if( value != null && sepa != null ) {
151                            String lkey = key.toLowerCase( Locale.JAPAN );
152                            String temp = attri.get( lkey );
153                            if( temp != null ) {
154                                    temp = temp.trim();
155                                    if( temp.indexOf( value ) < 0 ||                     // 存在しな?また??
156                                            ( ! temp.equals( value ) &&                             // ??しな?
157                                              ! temp.startsWith( value + sepa ) &&  // 先?にな?
158                                              ! temp.endsWith( sepa + value ) &&    // ?にな?
159                                              temp.indexOf( sepa + value + sepa ) < 0 ) ) {      // 途中にな?
160                                                    if( temp.endsWith( sepa ) ) {
161                                                            attri.put( lkey,temp + value );
162                                                    }
163                                                    else {
164                                                            attri.put( lkey,temp + sepa + value );
165                                                    }
166                                    }
167                            }
168                            else {
169                                    attri.put( lkey,value );
170                            }
171                    }
172            }
173    
174            /**
175             * Attributes 属?を?既存?属?に追?ます?
176             * すでに同?ーの属?が存在して?場合??上書きで
177             * 置き換えます?
178             * 引数 att ?null の場合??何もしません?
179             *
180             * @param att Attributes属?
181             */
182            public void addAttributes( final Attributes att ) {
183                    if( att != null ) {
184                            String[] keys = att.getKeyArray();
185                            for( int i=0; i<keys.length; i++ ) {
186                                    set( keys[i],att.get( keys[i] ) );
187                            }
188                    }
189            }
190    
191            /**
192             * こ?キーにマッピングがある?合に、そのマッピングを???から削除しま?
193             *
194             * @param    key マッピングが???から削除されるキー(大?小文字?同?)
195             *
196             * @return   こ?キーにマッピングがある?合に、そのマッピングを???から削除しま?
197             *           ?されたキーに関連した以前?値。key にマッピングがなかった?合? null?
198             */
199            public String remove( final String key ) {
200                    return attri.remove( key.toLowerCase( Locale.JAPAN ) );
201            }
202    
203            /**
204             * マップ?のキーと値のマッピングの数を返します?
205             *
206             * @return   インタフェース Map ?? size
207             *
208             */
209            public int size() {
210                    return attri.size() ;
211            }
212    
213            /**
214             * マップに含まれて?キーの配?を返します?
215             * ここでは、キーの配?はソートして返します?
216             *
217             * @return   マップに含まれて?キーの配?
218             *
219             */
220            public String[] getKeyArray() {
221                    Set<String> keyset = attri.keySet();
222                    String[] rtn = keyset.toArray( new String[keyset.size()] ) ;
223                    Arrays.sort( rtn );
224                    return rtn ;
225            }
226    
227            /**
228             * マップに含まれて?キーと属?のペア?タグの属?リスト?形式で返します?
229             * key1="value1" key2="value2" key3="value3" .... の形式で、value ?null の
230             * 場合??key そ?も?のペアを?力しません?
231             * value が空?? "" の場合??key="" で出力します?
232             *
233             * 引数には?key として出力したい値を?列文字?で渡します?
234             * これは、拡張性に乏し?すべて出せ??属??の追?対応できる?
235             * 方法ですが、タグ毎に異なる属?のみを管?るには?厳格に出?
236             * タグ属?を定義した??思いから?導?しました?
237             *
238             * @param    keys ??key の配???(大?小文字?同?)
239             *
240             * @return   キーと属?のペアをタグの属?リスト?形式で返しま?
241             *
242             */
243            public String getAttribute( final String[] keys ) {
244                    StringBuilder buf = new StringBuilder( 200 );
245    
246                    for( int i=0; i<keys.length; i++ ) {
247                            String value = get( keys[i].toLowerCase( Locale.JAPAN ) );
248                            if( value != null ) {
249                                    buf.append( keys[i] ).append("=");
250                                    buf.append("\"").append( value ).append("\" ");
251                            }
252                    }
253                    return buf.toString();
254            }
255    
256            /**
257             * マップに含まれて?キーと属?のペア?タグの属?リスト?形式ですべて返します?
258             * なお?value ?null の場合??key そ?も?のペアを?力しません?
259             * value が空?? "" の場合??key="" で出力します?
260             *
261             * @return   キーと属?のペアをタグの属?リスト?形式で返しま?
262             *
263             */
264            public String getAttribute() {
265                    return getAttribute( getKeyArray() );
266            }
267    
268            /**
269             * こ?オブジェクト???表現を返します?
270             * 基本???目?使用します?
271             *
272             * @return      オブジェクト???表現
273             */
274            @Override
275            public String toString() {
276                    return( getAttribute() );
277            }
278    }