View Javadoc

1   /*
2    * Copyright 2004-2008 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_PARAMS;
21  import static org.seasar.cubby.CubbyConstants.ATTR_VALIDATION_FAIL;
22  
23  import java.util.Collection;
24  import java.util.Map;
25  import java.util.Map.Entry;
26  
27  import javax.servlet.jsp.JspContext;
28  import javax.servlet.jsp.tagext.SimpleTag;
29  import javax.servlet.jsp.tagext.SimpleTagSupport;
30  
31  import org.seasar.cubby.CubbyConstants;
32  import org.seasar.cubby.action.ActionErrors;
33  import org.seasar.cubby.util.CubbyUtils;
34  import org.seasar.framework.util.StringUtil;
35  
36  /**
37   * カスタムタグで使用するユーティリティクラスです。
38   * 
39   * @author baba
40   * @since 1.0.0
41   */
42  class TagUtils {
43  
44  	/** リクエストスコープから{@link ActionErrors}を取得するためのキー。 */
45  	private static final String ATTR_ERRORS = "errors";
46  
47  	/**
48  	 * 指定されたJSPコンテキストから{@link ActionErrors}を取得します。
49  	 * 
50  	 * @param context
51  	 *            JSPコンテキスト
52  	 * @return アクションで発生したエラー
53  	 */
54  	public static ActionErrors errors(final JspContext context) {
55  		return (ActionErrors) context.getAttribute(ATTR_ERRORS, REQUEST_SCOPE);
56  	}
57  
58  	/**
59  	 * 指定されたJSPコンテキストから指定されたパラメータ名に対応するリクエストパラメータを取得します。
60  	 * 
61  	 * @param context
62  	 *            JSPコンテキスト
63  	 * @param name
64  	 *            パラメータ名
65  	 * @return リクエストパラメータ
66  	 */
67  	@SuppressWarnings("unchecked")
68  	private static Object[] paramValues(final JspContext context,
69  			final String name) {
70  		final Map<String, Object[]> valuesMap = Map.class.cast(context
71  				.getAttribute(ATTR_PARAMS, REQUEST_SCOPE));
72  		final Object[] values;
73  		if (valuesMap == null || !valuesMap.containsKey(name)) {
74  			values = new Object[0];
75  		} else {
76  			values = valuesMap.get(name);
77  		}
78  		return values;
79  	}
80  
81  	/**
82  	 * 指定されたフィールド名に対応するフォームのフィールドへの出力値を取得します。
83  	 * 
84  	 * @param context
85  	 *            JSPコンテキスト
86  	 * @param outputValues
87  	 *            フォームへ出力する値
88  	 * @param name
89  	 *            フィールド名
90  	 * @return フォームのフィールドへの出力値
91  	 */
92  	public static Object[] multipleFormValues(final JspContext context,
93  			final String[] outputValues, final String name) {
94  		return multipleFormValues(context, outputValues, name, null);
95  	}
96  
97  	/**
98  	 * 指定されたフィールド名に対応するフォームのフィールドへの出力値を取得します。
99  	 * 
100 	 * @param context
101 	 *            JSPコンテキスト
102 	 * @param outputValues
103 	 *            フォームへ出力する値
104 	 * @param name
105 	 *            フィールド名
106 	 * @param checkedValue
107 	 *            チェック済みにする値
108 	 * @return フォームのフィールドへの出力値
109 	 */
110 	public static Object[] multipleFormValues(final JspContext context,
111 			final String[] outputValues, final String name,
112 			final String checkedValue) {
113 		final Object[] values;
114 		if (isValidationFail(context)) {
115 			values = paramValues(context, name);
116 		} else {
117 			if (checkedValue != null) {
118 				values = new Object[] { checkedValue };
119 			} else if (outputValues == null) {
120 				values = paramValues(context, name);
121 			} else {
122 				values = outputValues;
123 			}
124 		}
125 		return values;
126 	}
127 
128 	/**
129 	 * 指定されたフィールド名に対応するフォームのフィールドへの出力値を取得します。
130 	 * 
131 	 * @param context
132 	 *            JSPコンテキスト
133 	 * @param outputValuesMap
134 	 *            フォームへ出力する値
135 	 * @param name
136 	 *            フィールド名
137 	 * @param index
138 	 *            インデックス
139 	 * @param specifiedValue
140 	 *            エラーがない場合に設定する値
141 	 * @return フォームのフィールドへの出力値
142 	 */
143 	public static Object formValue(final JspContext context,
144 			final String[] outputValues, final String name,
145 			final Integer index, final Object specifiedValue) {
146 		final Object value;
147 
148 		if (isValidationFail(context)) {
149 			if (specifiedValue == null) {
150 				final Object[] values = paramValues(context, name);
151 				value = value(values, index);
152 			} else {
153 				final Object[] values = paramValues(context, name);
154 				if (values.length == 0) {
155 					value = specifiedValue;
156 				} else {
157 					value = value(values, index);
158 				}
159 			}
160 		} else {
161 			if (specifiedValue != null) {
162 				value = specifiedValue;
163 			} else if (outputValues == null) {
164 				final Object[] values = paramValues(context, name);
165 				value = value(values, index);
166 			} else {
167 				value = value(outputValues, index);
168 			}
169 		}
170 
171 		return value;
172 	}
173 
174 	/**
175 	 * オブジェクトの配列から指定されたインデックスの値を取得します。
176 	 * <p>
177 	 * values が <code>null</code> の場合や index が要素数を越えていた場合は空文字を返します。index が
178 	 * <code>null</code> の場合は配列の最初の要素を返します。
179 	 * </p>
180 	 * 
181 	 * @param values
182 	 *            オブジェクトの配列
183 	 * @param index
184 	 *            インデックス
185 	 * @return 指定されたインデックスの要素
186 	 */
187 	private static Object value(final Object[] values, final Integer index) {
188 		final Object value;
189 		if (values == null) {
190 			value = "";
191 		} else {
192 			if (index == null) {
193 				value = getElement(values, 0);
194 			} else {
195 				value = getElement(values, index);
196 			}
197 		}
198 		return value;
199 	}
200 
201 	/**
202 	 * オブジェクトの配列から指定されたインデックスの要素を取得します。
203 	 * <p>
204 	 * index が要素数を越えていた場合は空文字を返します。
205 	 * </p>
206 	 * 
207 	 * @param values
208 	 *            オブジェクトの配列
209 	 * @param index
210 	 *            インデックス
211 	 * @return 指定されたインデックスの要素
212 	 */
213 	private static Object getElement(final Object[] values, final Integer index) {
214 		final Object value;
215 		if (values.length <= index) {
216 			value = "";
217 		} else {
218 			value = values[index];
219 		}
220 		return value;
221 	}
222 
223 	/**
224 	 * 指定されたJSPコンテキストのアクションが入力検証に失敗したかどうかを示します。
225 	 * 
226 	 * @param context
227 	 *            JSPコンテキスト
228 	 * @return アクションが入力検証に失敗した場合は <code>true</code>、そうでない場合は
229 	 *         <code>false</code>
230 	 * @see CubbyConstants#ATTR_VALIDATION_FAIL
231 	 */
232 	private static boolean isValidationFail(final JspContext context) {
233 		return TRUE.equals(context.getAttribute(ATTR_VALIDATION_FAIL,
234 				REQUEST_SCOPE));
235 	}
236 
237 	public static final Object REMOVE_ATTRIBUTE = new Object();
238 
239 	/**
240 	 * 指定された {@link Map} を HTML タグの属性へ変換します。
241 	 * <p>
242 	 * map 中の値が {@link #REMOVE_ATTRIBUTE} の場合、その属性は結果から除外します。
243 	 * </p>
244 	 * 
245 	 * @param map
246 	 *            属性のマップ
247 	 * @return HTML タグの属性
248 	 */
249 	public static String toAttr(final Map<String, Object> map) {
250 		final StringBuilder builder = new StringBuilder();
251 		for (final Entry<String, Object> entry : map.entrySet()) {
252 			final String key = entry.getKey();
253 			if (entry.getValue() == REMOVE_ATTRIBUTE) {
254 				continue;
255 			}
256 			builder.append(key);
257 			builder.append("=\"");
258 			builder.append(CubbyUtils.escapeHtml(entry.getValue()));
259 			builder.append("\" ");
260 		}
261 		return builder.toString();
262 	}
263 
264 	/**
265 	 * 指定されたオブジェクトが特定の文字列を含むかを示します。
266 	 * <p>
267 	 * 指定されたオブジェクトが配列や{@link Collection}の場合は、その要素の文字列表現が指定された文字列と同値かを示します。
268 	 * 指定されたオブジェクトが配列や{@link Collection}でない場合は、そのオブジェクトの文字列表現が指定された文字列と同値かを示します。
269 	 * </p>
270 	 * 
271 	 * @param obj
272 	 *            オブジェクト
273 	 * @param str
274 	 *            文字列
275 	 * @return 指定されたオブジェクトが特定の文字列を含む場合は <code>true</code>、そうでない場合は
276 	 *         <code>false</code>
277 	 */
278 	public static boolean contains(final Object obj, final String str) {
279 		if (obj instanceof Collection) {
280 			return ((Collection<?>) obj).contains(str);
281 		} else if (obj.getClass().isArray()) {
282 			for (final Object value : (Object[]) obj) {
283 				if (equalsAsString(value, str)) {
284 					return true;
285 				}
286 			}
287 			return false;
288 		} else {
289 			return equalsAsString(obj, str);
290 		}
291 	}
292 
293 	/**
294 	 * 指定された値が文字列として同値かを示します。
295 	 * 
296 	 * @param obj1
297 	 *            比較するオブジェクト1
298 	 * @param obj2
299 	 *            比較するオブジェクト2
300 	 * @return obj1とobj2が文字列として同値の場合は <code>true</code>、そうでない場合は
301 	 *         <code>false</code>
302 	 */
303 	private static boolean equalsAsString(final Object obj1, final Object obj2) {
304 		if (obj1 == obj2) {
305 			return true;
306 		} else if (obj1 == null) {
307 			return false;
308 		} else {
309 			return obj1.toString().equals(obj2.toString());
310 		}
311 	}
312 
313 	/**
314 	 * Dynamic-Attributes に指定された class 属性を追加します。
315 	 * 
316 	 * @param dyn
317 	 *            Dynamic-Attributes
318 	 * @param className
319 	 *            class属性の名前
320 	 */
321 	public static void addClassName(final Map<String, Object> dyn,
322 			final String className) {
323 		String classValue = (String) dyn.get("class");
324 		if (StringUtil.isEmpty(classValue)) {
325 			classValue = className;
326 		} else {
327 			classValue = classValue + " " + className;
328 		}
329 		dyn.put("class", classValue);
330 	}
331 
332 	/**
333 	 * 指定されたタグの親の {@ilnk FormTag} を検索し、そこから指定されたフィールド名の値を取得します。
334 	 * 
335 	 * @param tag
336 	 *            タグ
337 	 * @param name
338 	 *            フィールド名
339 	 * @return 指定されたフィールド名の値
340 	 */
341 	public static String[] getOutputValues(final SimpleTag tag,
342 			final String name) {
343 		final FormTag formTag = (FormTag) SimpleTagSupport
344 				.findAncestorWithClass(tag, FormTag.class);
345 		if (formTag == null) {
346 			return null;
347 		}
348 		final String[] outputValues = formTag.getValues(name);
349 		return outputValues;
350 	}
351 
352 }