Coverage Report - org.seasar.cubby.tags.TagUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
TagUtils
87%
84/96
75%
41/54
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  
 }