View Javadoc

1   /*
2    * Copyright 2004-2010 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  
17  package org.seasar.cubby.validator;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.seasar.cubby.action.ActionErrors;
24  import org.seasar.cubby.action.FieldInfo;
25  import org.seasar.cubby.action.MessageInfo;
26  
27  /**
28   * 入力フォームのフィールドに対する入力検証のルールです。
29   * 
30   * @author baba
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 	 */
155 	private interface ValidationInvoker {
156 
157 		/**
158 		 * 入力検証を呼び出します。
159 		 * 
160 		 * @param validationRule
161 		 *            入力検証ルール
162 		 * @param values
163 		 *            入力検証を行う値
164 		 * @param errors
165 		 *            アクションで発生したエラー
166 		 */
167 		void invoke(FieldValidationRule validationRule, Object[] values,
168 				ActionErrors errors);
169 
170 	}
171 
172 	/**
173 	 * {@link ArrayFieldValidator}の入力検証を呼び出すためのクラスです。
174 	 * 
175 	 * @author baba
176 	 */
177 	private static class ArrayFieldValidationInvoker implements
178 			ValidationInvoker {
179 
180 		/**
181 		 * {@link #invoke(FieldValidationRule, Object[], ActionErrors)}
182 		 * で呼び出す入力検証。
183 		 */
184 		private final ArrayFieldValidator validator;
185 
186 		/**
187 		 * インスタンス化します。
188 		 * 
189 		 * @param validator
190 		 *            入力検証
191 		 */
192 		public ArrayFieldValidationInvoker(final ArrayFieldValidator validator) {
193 			this.validator = validator;
194 		}
195 
196 		/**
197 		 * {@inheritDoc}
198 		 */
199 		public void invoke(final FieldValidationRule validationRule,
200 				final Object[] values, final ActionErrors errors) {
201 			final ValidationContext context = new ValidationContext();
202 			final FieldInfo fieldInfo = new FieldInfo(validationRule
203 					.getFieldName());
204 			this.validator.validate(context, values);
205 			for (final MessageInfo messageInfo : context.getMessageInfos()) {
206 				final String message = messageInfo.toMessage(validationRule
207 						.getFieldNameKey());
208 				errors.add(message, fieldInfo);
209 			}
210 		}
211 
212 	}
213 
214 	/**
215 	 * {@link ScalarFieldValidator}の入力検証を呼び出すためのクラスです。
216 	 * 
217 	 * @author baba
218 	 */
219 	private static class ScalarFieldValidationInvoker implements
220 			ValidationInvoker {
221 
222 		/**
223 		 * {@link #invoke(FieldValidationRule, Object[], ActionErrors)}
224 		 * で呼び出す入力検証。
225 		 */
226 		private final ScalarFieldValidator validator;
227 
228 		/**
229 		 * インスタンス化します。
230 		 * 
231 		 * @param validator
232 		 *            入力検証
233 		 */
234 		public ScalarFieldValidationInvoker(final ScalarFieldValidator validator) {
235 			this.validator = validator;
236 		}
237 
238 		/**
239 		 * {@inheritDoc}
240 		 */
241 		public void invoke(final FieldValidationRule validationRule,
242 				final Object[] values, final ActionErrors errors) {
243 			for (int i = 0; i < values.length; i++) {
244 				final ValidationContext context = new ValidationContext();
245 				final FieldInfo fieldInfo = new FieldInfo(validationRule
246 						.getFieldName(), i);
247 				this.validator.validate(context, values[i]);
248 				for (final MessageInfo messageInfo : context.getMessageInfos()) {
249 					final String message = messageInfo.toMessage(validationRule
250 							.getFieldNameKey());
251 					errors.add(message, fieldInfo);
252 				}
253 			}
254 		}
255 
256 	}
257 
258 }