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