##### Coverage Report - org.seasar.cubby.tags.TagUtils

Classes in this File | Line Coverage | Branch Coverage | Complexity
TagUtils |
87% | 84/96
75% | 41/54
| 3.3125;3.312

1 |  |
     /*
2 |  |
      * Copyright 2004-2009 the Seasar Foundation and the Others.
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.seasar.cubby.tags;
17 |  |
18 |  |
     import static java.lang.Boolean.TRUE;
19 |  |
     import static javax.servlet.jsp.PageContext.REQUEST_SCOPE;
20 |  |
     import static org.seasar.cubby.CubbyConstants.ATTR_CONTEXT_PATH;
21 |  |
     import static org.seasar.cubby.CubbyConstants.ATTR_ERRORS;
22 |  |
     import static org.seasar.cubby.CubbyConstants.ATTR_PARAMS;
23 |  |
     import static org.seasar.cubby.CubbyConstants.ATTR_VALIDATION_FAIL;
24 |  |
     import static org.seasar.cubby.internal.util.LogMessages.format;
25 |  |
26 |  |
     import java.util.Collection;
27 |  |
     import java.util.Map;
28 |  |
     import java.util.Map.Entry;
29 |  |
30 |  |
     import javax.servlet.jsp.JspContext;
31 |  |
     import javax.servlet.jsp.PageContext;
32 |  |
     import javax.servlet.jsp.tagext.SimpleTag;
33 |  |
     import javax.servlet.jsp.tagext.SimpleTagSupport;
34 |  |
35 |  |
     import org.seasar.cubby.CubbyConstants;
36 |  |
     import org.seasar.cubby.action.ActionErrors;
37 |  |
     import org.seasar.cubby.controller.FormWrapper;
38 |  |
     import org.seasar.cubby.internal.util.StringUtils;
39 |  |
     import org.slf4j.Logger;
40 |  |
     import org.slf4j.LoggerFactory;
41 |  |
42 |  |
     /**
43 |  |
      * カスタムタグで使用するユーティリティクラスです。
44 |  |
      *
45 |  |
      * @author baba
46 |  |
      */
47 | 0 |
     class TagUtils {
48 |  |
49 |  |
             /** ロガー。 */
50 | 1 |
             private static final Logger logger = LoggerFactory
51 |  |
                             .getLogger(TagUtils.class);
52 |  |
53 |  |
             /**
54 |  |
              * 指定されたJSPコンテキストから{@link ActionErrors}を取得します。
55 |  |
              *
56 |  |
              * @param context
57 |  |
              *            JSPコンテキスト
58 |  |
              * @return アクションで発生したエラー
59 |  |
              */
60 |  |
             public static ActionErrors errors(final JspContext context) {
61 | 37 |
                     return (ActionErrors) context.getAttribute(ATTR_ERRORS, REQUEST_SCOPE);
62 |  |
             }
63 |  |
64 |  |
             /**
65 |  |
              * 指定されたJSPコンテキストから指定されたパラメータ名に対応する要求パラメータを取得します。
66 |  |
              *
67 |  |
              * @param context
68 |  |
              *            JSPコンテキスト
69 |  |
              * @param name
70 |  |
              *            パラメータ名
71 |  |
              * @return 要求パラメータ
72 |  |
              */
73 |  |
             @SuppressWarnings("unchecked")
74 |  |
             private static Object[] paramValues(final JspContext context,
75 |  |
                             final String name) {
76 | 7 |
                     final Map<String, Object[]> valuesMap = Map.class.cast(context
77 |  |
                                     .getAttribute(ATTR_PARAMS, REQUEST_SCOPE));
78 |  |
                     final Object[] values;
79 | 7 |
                     if (valuesMap == null || !valuesMap.containsKey(name)) {
80 | 0 |
                             values = new Object[0];
81 |  |
                     } else {
82 | 7 |
                             values = valuesMap.get(name);
83 |  |
                     }
84 | 7 |
                     return values;
85 |  |
             }
86 |  |
87 |  |
             /**
88 |  |
              * 指定されたフィールド名に対応するフォームのフィールドへの出力値を取得します。
89 |  |
              *
90 |  |
              * @param context
91 |  |
              *            JSPコンテキスト
92 |  |
              * @param formWrapper
93 |  |
              *            フォームオブジェクトのラッパー
94 |  |
              * @param name
95 |  |
              *            フィールド名
96 |  |
              * @return フォームのフィールドへの出力値
97 |  |
              */
98 |  |
             public static Object[] multipleFormValues(final JspContext context,
99 |  |
                             final FormWrapper formWrapper, final String name) {
100 | 16 |
                     return multipleFormValues(context, formWrapper, name, null);
101 |  |
             }
102 |  |
103 |  |
             /**
104 |  |
              * 指定されたフィールド名に対応するフォームのフィールドへの出力値を取得します。
105 |  |
              *
106 |  |
              * @param context
107 |  |
              *            JSPコンテキスト
108 |  |
              * @param formWrapper
109 |  |
              *            フォームオブジェクトのラッパー
110 |  |
              * @param name
111 |  |
              *            フィールド名
112 |  |
              * @param checkedValue
113 |  |
              *            チェック済みにする値
114 |  |
              * @return フォームのフィールドへの出力値
115 |  |
              */
116 |  |
             public static Object[] multipleFormValues(final JspContext context,
117 |  |
                             final FormWrapper formWrapper, final String name,
118 |  |
                             final String checkedValue) {
119 |  |
                     final Object[] values;
120 | 30 |
                     if (isValidationFail(context)) {
121 | 5 |
                             values = paramValues(context, name);
122 |  |
                     } else {
123 | 25 |
                             if (checkedValue != null) {
124 | 5 |
                                     values = new Object[] { checkedValue };
125 |  |
                             } else {
126 | 20 |
                                     if (!formWrapper.hasValues(name)) {
127 | 0 |
                                             if (logger.isDebugEnabled()) {
128 | 0 |
                                                     logger.debug(format("DCUB0023", name));
129 |  |
                                             }
130 | 0 |
                                             return null;
131 |  |
                                     }
132 | 20 |
                                     values = formWrapper.getValues(name);
133 |  |
                             }
134 |  |
                     }
135 | 30 |
                     return values;
136 |  |
             }
137 |  |
138 |  |
             /**
139 |  |
              * 指定されたフィールド名に対応するフォームのフィールドへの出力値を取得します。
140 |  |
              *
141 |  |
              * @param context
142 |  |
              *            JSPコンテキスト
143 |  |
              * @param formWrapper
144 |  |
              *            フォームオブジェクトのラッパー
145 |  |
              * @param name
146 |  |
              *            フィールド名
147 |  |
              * @param index
148 |  |
              *            インデックス
149 |  |
              * @param specifiedValue
150 |  |
              *            エラーがない場合に設定する値
151 |  |
              * @return フォームのフィールドへの出力値
152 |  |
              */
153 |  |
             public static Object formValue(final JspContext context,
154 |  |
                             final FormWrapper formWrapper, final String name,
155 |  |
                             final Integer index, final Object specifiedValue) {
156 |  |
                     final Object value;
157 |  |
158 | 9 |
                     if (isValidationFail(context)) {
159 | 2 |
                             if (specifiedValue == null) {
160 | 1 |
                                     final Object[] values = paramValues(context, name);
161 | 1 |
                                     value = value(values, index);
162 | 1 |
                             } else {
163 | 1 |
                                     final Object[] values = paramValues(context, name);
164 | 1 |
                                     if (values.length == 0) {
165 | 0 |
                                             value = specifiedValue;
166 |  |
                                     } else {
167 | 1 |
                                             value = value(values, index);
168 |  |
                                     }
169 | 1 |
                             }
170 |  |
                     } else {
171 | 7 |
                             if (specifiedValue != null) {
172 | 2 |
                                     value = specifiedValue;
173 |  |
                             } else {
174 | 5 |
                                     if (!formWrapper.hasValues(name)) {
175 | 1 |
                                             logger.debug(format("DCUB0023", name));
176 | 1 |
                                             return null;
177 |  |
                                     }
178 | 4 |
                                     value = value(formWrapper.getValues(name), index);
179 |  |
                             }
180 |  |
                     }
181 |  |
182 | 8 |
                     return value;
183 |  |
             }
184 |  |
185 |  |
             /**
186 |  |
              * オブジェクトの配列から指定されたインデックスの値を取得します。
187 |  |
              * <p>
188 |  |
              * values が <code>null</code> の場合や index が要素数を越えていた場合は空文字を返します。index が
189 |  |
              * <code>null</code> の場合は配列の最初の要素を返します。
190 |  |
              * </p>
191 |  |
              *
192 |  |
              * @param values
193 |  |
              *            オブジェクトの配列
194 |  |
              * @param index
195 |  |
              *            インデックス
196 |  |
              * @return 指定されたインデックスの要素
197 |  |
              */
198 |  |
             private static Object value(final Object[] values, final Integer index) {
199 |  |
                     final Object value;
200 | 6 |
                     if (values == null) {
201 | 0 |
                             value = "";
202 |  |
                     } else {
203 | 6 |
                             if (index == null) {
204 | 6 |
                                     value = getElement(values, 0);
205 |  |
                             } else {
206 | 0 |
                                     value = getElement(values, index);
207 |  |
                             }
208 |  |
                     }
209 | 6 |
                     return value;
210 |  |
             }
211 |  |
212 |  |
             /**
213 |  |
              * オブジェクトの配列から指定されたインデックスの要素を取得します。
214 |  |
              * <p>
215 |  |
              * index が要素数を越えていた場合は空文字を返します。
216 |  |
              * </p>
217 |  |
              *
218 |  |
              * @param values
219 |  |
              *            オブジェクトの配列
220 |  |
              * @param index
221 |  |
              *            インデックス
222 |  |
              * @return 指定されたインデックスの要素
223 |  |
              */
224 |  |
             private static Object getElement(final Object[] values, final Integer index) {
225 |  |
                     final Object value;
226 | 6 |
                     if (values.length <= index) {
227 | 0 |
                             value = "";
228 |  |
                     } else {
229 | 6 |
                             value = values[index];
230 |  |
                     }
231 | 6 |
                     return value;
232 |  |
             }
233 |  |
234 |  |
             /**
235 |  |
              * 指定されたJSPコンテキストのアクションが入力検証に失敗したかどうかを示します。
236 |  |
              *
237 |  |
              * @param context
238 |  |
              *            JSPコンテキスト
239 |  |
              * @return アクションが入力検証に失敗した場合は <code>true</code>、そうでない場合は <code>false</code>
240 |  |
              * @see CubbyConstants#ATTR_VALIDATION_FAIL
241 |  |
              */
242 |  |
             private static boolean isValidationFail(final JspContext context) {
243 | 39 |
                     return TRUE.equals(context.getAttribute(ATTR_VALIDATION_FAIL,
244 |  |
                                     REQUEST_SCOPE));
245 |  |
             }
246 |  |
247 | 1 |
             public static final Object REMOVE_ATTRIBUTE = new Object();
248 |  |
249 |  |
             /**
250 |  |
              * 指定された {@link Map} を HTML タグの属性へ変換します。
251 |  |
              * <p>
252 |  |
              * map 中の値が属性を出力しないことを示すオブジェクトの場合、その属性は結果から除外します。
253 |  |
              * </p>
254 |  |
              *
255 |  |
              * @param map
256 |  |
              *            属性のマップ
257 |  |
              * @return HTML タグの属性
258 |  |
              */
259 |  |
             public static String toAttr(final Map<String, Object> map) {
260 | 47 |
                     final StringBuilder builder = new StringBuilder();
261 | 47 |
                     for (final Entry<String, Object> entry : map.entrySet()) {
262 | 19 |
                             final String key = entry.getKey();
263 | 19 |
                             if (entry.getValue() == REMOVE_ATTRIBUTE) {
264 | 0 |
                                     continue;
265 |  |
                             }
266 | 19 |
                             builder.append(key);
267 | 19 |
                             builder.append("=\"");
268 | 19 |
                             builder.append(escapeHtml(entry.getValue()));
269 | 19 |
                             builder.append("\" ");
270 | 19 |
                     }
271 | 46 |
                     return builder.toString();
272 |  |
             }
273 |  |
274 |  |
             /**
275 |  |
              * 指定されたオブジェクトが特定の文字列を含むかを示します。
276 |  |
              * <p>
277 |  |
              * 指定されたオブジェクトが配列や{@link Collection}の場合は、その要素の文字列表現が指定された文字列と同値かを示します。
278 |  |
              * 指定されたオブジェクトが配列や{@link Collection}でない場合は、そのオブジェクトの文字列表現が指定された文字列と同値かを示します。
279 |  |
              * </p>
280 |  |
              *
281 |  |
              * @param obj
282 |  |
              *            オブジェクト
283 |  |
              * @param str
284 |  |
              *            文字列
285 |  |
              * @return 指定されたオブジェクトが特定の文字列を含む場合は <code>true</code>、そうでない場合は
286 |  |
              *         <code>false</code>
287 |  |
              */
288 |  |
             public static boolean contains(final Object obj, final String str) {
289 | 60 |
                     if (obj instanceof Collection) {
290 | 1 |
                             return ((Collection<?>) obj).contains(str);
291 | 59 |
                     } else if (obj.getClass().isArray()) {
292 | 95 |
                             for (final Object value : (Object[]) obj) {
293 | 62 |
                                     if (equalsAsString(value, str)) {
294 | 23 |
                                             return true;
295 |  |
                                     }
296 |  |
                             }
297 | 32 |
                             return false;
298 |  |
                     } else {
299 | 2 |
                             return equalsAsString(obj, str);
300 |  |
                     }
301 |  |
             }
302 |  |
303 |  |
             /**
304 |  |
              * 指定された値が文字列として同値かを示します。
305 |  |
              *
306 |  |
              * @param obj1
307 |  |
              *            比較するオブジェクト1
308 |  |
              * @param obj2
309 |  |
              *            比較するオブジェクト2
310 |  |
              * @return obj1とobj2が文字列として同値の場合は <code>true</code>、そうでない場合は
311 |  |
              *         <code>false</code>
312 |  |
              */
313 |  |
             private static boolean equalsAsString(final Object obj1, final Object obj2) {
314 | 64 |
                     if (obj1 == obj2) {
315 | 10 |
                             return true;
316 | 54 |
                     } else if (obj1 == null) {
317 | 4 |
                             return false;
318 |  |
                     } else {
319 | 50 |
                             return obj1.toString().equals(obj2.toString());
320 |  |
                     }
321 |  |
             }
322 |  |
323 |  |
             /**
324 |  |
              * 動的な属性の {@link Map} に、指定された <code>class</code> 属性を追加します。
325 |  |
              *
326 |  |
              * @param dynamicAttributes
327 |  |
              *            動的な属性の {@link Map}
328 |  |
              * @param className
329 |  |
              *            <code>class</code> 属性の名前
330 |  |
              */
331 |  |
             public static void addCSSClassName(
332 |  |
                             final Map<String, Object> dynamicAttributes, final String className) {
333 | 3 |
                     String classValue = (String) dynamicAttributes.get("class");
334 | 2 |
                     if (StringUtils.isEmpty(classValue)) {
335 | 1 |
                             classValue = className;
336 |  |
                     } else {
337 | 1 |
                             classValue = classValue + " " + className;
338 |  |
                     }
339 | 2 |
                     dynamicAttributes.put("class", classValue);
340 | 2 |
             }
341 |  |
342 |  |
             /**
343 |  |
              * 指定されたタグの親の {@link FormTag} を検索し、そこからフォームオブジェクトのラッパーを取得します。
344 |  |
              *
345 |  |
              * @param tag
346 |  |
              *            タグ
347 |  |
              * @return フォームオブジェクトのラッパー
348 |  |
              */
349 |  |
             public static FormWrapper getFormWrapper(final SimpleTag tag) {
350 | 35 |
                     final FormTag formTag = (FormTag) SimpleTagSupport
351 |  |
                                     .findAncestorWithClass(tag, FormTag.class);
352 | 35 |
                     if (formTag == null) {
353 | 0 |
                             return null;
354 |  |
                     }
355 | 35 |
                     return formTag.getFormWrapper();
356 |  |
             }
357 |  |
358 |  |
             /**
359 |  |
              * 指定された文字列をHTMLとしてエスケープします。
360 |  |
              * <p>
361 |  |
              * <table>
362 |  |
              * <thead>
363 |  |
              * <tr>
364 |  |
              * <th>変換前</th>
365 |  |
              * <th>変換後</th>
366 |  |
              * </tr>
367 |  |
              * </thead> <tbody>
368 |  |
              * <tr>
369 |  |
              * <td>&amp;</td>
370 |  |
              * <td>&amp;amp;</td>
371 |  |
              * </tr>
372 |  |
              * <tr>
373 |  |
              * <td>&lt;</td>
374 |  |
              * <td>&amp;lt;</td>
375 |  |
              * </tr>
376 |  |
              * <tr>
377 |  |
              * <td>&gt;</td>
378 |  |
              * <td>&amp;gt;</td>
379 |  |
              * </tr>
380 |  |
              * <tr>
381 |  |
              * <td>&quot;</td>
382 |  |
              * <td>&amp;quot;</td>
383 |  |
              * </tr>
384 |  |
              * <tr>
385 |  |
              * <td>&#39</td>
386 |  |
              * <td>&amp;#39</td>
387 |  |
              * </tr>
388 |  |
              * </tbody>
389 |  |
              * </table>
390 |  |
              * </p>
391 |  |
              *
392 |  |
              * @param str
393 |  |
              * @return エスケープされた文字列
394 |  |
              */
395 |  |
             public static String escapeHtml(final Object str) {
396 | 114 |
                     if (str == null) {
397 | 0 |
                             return "";
398 |  |
                     }
399 | 114 |
                     String text = str.toString();
400 | 114 |
                     text = StringUtils.replace(text, "&", "&amp;");
401 | 114 |
                     text = StringUtils.replace(text, "<", "&lt;");
402 | 114 |
                     text = StringUtils.replace(text, ">", "&gt;");
403 | 114 |
                     text = StringUtils.replace(text, "\"", "&quot;");
404 | 114 |
                     text = StringUtils.replace(text, "'", "&#39;");
405 | 114 |
                     return text;
406 |  |
             }
407 |  |
408 |  |
             /**
409 |  |
              * オブジェクトを文字列に変換します。 オブジェクトが<code>null</code>の場合、空文字を返します。
410 |  |
              *
411 |  |
              * @param object
412 |  |
              *            対象のオブジェクト
413 |  |
              * @return オブジェクトのtoString結果。
414 |  |
              */
415 |  |
             public static String toString(final Object object) {
416 | 88 |
                     return object == null ? "" : object.toString();
417 |  |
             }
418 |  |
419 |  |
             /**
420 |  |
              * コンテキストパスを取得します。
421 |  |
              *
422 |  |
              * @param jspContext
423 |  |
              *            JSP コンテキスト
424 |  |
              * @return コンテキストパス
425 |  |
              */
426 |  |
             public static String getContextPath(final JspContext jspContext) {
427 | 13 |
                     final String contextPath = (String) jspContext.getAttribute(
428 |  |
                                     ATTR_CONTEXT_PATH, PageContext.REQUEST_SCOPE);
429 | 13 |
                     if ("/".equals(contextPath)) {
430 | 1 |
                             return "";
431 |  |
                     }
432 | 12 |
                     return contextPath;
433 |  |
             }
434 |  |
435 |  |
     }