View Javadoc

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.validator;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  import java.util.Map;
21  
22  import org.seasar.cubby.action.ActionErrors;
23  import org.seasar.cubby.action.FieldInfo;
24  import org.seasar.cubby.action.MessageInfo;
25  
26  /**
27   * 入力フォームのフィールドに対する入力検証のルールです。
28   * 
29   * @author baba
30   * @since 1.0.0
31   */
32  public class FieldValidationRule implements ValidationRule {
33  
34  	/** 空のオブジェクト配列。 */
35  	private static final Object[] EMPTY_VALUES = new Object[] { "" };
36  
37  	/** この入力検証ルールが対応する入力フォームのフィールド名。 */
38  	private final String fieldName;
39  
40  	/** リソースバンドルからフィールド名を取得するためのキー。 */
41  	private final String fieldNameKey;
42  
43  	/** 入力検証を実行するクラスのリスト。 */
44  	private final List<ValidationInvoker> invokers = new ArrayList<ValidationInvoker>();
45  
46  	/**
47  	 * 指定されたフィールド名に対する入力検証ルールを生成します。
48  	 * 
49  	 * @param fieldName
50  	 *            フィールド名
51  	 * @param validators
52  	 *            入力検証
53  	 */
54  	public FieldValidationRule(final String fieldName,
55  			final Validator... validators) {
56  		this(fieldName, fieldName, validators);
57  	}
58  
59  	/**
60  	 * 指定されたフィールド名に対する入力検証ルールを生成します。
61  	 * 
62  	 * @param fieldName
63  	 *            フィールド名
64  	 * @param fieldNameKey
65  	 *            リソースバンドルからフィールド名を取得するためのキー
66  	 * @param validators
67  	 *            入力検証
68  	 */
69  	public FieldValidationRule(final String fieldName,
70  			final String fieldNameKey, final Validator... validators) {
71  		this.fieldName = fieldName;
72  		this.fieldNameKey = fieldNameKey;
73  		for (final Validator validator : validators) {
74  			final ValidationInvoker invoker = createInvoker(validator);
75  			this.invokers.add(invoker);
76  		}
77  	}
78  
79  	/**
80  	 * {@inheritDoc}
81  	 * <p>
82  	 * 対応するフィールドに対してこのオブジェクトが保持する入力検証を順次実行します。
83  	 * </p>
84  	 */
85  	public void apply(final Map<String, Object[]> params, final Object form,
86  			final ActionErrors errors) {
87  		final Object[] values = getValues(params, this.fieldName);
88  		for (final ValidationInvoker invoker : this.invokers) {
89  			invoker.invoke(this, values, errors);
90  		}
91  	}
92  
93  	/**
94  	 * リクエストパラメータの{@link Map}から指定されたフィールド名に対する値を取得します。
95  	 * 
96  	 * @param params
97  	 *            リクエストパラメータの{@link Map}
98  	 * @param fieldName
99  	 *            フィールド名
100 	 * @return フィールド名に対する値
101 	 */
102 	private Object[] getValues(final Map<String, Object[]> params,
103 			final String fieldName) {
104 		final Object[] values = params.get(fieldName);
105 		if (values != null) {
106 			return values;
107 		}
108 		return EMPTY_VALUES;
109 	}
110 
111 	/**
112 	 * この入力検証ルールが対応する入力フォームのフィールド名を取得します。
113 	 * 
114 	 * @return この入力検証ルールが対応する入力フォームのフィールド名
115 	 */
116 	public String getFieldName() {
117 		return fieldName;
118 	}
119 
120 	/**
121 	 * リソースバンドルからフィールド名を取得するためのキーを取得します。
122 	 * 
123 	 * @return リソースバンドルからフィールド名を取得するためのキー
124 	 */
125 	public String getFieldNameKey() {
126 		return fieldNameKey;
127 	}
128 
129 	/**
130 	 * 入力検証を呼び出すクラスのインスタンスを生成します。
131 	 * 
132 	 * @param validator
133 	 *            入力検証
134 	 * @return 入力検証を呼び出すクラスのインスタンス
135 	 */
136 	private ValidationInvoker createInvoker(final Validator validator) {
137 		final ValidationInvoker invoker;
138 		if (validator instanceof ArrayFieldValidator) {
139 			invoker = new ArrayFieldValidationInvoker(
140 					(ArrayFieldValidator) validator);
141 		} else if (validator instanceof ScalarFieldValidator) {
142 			invoker = new ScalarFieldValidationInvoker(
143 					(ScalarFieldValidator) validator);
144 		} else {
145 			throw new UnsupportedOperationException();
146 		}
147 		return invoker;
148 	}
149 
150 	/**
151 	 * 入力検証を呼び出すためのクラスです。
152 	 * 
153 	 * @author baba
154 	 * @since 1.0.0
155 	 */
156 	private interface ValidationInvoker {
157 
158 		/**
159 		 * 入力検証を呼び出します。
160 		 * 
161 		 * @param validationRule
162 		 *            入力検証ルール
163 		 * @param values
164 		 *            入力検証を行う値
165 		 * @param errors
166 		 *            アクションで発生したエラー
167 		 */
168 		void invoke(FieldValidationRule validationRule, Object[] values,
169 				ActionErrors errors);
170 
171 	}
172 
173 	/**
174 	 * {@link ArrayFieldValidator}の入力検証を呼び出すためのクラスです。
175 	 * 
176 	 * @author baba
177 	 * @since 1.0.0
178 	 */
179 	private static class ArrayFieldValidationInvoker implements
180 			ValidationInvoker {
181 
182 		/**
183 		 * {@link #invoke(FieldValidationRule, Object[], ActionErrors)}
184 		 * で呼び出す入力検証。
185 		 */
186 		private final ArrayFieldValidator validator;
187 
188 		/**
189 		 * インスタンス化します。
190 		 * 
191 		 * @param validator
192 		 *            入力検証
193 		 */
194 		public ArrayFieldValidationInvoker(final ArrayFieldValidator validator) {
195 			this.validator = validator;
196 		}
197 
198 		/**
199 		 * {@inheritDoc}
200 		 */
201 		public void invoke(final FieldValidationRule validationRule,
202 				final Object[] values, final ActionErrors errors) {
203 			final ValidationContext context = new ValidationContext();
204 			final FieldInfo fieldInfo = new FieldInfo(validationRule
205 					.getFieldName());
206 			this.validator.validate(context, values);
207 			for (final MessageInfo messageInfo : context.getMessageInfos()) {
208 				final String message = messageInfo.toMessage(validationRule
209 						.getFieldNameKey());
210 				errors.add(message, fieldInfo);
211 			}
212 		}
213 
214 	}
215 
216 	/**
217 	 * {@link ScalarFieldValidator}の入力検証を呼び出すためのクラスです。
218 	 * 
219 	 * @author baba
220 	 * @since 1.0.0
221 	 */
222 	private static class ScalarFieldValidationInvoker implements
223 			ValidationInvoker {
224 
225 		/**
226 		 * {@link #invoke(FieldValidationRule, Object[], ActionErrors)}
227 		 * で呼び出す入力検証。
228 		 */
229 		private final ScalarFieldValidator validator;
230 
231 		/**
232 		 * インスタンス化します。
233 		 * 
234 		 * @param validator
235 		 *            入力検証
236 		 */
237 		public ScalarFieldValidationInvoker(final ScalarFieldValidator validator) {
238 			this.validator = validator;
239 		}
240 
241 		/**
242 		 * {@inheritDoc}
243 		 */
244 		public void invoke(final FieldValidationRule validationRule,
245 				final Object[] values, final ActionErrors errors) {
246 			for (int i = 0; i < values.length; i++) {
247 				final ValidationContext context = new ValidationContext();
248 				final FieldInfo fieldInfo = new FieldInfo(validationRule
249 						.getFieldName(), i);
250 				this.validator.validate(context, values[i]);
251 				for (final MessageInfo messageInfo : context.getMessageInfos()) {
252 					final String message = messageInfo.toMessage(validationRule
253 							.getFieldNameKey());
254 					errors.add(message, fieldInfo);
255 				}
256 			}
257 		}
258 
259 	}
260 
261 }