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