1 package org.nuiton.validator.bean;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 import com.google.common.collect.Lists;
25 import com.google.common.collect.Maps;
26 import org.apache.commons.beanutils.ConversionException;
27 import org.apache.commons.beanutils.Converter;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.nuiton.converter.ConverterUtil;
31 import org.nuiton.validator.NuitonValidator;
32 import org.nuiton.validator.NuitonValidatorResult;
33 import org.nuiton.validator.NuitonValidatorScope;
34 import org.nuiton.validator.bean.list.BeanListValidator;
35 import org.nuiton.validator.bean.simple.SimpleBeanValidator;
36
37 import java.beans.Introspector;
38 import java.util.Collections;
39 import java.util.HashSet;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Set;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public abstract class AbstractNuitonValidatorContext<O, V, E> {
63
64
65 private static final Log log =
66 LogFactory.getLog(AbstractNuitonValidatorContext.class);
67
68
69 protected O bean;
70
71
72
73
74
75 protected NuitonValidatorResult messages;
76
77
78 protected NuitonValidator<O> validator;
79
80
81 protected final Map<String, String> conversionErrors;
82
83
84
85
86
87
88 protected boolean canValidate;
89
90 protected abstract E createEvent(V source,
91 O bean,
92 String field,
93 NuitonValidatorScope scope,
94 String[] toAdd,
95 String[] toDelete);
96
97 public AbstractNuitonValidatorContext() {
98 conversionErrors = Maps.newTreeMap();
99 }
100
101 public O getBean() {
102 return bean;
103 }
104
105 public void setBean(O bean) {
106 if (log.isDebugEnabled()) {
107 log.debug(this + " : " + bean);
108 }
109
110
111 conversionErrors.clear();
112 this.bean = bean;
113
114 setCanValidate(!validator.getEffectiveFields().isEmpty() && bean != null);
115 }
116
117 public NuitonValidator<O> getValidator() {
118 return validator;
119 }
120
121 public NuitonValidatorResult getMessages() {
122 return messages;
123 }
124
125 public boolean isCanValidate() {
126 return canValidate;
127 }
128
129 public void setCanValidate(boolean canValidate) {
130 this.canValidate = canValidate;
131 }
132
133 public boolean isValid() {
134 return messages == null || messages.isValid();
135 }
136
137 public boolean hasFatalErrors() {
138 boolean result = messages != null && messages.hasFatalMessages();
139 return result;
140 }
141
142 public boolean hasErrors() {
143 boolean result = messages != null && messages.hasErrorMessagess();
144 return result;
145 }
146
147 public boolean hasWarnings() {
148 boolean result = messages != null && messages.hasWarningMessages();
149 return result;
150 }
151
152 public boolean hasInfos() {
153 boolean result = messages != null && messages.hasInfoMessages();
154 return result;
155 }
156
157 public boolean isValid(String fieldName) {
158
159
160 boolean result = !(
161 messages.hasMessagesForScope(fieldName, NuitonValidatorScope.FATAL) ||
162 messages.hasMessagesForScope(fieldName, NuitonValidatorScope.ERROR));
163
164 return result;
165 }
166
167 public NuitonValidatorScope getHighestScope(String field) {
168
169 NuitonValidatorScope scope = messages.getFieldHighestScope(field);
170 return scope;
171 }
172
173 public void setValidator(NuitonValidator<O> validator) {
174 this.validator = validator;
175 }
176
177 public NuitonValidatorResult validate() {
178 NuitonValidatorResult result = validator.validate(bean);
179
180
181
182 for (Map.Entry<String, String> entry : conversionErrors.entrySet()) {
183
184
185
186 String field = entry.getKey();
187
188
189 List<String> errors = result.getErrorMessages(field);
190
191 String conversionError = entry.getValue();
192 if (errors != null) {
193 errors.clear();
194 errors.add(conversionError);
195 } else {
196 errors = Collections.singletonList(conversionError);
197 }
198
199 result.setMessagesForScope(NuitonValidatorScope.ERROR, field, errors);
200 }
201 return result;
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215 @SuppressWarnings({"unchecked"})
216 public <T> T convert(String fieldName, String value, Class<T> valueClass) {
217 if (fieldName == null) {
218 throw new IllegalArgumentException("fieldName can not be null");
219 }
220 if (valueClass == null) {
221 throw new IllegalArgumentException("valueClass can not be null");
222 }
223
224
225
226 if (!isCanValidate() || value == null) {
227 return null;
228 }
229
230
231 conversionErrors.remove(fieldName);
232
233 T result;
234 try {
235 Converter converter = ConverterUtil.getConverter(valueClass);
236 if (converter == null) {
237 throw new RuntimeException(
238 "could not find converter for the type " + valueClass);
239 }
240 result = converter.convert(valueClass, value);
241
242
243
244
245
246 } catch (ConversionException e) {
247
248 String s = Introspector.decapitalize(valueClass.getSimpleName());
249 conversionErrors.put(fieldName, "error.convertor." + s);
250 throw e;
251 }
252 return result;
253 }
254
255 public List<E> mergeMessages(V beanValidator,
256 NuitonValidatorResult newMessages) {
257
258 if (newMessages == null && messages == null) {
259
260
261
262 return null;
263 }
264
265 Set<NuitonValidatorScope> scopes = getValidator().getEffectiveScopes();
266
267
268 List<E> events = Lists.newArrayList();
269
270 for (NuitonValidatorScope scope : scopes) {
271
272
273 mergeMessages(beanValidator, scope, newMessages, events);
274
275 }
276
277 if (newMessages != null) {
278
279
280
281
282 this.messages = newMessages;
283 }
284
285 return events;
286 }
287
288 protected void mergeMessages(V beanValidator,
289 NuitonValidatorScope scope,
290 NuitonValidatorResult newMessages,
291 List<E> events) {
292
293
294 if (newMessages == null) {
295
296
297
298 List<String> fieldsForScope = messages.getFieldsForScope(scope);
299
300 for (String field : fieldsForScope) {
301 List<String> messagesForScope = messages.getMessagesForScope(field, scope);
302 events.add(createEvent(beanValidator, bean, field, scope, null, messagesForScope.toArray(new String[messagesForScope.size()])));
303 }
304
305
306 messages.clearMessagesForScope(scope);
307
308
309 } else {
310
311 List<String> newFields = newMessages.getFieldsForScope(scope);
312
313 if (messages == null) {
314
315
316
317 for (String field : newFields) {
318 List<String> messagesForScope = newMessages.getMessagesForScope(field, scope);
319 events.add(createEvent(beanValidator, bean, field, scope, messagesForScope.toArray(new String[messagesForScope.size()]), null));
320 }
321
322
323 return;
324 }
325
326 List<String> oldFields = messages.getFieldsForScope(scope);
327
328 Iterator<String> itr;
329
330
331 itr = newFields.iterator();
332 while (itr.hasNext()) {
333 String newField = itr.next();
334
335 if (!oldFields.contains(newField)) {
336
337
338 List<String> messagesForScope = newMessages.getMessagesForScope(newField, scope);
339 events.add(createEvent(beanValidator, bean, newField, scope, messagesForScope.toArray(new String[messagesForScope.size()]), null));
340
341
342 itr.remove();
343 }
344 }
345
346
347 itr = oldFields.iterator();
348 while (itr.hasNext()) {
349 String oldField = itr.next();
350
351 if (!newFields.contains(oldField)) {
352
353
354 List<String> messagesForScope = messages.getMessagesForScope(oldField, scope);
355 events.add(createEvent(beanValidator, bean, oldField, scope, null, messagesForScope.toArray(new String[messagesForScope.size()])));
356
357
358 itr.remove();
359 }
360 }
361
362
363 for (String field : newFields) {
364
365 List<String> newMessagesForScope = newMessages.getMessagesForScope(field, scope);
366 List<String> oldMessagesForScope = messages.getMessagesForScope(field, scope);
367
368
369 Set<String> toDelete = new HashSet<String>(oldMessagesForScope);
370 toDelete.removeAll(newMessagesForScope);
371
372
373 Set<String> toAdd = new HashSet<String>(newMessagesForScope);
374 toAdd.removeAll(oldMessagesForScope);
375
376 events.add(createEvent(
377 beanValidator,
378 bean,
379 field,
380 scope,
381 toAdd.isEmpty() ? null : toAdd.toArray(new String[toAdd.size()]),
382 toDelete.isEmpty() ? null : toDelete.toArray(new String[toDelete.size()])
383 ));
384
385 }
386 }
387 }
388 }