1 package org.andromda.cartridges.jsf.validator;
2
3 import java.io.InputStream;
4 import java.io.Serializable;
5 import java.lang.reflect.Method;
6 import java.util.ArrayList;
7 import java.util.Collection;
8 import java.util.HashMap;
9 import java.util.Locale;
10 import java.util.Map;
11 import javax.faces.application.FacesMessage;
12 import javax.faces.component.UIComponent;
13 import javax.faces.context.ExternalContext;
14 import javax.faces.context.FacesContext;
15 import javax.faces.validator.Validator;
16 import javax.faces.validator.ValidatorException;
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19 import org.apache.commons.validator.Field;
20 import org.apache.commons.validator.Form;
21 import org.apache.commons.validator.ValidatorAction;
22 import org.apache.commons.validator.ValidatorResources;
23
24
25
26
27
28 public class JSFValidator
29 implements Validator,
30 Serializable
31 {
32 private static final Log logger = LogFactory.getLog(JSFValidator.class);
33
34
35
36
37
38
39
40
41 public JSFValidator(final String formIdIn, final ValidatorAction validatorActionIn)
42 {
43 this.formId = formIdIn;
44 this.validatorAction = validatorActionIn;
45 }
46
47 private String formId;
48
49
50
51
52 public JSFValidator()
53 {
54
55 }
56
57
58
59
60 private String type;
61
62
63
64
65
66
67
68 public void setType(final String typeIn)
69 {
70 this.type = typeIn;
71 }
72
73
74
75
76
77
78 public String getType()
79 {
80 return this.type;
81 }
82
83
84
85
86
87 private String[] args;
88
89
90
91
92
93
94
95 public void setArgs(final String[] argsIn)
96 {
97 this.args = argsIn;
98 }
99
100
101
102
103 private final Map parameters = new HashMap();
104
105
106
107
108
109
110 public Map getParameters()
111 {
112 return this.parameters;
113 }
114
115
116
117
118
119
120
121
122 public void addParameter(
123 final String name,
124 final Object value)
125 {
126 this.parameters.put(
127 name,
128 value);
129 }
130
131
132
133
134
135
136
137
138
139
140 public static ValidatorAction getValidatorAction(final String name)
141 {
142 return getValidatorResources().getValidatorAction(name);
143 }
144
145
146
147
148 private ValidatorAction validatorAction;
149
150
151
152
153 public static final String RULES_LOCATION = "/WEB-INF/validator-rules.xml";
154
155
156
157
158 private static final String VALIDATOR_RESOURCES_KEY = "org.andromda.jsf.validator.resources";
159
160
161
162
163
164
165
166
167 public static ValidatorResources getValidatorResources()
168 {
169 final FacesContext context = FacesContext.getCurrentInstance();
170 final ExternalContext external = context.getExternalContext();
171 final Map applicationMap = external.getApplicationMap();
172 ValidatorResources validatorResources = (ValidatorResources)applicationMap.get(VALIDATOR_RESOURCES_KEY);
173 if (validatorResources == null)
174 {
175 final String rulesResource = RULES_LOCATION;
176 final String validationResource = "/WEB-INF/validation.xml";
177 final InputStream rulesInput = external.getResourceAsStream(rulesResource);
178 if (rulesInput == null)
179 {
180 throw new JSFValidatorException("Could not find rules file '" + rulesResource + '\'');
181 }
182 final InputStream validationInput = external.getResourceAsStream(validationResource);
183 if (validationInput != null)
184 {
185 final InputStream[] inputs = new InputStream[] {rulesInput, validationInput};
186 try
187 {
188 validatorResources = new ValidatorResources(inputs);
189 applicationMap.put(
190 VALIDATOR_RESOURCES_KEY,
191 validatorResources);
192 }
193 catch (final Throwable throwable)
194 {
195 throw new JSFValidatorException(throwable);
196 }
197 }
198 else
199 {
200 logger.info(
201 "No validation rules could be loaded from --> '" + validationResource +
202 ", validation not configured");
203 }
204 }
205 return validatorResources;
206 }
207
208
209
210
211
212
213
214 public void validate(
215 final FacesContext context,
216 final UIComponent component,
217 final Object value)
218 {
219 if (this.formId != null)
220 {
221 try
222 {
223 final Form validatorForm = getValidatorResources().getForm(
224 Locale.getDefault(),
225 this.formId);
226 if (validatorForm != null)
227 {
228 final Field field = this.getFormField(validatorForm, component.getId());
229 if (field != null)
230 {
231 final Collection errors = new ArrayList();
232 this.getValidatorMethod().invoke(
233 this.getValidatorClass(),
234 context, value, this.getParameters(), errors, this.validatorAction,
235 field);
236 if (!errors.isEmpty())
237 {
238 throw new ValidatorException(new FacesMessage(
239 FacesMessage.SEVERITY_ERROR,
240 (String)errors.iterator().next(),
241 null));
242 }
243 }
244 else
245 {
246 logger.error("No field with id '" + component.getId() + "' found on form '" + this.formId + '\'');
247 }
248 }
249 else
250 {
251 logger.error("No validator form could be found with id '" + this.formId + '\'');
252 }
253 }
254 catch (final ValidatorException exception)
255 {
256 throw exception;
257 }
258 catch (final Exception exception)
259 {
260 logger.error(
261 exception.getMessage(),
262 exception);
263 }
264 }
265 }
266
267
268
269
270
271
272 private Class getValidatorClass()
273 throws ClassNotFoundException
274 {
275 final FacesContext context = FacesContext.getCurrentInstance();
276 final ExternalContext external = context.getExternalContext();
277 final Map applicationMap = external.getApplicationMap();
278 final String validatorClassName = this.validatorAction.getClassname();
279 Class validatorClass = (Class)applicationMap.get(validatorClassName);
280 if (validatorClass == null)
281 {
282 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
283 if (classLoader == null)
284 {
285 classLoader = getClass().getClassLoader();
286 }
287 validatorClass = classLoader.loadClass(validatorClassName);
288 applicationMap.put(
289 validatorClassName,
290 validatorClass);
291 }
292 return validatorClass;
293 }
294
295
296
297
298
299
300
301
302 private Method getValidatorMethod()
303 throws ClassNotFoundException, NoSuchMethodException
304 {
305 Class[] parameterTypes =
306 new Class[]
307 {
308 javax.faces.context.FacesContext.class, Object.class, java.util.Map.class,
309 java.util.Collection.class, org.apache.commons.validator.ValidatorAction.class,
310 org.apache.commons.validator.Field.class
311 };
312 return this.getValidatorClass().getMethod(
313 this.validatorAction.getMethod(),
314 parameterTypes);
315 }
316
317
318
319
320
321
322
323
324
325 private Field getFormField(
326 final Form form,
327 final String fieldName)
328 {
329 Field field = null;
330 if (form != null)
331 {
332 field = form.getField(fieldName);
333 }
334 return field;
335 }
336
337
338
339
340
341
342
343 public String getErrorMessage(final FacesContext context)
344 {
345 return ValidatorMessages.getMessage(
346 this.validatorAction,
347 this.args,
348 context);
349 }
350
351
352
353
354 @Override
355 public String toString()
356 {
357 return super.toString() + ":formId=" + this.formId + ", validatorAction="
358 + (this.validatorAction != null ? this.validatorAction.getName() : null);
359 }
360
361 private static final long serialVersionUID = 1;
362 }