2009/05/20 - Apache Shale has been retired.
For more information, please explore the Attic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shale.validator.validator;
19
20 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22 import java.text.MessageFormat;
23 import java.util.Locale;
24 import java.util.Map;
25
26 import javax.faces.application.FacesMessage;
27 import javax.faces.component.UIComponent;
28 import javax.faces.context.FacesContext;
29 import javax.faces.validator.Validator;
30 import javax.faces.validator.ValidatorException;
31
32 import org.apache.commons.validator.Arg;
33 import org.apache.commons.validator.ValidatorResources;
34 import org.apache.shale.util.ConverterHelper;
35 import org.apache.shale.validator.Globals;
36 import org.apache.shale.validator.util.AbstractUtilities;
37 import org.apache.shale.validator.util.ShaleValidatorAction;
38
39 /***
40 * <p>Abstract base class for validators that use Apache Commons Validator
41 * as their foundation.</p>
42 */
43 public abstract class AbstractValidator extends AbstractUtilities
44 implements Validator {
45
46
47
48
49
50
51
52
53 /***
54 * <p>Variable name in a <code>vars</code> map representing the argument
55 * that was being evaluated, and should be included in any error message.
56 * Typically, this will be either the value itself or a user-friendly
57 * (localized) field label.</p>
58 */
59 protected static final String ARG_VALUE =
60 "arg";
61
62
63 /***
64 * <p>Variable name in a <code>vars</code> map representing the maximum
65 * value that should be accepted by this <code>Validator</code>.</p>
66 */
67 protected static final String MAXIMUM_VALUE =
68 "max";
69
70
71 /***
72 * <p>Variable name in a <code>vars</code> map representing the minimum
73 * value that should be accepted by this <code>Validator</code>.</p>
74 */
75 protected static final String MINIMUM_VALUE =
76 "min";
77
78
79 /***
80 * <p>Variable name in a <code>vars</code> map representing the submitted
81 * value that should be validated by this <code>Validator</code>.</p>
82 */
83 protected static final String SUBMITTED_VALUE =
84 "submittedValue";
85
86
87
88
89
90 /***
91 * <p>Converter helper instance we can use in the <code>convert()</code>
92 * method implementation.</p>
93 */
94 protected static final ConverterHelper helper = new ConverterHelper();
95
96
97
98
99
100
101 private boolean client = true;
102
103
104 /***
105 * <p>Return a flag describing whether this validator should be enforced
106 * on the client side or not. Default is <code>true</code>.</p>
107 */
108 public boolean isClient() {
109 return this.client;
110 }
111
112
113 /***
114 * <p>Set a flag describing whether this validator should be enforced
115 * on the client side or not.</p>
116 *
117 * @param client The new client enforcement flag
118 */
119 public void setClient(boolean client) {
120 this.client = client;
121 }
122
123
124
125
126
127 /***
128 * <p>Perform the correctness checks implemented by this
129 * {@link Validator} against the specified {@link UIComponent}.
130 * If any violations are found, a {@link ValidatorException}
131 * will be thrown containing the {@link javax.faces.application.FacesMessage}
132 * describing the failure.</p>
133 *
134 * <p><strong>IMPLEMENTATION NOTE</strong>: Unlike earlier implementations
135 * of Shale Validator integration, validators that subclass this class do
136 * not support the option to skip server side validation.</p>
137 *
138 * @param context <code>FacesContext</code> for the current request
139 * @param component <code>UIComponent</code> we are checking for correctness
140 * @param value The value to validate
141 *
142 * @throws ValidatorException if validation fails
143 * @throws NullPointerException if <code>context</code>
144 * or <code>component</code> is <code>null</code>
145 */
146 public abstract void validate(FacesContext context,
147 UIComponent component,
148 Object value) throws ValidatorException;
149
150
151
152
153
154 /*** {@inheritDoc} */
155 public void restoreState(FacesContext context, Object state) {
156 Object[] values = (Object[]) state;
157 super.restoreState(context, values[0]);
158 this.client = Boolean.TRUE.equals((Boolean) values[1]);
159 }
160
161
162 /*** {@inheritDoc} */
163 public Object saveState(FacesContext context) {
164 Object[] values = new Object[2];
165 values[0] = super.saveState(context);
166 values[1] = this.client ? Boolean.TRUE : Boolean.FALSE;
167 return values;
168 }
169
170
171
172
173
174
175
176
177 /***
178 * <p>Return an array of <code>ShaleValidatorAction</code>s to execute
179 * for a given validation, starting with the configured dependent
180 * actions, and ending with the action corresponding to the specified
181 * action type. If there is no defined action with the specified
182 * type, return <code>null</code>.</p>
183 *
184 * @param context <code>FacesContext</code> for the current request
185 * @param type Type of the validator action for which to return actions
186 */
187 protected ShaleValidatorAction[] actions(FacesContext context, String type) {
188
189 Map actions = (Map) context.getExternalContext().
190 getApplicationMap().get(Globals.VALIDATOR_ACTIONS);
191 return (ShaleValidatorAction[]) actions.get(type);
192
193 }
194
195
196 /***
197 * <p>Use the registered converters to convert the specified value
198 * to the specified type.</p>
199 *
200 * @param context <code>FacesContext</code> for the current request
201 * @param value Value to be converted
202 * @param type Type to which the value should be converted
203 */
204 protected Object convert(FacesContext context, Object value, Class type) {
205
206
207 if (value == null) {
208 return null;
209 }
210
211
212
213 if (type.isInstance(value)) {
214 return value;
215 }
216
217
218 if (type == String.class) {
219 if (value instanceof String) {
220 return value;
221 } else {
222 return helper.asString(context, value.getClass(), value);
223 }
224 }
225
226
227 if (value instanceof String) {
228 return helper.asObject(context, type, (String) value);
229 }
230
231
232 String string = helper.asString(context, value.getClass(), value);
233 return helper.asObject(context, type, string);
234
235 }
236
237
238 /***
239 * <p>Return the <code>ValidatorResources</code> that describe the
240 * validation rules to be enforced by this application.</p>
241 *
242 * @param context <code>FacesContext</code> for the current request
243 */
244 protected ValidatorResources resources(FacesContext context) {
245
246 return (ValidatorResources) context.getExternalContext().
247 getApplicationMap().get(Globals.VALIDATOR_RESOURCES);
248
249 }
250
251
252 /***
253 * <p>Perform a validation using the specified Commons Validator type.</p>
254 *
255 * @param context <code>FacesContext</code> for the current request
256 * @param component <code>UIComponent</code> whose value is being validated
257 * @param value The value being validated
258 * @param type Type of validation to be performed
259 * @param vars Mutable map of values to be passed in to the validation
260 *
261 * @exception ValidatorException if a validation error occurs
262 */
263 protected void validate(FacesContext context, UIComponent component,
264 Object value, String type, Map vars)
265 throws ValidatorException {
266
267
268 ShaleValidatorAction[] actions = actions(context, type);
269 if (actions == null) {
270 throw new IllegalArgumentException("No validator for type '"
271 + type + "' has been configured");
272 }
273
274
275
276 for (int i = 0; i < actions.length; i++) {
277 Object instance = actions[i].getInstance();
278 Method method = actions[i].getMethod();
279 Class[] signature = actions[i].getSignature();
280 Arg[] args = actions[i].getParameterArgs();
281 Object[] parameters = new Object[signature.length];
282 for (int j = 0; j < parameters.length; j++) {
283 parameters[j] = convert(context, vars.get(args[j].getKey()), signature[j]);
284 }
285 Boolean result = null;
286 try {
287 result = (Boolean) method.invoke(instance, parameters);
288 } catch (IllegalAccessException e) {
289 ;
290 } catch (InvocationTargetException e) {
291 ;
292 }
293 if (!result.booleanValue()) {
294 String error = getMessage();
295 if (error == null) {
296 error = message(context, actions[i].getMessageKey());
297 }
298 args = actions[i].getMessageArgs();
299 parameters = new Object[args.length];
300 for (int j = 0; j < parameters.length; j++) {
301 parameters[j] = vars.get(args[j].getKey());
302 }
303 Locale locale = context.getViewRoot().getLocale();
304 String formatted = new MessageFormat(error, locale).format(parameters);
305 FacesMessage message =
306 new FacesMessage(FacesMessage.SEVERITY_ERROR, formatted, null);
307 throw new ValidatorException(message);
308 }
309 }
310
311 }
312
313
314 }