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.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  
25  /**
26   * 入力フォームのフィールドに対する入力検証のルールです。
27   * 
28   * @author baba
29   * @since 1.0.0
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 	 * @since 1.0.0
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 	 * @since 1.0.0
177 	 */
178 	private static class ArrayFieldValidationInvoker implements
179 			ValidationInvoker {
180 
181 		/** {@link #invoke(FieldValidationRule, Object[], ActionErrors)}で呼び出す入力検証。 */
182 		private final ArrayFieldValidator validator;
183 
184 		/**
185 		 * インスタンス化します。
186 		 * 
187 		 * @param validator
188 		 *            入力検証
189 		 */
190 		public ArrayFieldValidationInvoker(final ArrayFieldValidator validator) {
191 			this.validator = validator;
192 		}
193 
194 		/**
195 		 * {@inheritDoc}
196 		 */
197 		public void invoke(final FieldValidationRule validationRule,
198 				final Object[] values, final ActionErrors errors) {
199 			final ValidationContext context = new ValidationContext();
200 			final FieldInfo fieldInfo = new FieldInfo(validationRule
201 					.getFieldName());
202 			this.validator.validate(context, values);
203 			for (final MessageInfo message : context.getMessageInfos()) {
204 				errors
205 						.add(message.builder().fieldNameKey(
206 								validationRule.getFieldNameKey()).toString(),
207 								fieldInfo);
208 			}
209 		}
210 
211 	}
212 
213 	/**
214 	 * {@link ScalarFieldValidator}の入力検証を呼び出すためのクラスです。
215 	 * 
216 	 * @author baba
217 	 * @since 1.0.0
218 	 */
219 	private static class ScalarFieldValidationInvoker implements
220 			ValidationInvoker {
221 
222 		/** {@link #invoke(FieldValidationRule, Object[], ActionErrors)}で呼び出す入力検証。 */
223 		private final ScalarFieldValidator validator;
224 
225 		/**
226 		 * インスタンス化します。
227 		 * 
228 		 * @param validator
229 		 *            入力検証
230 		 */
231 		public ScalarFieldValidationInvoker(final ScalarFieldValidator validator) {
232 			this.validator = validator;
233 		}
234 
235 		/**
236 		 * {@inheritDoc}
237 		 */
238 		public void invoke(final FieldValidationRule validationRule,
239 				final Object[] values, final ActionErrors errors) {
240 			for (int i = 0; i < values.length; i++) {
241 				final ValidationContext context = new ValidationContext();
242 				final FieldInfo fieldInfo = new FieldInfo(validationRule
243 						.getFieldName(), i);
244 				this.validator.validate(context, values[i]);
245 				for (final MessageInfo messageInfo : context.getMessageInfos()) {
246 					final String message = messageInfo.builder().fieldNameKey(
247 							validationRule.getFieldNameKey()).toString();
248 					errors.add(message, fieldInfo);
249 				}
250 			}
251 		}
252 
253 	}
254 
255 }