    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.Set;
    019import java.util.Map;
    020import java.util.HashMap;
    021import java.util.Arrays;
    022import 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 */
    037public 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}