OSDN Git Service

Ver8.5.2.0
[opengion/opengionV8.git] / uap / webapps / gf / src / org / opengion / fukurou / util / Attributes.java
1 /*
2  * Copyright (c) 2009 The openGion Project.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific language
14  * governing permissions and limitations under the License.
15  */
16 package org.opengion.fukurou.util;
17
18 import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
19 import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.1 (2016/02/12) refactoring
20 import java.util.Locale;
21
22 import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
23
24 /**
25  * Attributes.java は、String 型キーにString型値を Map するクラスです。
26  *
27  * HTMLのPOST/GET等の受け渡しや、String型の引数が多い場合に効果があります。
28  * 特に、getAttributes( String[] param ) による属性リスト作成は、
29  * HTMLタグの属性定義を行う上で、非常に便利に利用できます。
30  *
31  * ※ 6.1.1.0 (2015/01/17)
32  *    StringBuilder と同様、set メソッド , add メソッドの戻り値に、自分自身を戻します。
33  *    これにより、連結処理できるようにします。
34  *
35  * この実装は同期化されません。
36  *
37  * @version  4.0
38  * @author   Kazuhiko Hasegawa
39  * @since    JDK5.0,
40  */
41 public final class Attributes {
42         /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 */
43         private final ConcurrentMap<String,String> attMap ;             // Map系変数は、Mapと判る様に命名する。
44
45         /**
46          * デフォルトコンストラクター
47          *
48          * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
49          */
50         public Attributes() {
51                 attMap = new ConcurrentHashMap<>();
52         }
53
54         /**
55          * Attributesオブジェクト を与えて新しく作成するコンストラクター
56          *
57          * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
58          *
59          * @param att Attributesオブジェクト
60          */
61         public Attributes( final Attributes att ) {
62                 attMap = new ConcurrentHashMap<>( att.attMap );                 // AttributesのattMapは、ConcurrentHashMap なので、not null保障
63         }
64
65         /**
66          * マップからマッピングをすべて削除します 。
67          *
68          */
69         public void clear()  {
70                 attMap.clear() ;
71         }
72
73         /**
74          * マップが指定のキーをマップする値を返します。
75          * マップがこのキーのマッピングを保持していない場合は null
76          * を返します。戻り値の null は、マップがキーのマッピングを
77          * 保持していないことを示すとはかぎりません。つまり、マップが
78          * 明示的にキーを null にマップすることもあります。
79          *
80          * @param    key 関連付けられた値が返されるキー(大文字小文字は同値)
81          *
82          * @return   マップが、指定されたキーにマッピングしている値。
83          *           このキーに対するマッピングがマップにない場合は null
84          */
85         public String get( final String key ) {
86                 return attMap.get( key.toLowerCase( Locale.JAPAN ) ) ;
87         }
88
89         /**
90          * 指定された値と指定されたキーをこのマップに関連付けます
91          * 指定されたキーに、null を関連付けることはできません。
92          * (もちろん、"":ゼロストリング は登録できます。)
93          * なぜなら、getAttribute( String[] keys ) 等で値が null の
94          * キーは、取得できない為です。
95          * また、すでに何らかの値がセットされている所に、null をセットした
96          * 場合は、前の値をなにも変更しません。
97          * 通常、値をクリアしたい場合は、 remove( String key ) を利用してください。
98          *
99          * @og.rev 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返すようにします。
100          *
101          * @param    key 指定される値が関連付けられるキー(大文字小文字は同値)
102          * @param    value 指定されるキーに関連付けられる値
103          *
104          * @return      自分自身
105          * @og.rtnNotNull
106          */
107         public Attributes set( final String key,final String value ) {
108                 if( value != null ) {
109                         attMap.put( key.toLowerCase( Locale.JAPAN ),value ) ;
110                 }
111                 return this ;           // 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返す
112         }
113
114         /**
115          * 指定された値と指定されたキーをこのマップに関連付けます
116          * set( String key,String value ) との違いは、value が null
117          * の場合に、def を代わりにセットすることです。
118          * ただし、value が null で、def も null の場合は、
119          * なにもセットされません。
120          *
121          * @og.rev 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返すようにします。
122          *
123          * @param    key 指定される値が関連付けられるキー(大文字小文字は同値)
124          * @param    value 指定されるキーに関連付けられる値
125          * @param    def value が null の場合にキーに関連付けられる値
126          *
127          * @return      自分自身
128          * @og.rtnNotNull
129          */
130         public Attributes set( final String key,final String value,final String def ) {
131                 if( value != null )    { attMap.put( key.toLowerCase( Locale.JAPAN ),value ) ; }
132                 else if( def != null ) { attMap.put( key.toLowerCase( Locale.JAPAN ),def )   ; }
133
134                 return this ;           // 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返す
135         }
136
137         /**
138          * Attributes 属性を、既存の属性に上書き追加します。
139          *
140          * 引数 att が null の場合は、何もしません。
141          * 内部の Map に直接書き込みますので、すでに同一キーの属性が存在している場合は、
142          * 上書きで置き換えます。
143          * つまり、初期値を設定する場合は、最初に呼び出します。引数で設定された最新の値を
144          * 使用する場合は、最後に設定します。
145          * ただし、#add(String,String) は、既存のキーに値を追記していきますので、これらより
146          * 後に設定しないと、上書きされてしまいますので、ご注意ください。
147          *
148          * 従来の、#addAttributes( Attributes ) の代替えメソッドです。
149          *
150          * @og.rev 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返すようにします。
151          *
152          * @param att Attributes属性
153          *
154          * @return      自分自身
155          * @og.rtnNotNull
156          */
157         public Attributes set( final Attributes att ) {
158                 if( att != null && !att.attMap.isEmpty() ) {
159                         attMap.putAll( att.attMap );                            // AttributesのattMapは、ConcurrentHashMap なので、not null保障
160                 }
161
162                 return this ;           // 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返す
163         }
164
165         /**
166          * 指定された値と指定されたキーをこのマップに追加します
167          *
168          * マップ自身のキーは、ユニークである為、既存の値に対して、
169          * 新しく値を追加します。
170          * 追加する方法は、値の文字列の結合です。このメソッドでは、
171          * デフォルトのスペースで結合します。
172          *
173          * 値が null または、すでにそのキーに同一の値が関連付けられている場合は、
174          * 何もしません。
175          *
176          * @og.rev 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返すようにします。
177          *
178          * @param    key   指定される値が関連付けられるキー(大文字小文字は同値)
179          * @param    value 指定されるキーの値に、追加される値
180          *
181          * @return      自分自身
182          * @og.rtnNotNull
183          */
184         public Attributes add( final String key,final String value ) {
185                 return add( key,value," " ) ;           // 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返す
186         }
187
188         /**
189          * 指定された値と指定されたキーをこのマップに追加します
190          *
191          * class属性や、style属性など、同一キーに対して、複数の値をつなげる場合に
192          * 使用します。
193          *
194          * マップ自身のキーは、ユニークである為、既存の値に対して、
195          * 新しく値を追加します。
196          * 追加する方法は、値の文字列の結合です。このメソッドでは、
197          * 引数 sepa で文字列を結合します。
198          *
199          * 値が null または、sepa が null または、すでにそのキーに
200          * 同一の値が関連付けられている場合は、何もしません。
201          *
202          * @og.rev 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返すようにします。
203          *
204          * @param    key   指定される値が関連付けられるキー(大文字小文字は同値)
205          * @param    value 指定されるキーの値に、追加される値
206          * @param    sepa  値を連結するときの文字列
207          *
208          * @return      自分自身
209          * @og.rtnNotNull
210          */
211         public Attributes add( final String key,final String value,final String sepa ) {
212                 if( value != null && sepa != null ) {
213                         final String lkey = key.toLowerCase( Locale.JAPAN );
214
215                         String temp = attMap.get( lkey );
216                         // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
217                         if( temp == null ) {
218                                 attMap.put( lkey,value );
219                         }
220                         else {
221                                 temp = temp.trim();
222                                 if( temp.indexOf( value ) < 0 ||                        // 存在しない または、
223                                           ! temp.equals( value ) &&                             // 一致しない
224                                           ! temp.startsWith( value + sepa ) &&  // 先頭にない
225                                           ! temp.endsWith( sepa + value ) &&    // 最終にない
226                                           temp.indexOf( sepa + value + sepa ) < 0 ) {   // 途中にない                      // 6.9.7.0 (2018/05/14) PMD
227                                                 if( temp.endsWith( sepa ) ) {
228                                                         attMap.put( lkey,temp + value );
229                                                 }
230                                                 else {
231                                                         attMap.put( lkey,temp + sepa + value );
232                                                 }
233                                 }
234                         }
235                 }
236
237                 return this ;           // 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返す
238         }
239
240         /**
241          * このキーにマッピングがある場合に、そのマッピングをマップから削除します。
242          *
243          * @param    key マッピングがマップから削除されるキー(大文字小文字は同値)
244          *
245          * @return   このキーにマッピングがある場合に、そのマッピングをマップから削除します
246          *           指定されたキーに関連した以前の値。key にマッピングがなかった場合は null。
247          */
248         public String remove( final String key ) {
249                 return attMap.remove( key.toLowerCase( Locale.JAPAN ) );
250         }
251
252         /**
253          * マップ内のキーと値のマッピングの数を返します。
254          *
255          * @return   インタフェース Map 内の size
256          */
257         public int size() {
258                 return attMap.size() ;
259         }
260
261         /**
262          * マップに含まれているキーと属性のペアを タグの属性リストの形式で返します。
263          * key1="value1" key2="value2" key3="value3" .... の形式で、value が null の
264          * 場合は、key そのもののペアを出力しません。
265          * value が空文字列 "" の場合は、key="" で出力します。
266          *
267          * 引数には、key として出力したい値を配列文字列で渡します。
268          * これは、拡張性に乏しい(すべて出せば、属性項目の追加に対応できる。)
269          * 方法ですが、タグ毎に異なる属性のみを管理するには、厳格に出力
270          * タグ属性を定義したいという思いから導入しました。
271          *
272          * @og.rev 6.0.4.0 (2014/11/28) 内部処理見直し。値の取得は、Mapから直接取得する。
273          * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap の not null制限のチェック追加
274          *
275          * @param    keys 指定 key の文字列配列(可変長引数)(大文字小文字は同値)
276          *
277          * @return   キーと属性のペアをタグの属性リストの形式で返します
278          * @og.rtnNotNull
279          */
280 //      public String getAttribute( final String[] keys ) {
281         public String getAttribute( final String... keys ) {
282                 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
283
284                 if( keys != null ) {
285                         for( final String key : keys ) {
286                                 if( key != null ) {
287                                         final String value = attMap.get( key.toLowerCase( Locale.JAPAN ) );     // 6.0.4.0 (2014/11/28) Mapから直接取得する。
288                                         if( value != null ) {
289                                                 // 6.0.2.5 (2014/10/31) char を append する。
290                                                 buf.append( key ).append("=\"").append( value ).append("\" ");
291                                         }
292                                 }
293                         }
294                 }
295
296                 return buf.toString();
297         }
298
299         /**
300          * マップに含まれているキーと属性のペアを タグの属性リストの形式ですべて返します。
301          * なお、value が null の場合は、key そのもののペアを出力しません。
302          * value が空文字列 "" の場合は、key="" で出力します。
303          *
304          * @og.rev 6.0.4.0 (2014/11/28) 内部処理見直し。値の取得は、Mapから直接取得する。
305          * @og.rev 6.4.3.4 (2016/03/11) forループを、forEach メソッドに置き換えます。
306          *
307          * @return   キーと属性のペアをタグの属性リストの形式で返します
308          * @og.rtnNotNull
309          */
310         public String getAttribute() {
311                 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
312
313                 // 内部に持っているすべてのデータを出力する。
314                 // よって、toLowerCase も、null チェックも不要。
315                 attMap.forEach( (k,v) -> buf.append( k ).append("=\"").append( v ).append("\" ") );
316
317                 return buf.toString();
318         }
319
320         /**
321          * マップに含まれているキーと属性のペアを タグの属性リストの形式ですべて返します。
322          * なお、value が nullや、空文字列("") の場合は、key そのもののペアを出力しません。
323          * この文字列は、key:value; 形式で、文字列を作成します。value に、ダブルコーテーション
324          * は付けません。
325          *
326          * @og.rev 7.0.1.0 (2018/10/15) 新規作成
327          *
328          * @return   キーと属性のペアをCSS形式で返します
329          * @og.rtnNotNull
330          */
331         public String getCssFormat() {
332                 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
333
334                 // 内部に持っているすべてのデータを出力する。
335                 // よって、toLowerCase も、null チェックも不要。
336                 attMap.forEach( (k,v) -> { if( StringUtil.isNotNull(k) ) { buf.append( k ).append(':').append( v ).append("; "); } } );
337
338                 return buf.toString();
339         }
340
341         /**
342          * 指定の文字列を分解して、Mapを作成します。
343          * 『;』 で分解して、ここのキーと値を、『=』で分解します。
344          * 引数の値は、そのまま適用されますので、クオーテーション等は、付けないと想定しています。
345          *
346          * @og.rev 7.4.2.1 (2021/05/08)
347          *
348          * @param  params キー=値; キー=値 形式の文字列
349          * @return   キーと属性に分解したMap
350          * @og.rtnNotNull
351          */
352         public ConcurrentMap<String,String> getParamMap( final String params ) {
353                 final ConcurrentMap<String,String> optMap = new ConcurrentHashMap<>();
354                 if( params != null ) {
355                         final String[] prms = params.split( ";" );              // 各項目は、『;』 で分解する。
356                         for( final String prm : prms ) {
357                                 final String[] keyval = prm.split( "=" );               // キーと値は、『=』 で分解する。
358                                 if( keyval.length >= 2 ) {
359                                         final String val = keyval[1].replaceAll( "'","" ).replaceAll( "\"","" );
360                                         optMap.put( keyval[0].trim() , val );
361                                 }
362                         }
363                 }
364                 return optMap ;
365         }
366
367         /**
368          * このオブジェクトの文字列表現を返します。
369          * 基本的にデバッグ目的に使用します。
370          *
371          * @return      オブジェクトの文字列表現
372          * @og.rtnNotNull
373          */
374         @Override
375         public String toString() {
376                 return getAttribute() ;
377         }
378 }