Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
AbstractValidator |
|
| 3.2222222222222223;3.222 |
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
3 | * contributor license agreements. See the NOTICE file distributed with | |
4 | * this work for additional information regarding copyright ownership. | |
5 | * The ASF licenses this file to you under the Apache License, Version 2.0 | |
6 | * (the "License"); you may not use this file except in compliance with | |
7 | * the License. You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
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 | 40 | public abstract class AbstractValidator extends AbstractUtilities |
44 | implements Validator { | |
45 | ||
46 | ||
47 | // ------------------------------------------------------------ Constructors | |
48 | ||
49 | ||
50 | // ------------------------------------------------------ Manifest Constants | |
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 | // -------------------------------------------------------- Static Variables | |
88 | ||
89 | ||
90 | /** | |
91 | * <p>Converter helper instance we can use in the <code>convert()</code> | |
92 | * method implementation.</p> | |
93 | */ | |
94 | 1 | protected static final ConverterHelper helper = new ConverterHelper(); |
95 | ||
96 | ||
97 | ||
98 | // -------------------------------------------------------------- Properties | |
99 | ||
100 | ||
101 | 40 | 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 | // ------------------------------------------------------- Validator Methods | |
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 | // ----------------------------------------------------- StateHolder Methods | |
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 | // ---------------------------------------------------------- Object Methods | |
172 | ||
173 | ||
174 | // ------------------------------------------------------- Protected Methods | |
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 | // Is the specified value null? If so, return it unchanged | |
207 | if (value == null) { | |
208 | return null; | |
209 | } | |
210 | ||
211 | // Is the specified value of the correct type already? | |
212 | // If so, return it unchanged | |
213 | if (type.isInstance(value)) { | |
214 | return value; | |
215 | } | |
216 | ||
217 | // Is the target type String? If so, use the asString() conversion | |
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 | // Is the source type String? If so, use the asObject() conversion | |
227 | if (value instanceof String) { | |
228 | return helper.asObject(context, type, (String) value); | |
229 | } | |
230 | ||
231 | // Fall back to converting to String, then to the requested type | |
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 | // Look up the actions we must perform | |
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 | // Perform the actions in order, throwing a ValidatorException | |
275 | // on the first one that fails (per the standard Validator contract) | |
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 | } |