1 package org.nuiton.validator.bean.list;
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.base.Preconditions;
25 import com.google.common.collect.ImmutableSet;
26 import com.google.common.collect.Lists;
27 import com.google.common.collect.Maps;
28 import com.google.common.collect.Sets;
29 import org.apache.commons.beanutils.ConversionException;
30 import org.apache.commons.collections4.CollectionUtils;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.nuiton.util.beans.BeanUtil;
34 import org.nuiton.validator.NuitonValidator;
35 import org.nuiton.validator.NuitonValidatorFactory;
36 import org.nuiton.validator.NuitonValidatorModel;
37 import org.nuiton.validator.NuitonValidatorProvider;
38 import org.nuiton.validator.NuitonValidatorResult;
39 import org.nuiton.validator.NuitonValidatorScope;
40 import org.nuiton.validator.bean.AbstractNuitonValidatorContext;
41 import org.nuiton.validator.bean.AbstractValidator;
42
43 import java.beans.PropertyChangeListener;
44 import java.util.Collection;
45 import java.util.Collections;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Set;
49
50
51
52
53
54
55
56
57
58 public class BeanListValidator<O> extends AbstractValidator<O> {
59
60
61 private static final Log log = LogFactory.getLog(BeanListValidator.class);
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 public static <O> BeanListValidator<O> newValidator(Class<O> type,
77 String context,
78 NuitonValidatorScope... scopes) throws NullPointerException {
79
80
81
82 String providerName = NuitonValidatorFactory.getDefaultProviderName();
83
84
85 BeanListValidator<O> beanValidator = newValidator(providerName,
86 type,
87 context,
88 scopes
89 );
90 return beanValidator;
91 }
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 public static <O> BeanListValidator<O> newValidator(String providerName,
109 Class<O> type,
110 String context,
111 NuitonValidatorScope... scopes) throws NullPointerException {
112
113 Preconditions.checkNotNull(type, "type parameter can not be null.");
114
115
116 NuitonValidatorProvider provider =
117 NuitonValidatorFactory.getProvider(providerName);
118
119 Preconditions.checkState(
120 provider != null,
121 "Could not find provider with name " + providerName);
122
123
124 BeanListValidator<O> validator = new BeanListValidator<O>(
125 provider, type, context, scopes
126 );
127
128 return validator;
129 }
130
131
132
133
134
135
136 protected final Map<O, NuitonValidatorContext<O>> contexts;
137
138
139
140
141
142
143 protected NuitonValidator<O> delegate;
144
145 public BeanListValidator(NuitonValidatorProvider validatorProvider,
146 Class<O> beanClass,
147 String context) {
148
149 this(validatorProvider, beanClass,
150 context,
151 NuitonValidatorScope.values()
152 );
153 }
154
155 public BeanListValidator(NuitonValidatorProvider validatorProvider,
156 Class<O> beanClass,
157 String context,
158 NuitonValidatorScope... scopes) {
159
160 super(validatorProvider, beanClass);
161
162 contexts = Maps.newHashMap();
163
164
165 rebuildDelegateValidator(beanClass, context, scopes);
166
167
168 firePropertyChange(CONTEXT_PROPERTY,
169 null,
170 context
171 );
172
173
174 firePropertyChange(SCOPES_PROPERTY,
175 null,
176 scopes
177 );
178 }
179
180
181
182
183
184
185
186
187 public void addBean(O bean) {
188
189
190 Preconditions.checkNotNull(bean);
191
192
193 Preconditions.checkState(!contexts.containsKey(bean),
194 "The bean " + bean +
195 " is already registred in this validator.");
196
197 if (log.isDebugEnabled()) {
198 log.debug(this + " : " + bean);
199 }
200
201
202 NuitonValidator<O> validator = validatorProvider.newValidator(getModel());
203
204
205 NuitonValidatorContext<O> newcontext =
206 new NuitonValidatorContext<O>(bean, validator);
207 newcontext.setValidator(validator);
208 newcontext.setBean(bean);
209
210 contexts.put(bean, newcontext);
211
212 setCanValidate(isCanValidate() && newcontext.isCanValidate());
213
214 try {
215
216 BeanUtil.addPropertyChangeListener(l, bean);
217 } catch (Exception eee) {
218 if (log.isInfoEnabled()) {
219 log.info("Can't register as listener for bean " + bean.getClass() +
220 " for reason " + eee.getMessage(), eee);
221 }
222 }
223 validate(bean);
224
225 setChanged(false);
226 setValid(isValid0());
227 }
228
229 public void addAllBeans(Collection<O> beansToAdd) {
230 for (O bean : beansToAdd) {
231 addBean(bean);
232 }
233 }
234
235
236
237
238
239
240
241
242
243 public void removeBean(O bean) {
244
245
246 Preconditions.checkNotNull(bean);
247
248 if (log.isDebugEnabled()) {
249 log.debug(this + " : " + bean);
250 }
251
252
253 NuitonValidatorContext<O> context = getContext(bean);
254
255 mergeMessages(context, null);
256
257 contexts.remove(bean);
258
259 try {
260 BeanUtil.removePropertyChangeListener(l, bean);
261 } catch (Exception eee) {
262 if (log.isInfoEnabled()) {
263 log.info("Can't unregister as listener for bean " + bean.getClass() +
264 " for reason " + eee.getMessage(), eee);
265 }
266 }
267 }
268
269
270
271
272
273
274
275
276
277 public void removeAllBeans(Collection<O> beansToRemove) {
278 for (O bean : beansToRemove) {
279 removeBean(bean);
280 }
281 }
282
283
284
285
286
287 public void removeAllBeans() {
288 Set<O> beansToRemove = getBeans();
289 removeAllBeans(beansToRemove);
290 }
291
292 @Override
293 public boolean hasFatalErrors() {
294 boolean result = false;
295 for (NuitonValidatorContext<O> context : contexts.values()) {
296 result = context.hasFatalErrors();
297 if (result) {
298 break;
299 }
300 }
301 return result;
302 }
303
304 @Override
305 public boolean hasErrors() {
306 boolean result = false;
307 for (NuitonValidatorContext<O> context : contexts.values()) {
308 result = context.hasErrors();
309 if (result) {
310 break;
311 }
312 }
313 return result;
314 }
315
316 @Override
317 public boolean hasWarnings() {
318 boolean result = false;
319 for (NuitonValidatorContext<O> context : contexts.values()) {
320 result = context.hasWarnings();
321 if (result) {
322 break;
323 }
324 }
325 return result;
326 }
327
328 @Override
329 public boolean hasInfos() {
330 boolean result = false;
331 for (NuitonValidatorContext<O> context : contexts.values()) {
332 result = context.hasInfos();
333 if (result) {
334 break;
335 }
336 }
337 return result;
338 }
339
340 @Override
341 public boolean isValid(String fieldName) {
342 boolean result = true;
343
344 for (NuitonValidatorContext<O> context : contexts.values()) {
345 result = context.isValid(fieldName);
346 if (!result) {
347 break;
348 }
349 }
350 return result;
351 }
352
353 @Override
354 public NuitonValidatorScope getHighestScope(String field) {
355 Set<NuitonValidatorScope> scopes = Sets.newHashSet();
356 for (NuitonValidatorContext<O> context : contexts.values()) {
357 scopes.add(context.getHighestScope(field));
358 }
359 NuitonValidatorScope scope = null;
360 if (scopes.isEmpty()) {
361 List<NuitonValidatorScope> scopeList = Lists.newArrayList(scopes);
362 Collections.sort(scopeList);
363 scope = scopeList.get(0);
364 }
365 return scope;
366 }
367
368 @Override
369 public void doValidate() {
370 validate();
371 setValid(isValid0());
372 setChanged(true);
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386 @Override
387 public <T> T convert(O bean,
388 String fieldName,
389 String value,
390 Class<T> valueClass) {
391 NuitonValidatorContext<O> context = getContext(bean);
392 T convert = null;
393 try {
394 convert = context.convert(fieldName, value, valueClass);
395 } catch (ConversionException e) {
396
397 validate();
398 }
399 return convert;
400 }
401
402 public void addBeanListValidatorListener(BeanListValidatorListener listener) {
403 listenerList.add(BeanListValidatorListener.class, listener);
404 }
405
406 public void removeBeanListValidatorListener(BeanListValidatorListener listener) {
407 listenerList.remove(BeanListValidatorListener.class, listener);
408 }
409
410 public BeanListValidatorListener[] getBeanListValidatorListeners() {
411 return listenerList.getListeners(BeanListValidatorListener.class);
412 }
413
414 public Set<O> getBeans() {
415 return ImmutableSet.copyOf(contexts.keySet());
416 }
417
418 @Override
419 protected void doValidate(O bean) {
420 validate(bean);
421 setValid(isValid0());
422 setChanged(true);
423 }
424
425 @Override
426 protected NuitonValidator<O> getDelegate() {
427 return delegate;
428 }
429
430 @Override
431 protected void rebuildDelegateValidator(Class<O> beanType,
432 String context,
433 NuitonValidatorScope... scopes) {
434
435
436
437
438
439
440
441
442
443
444 if (scopes == null || scopes.length == 0) {
445 scopes = NuitonValidatorScope.values();
446 }
447
448
449 NuitonValidatorModel<O> model = validatorProvider.getModel(beanType,
450 context,
451 scopes
452 );
453
454
455 delegate = validatorProvider.newValidator(model);
456 }
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471 protected void validate() {
472
473
474
475 if (isCanValidate()) {
476
477 for (O bean : contexts.keySet()) {
478
479 validate(bean);
480 }
481 }
482 }
483
484 protected void validate(O bean) {
485 NuitonValidatorContext<O> validator = getContext(bean);
486 NuitonValidatorResult result = validator.validate();
487 mergeMessages(validator, result);
488 }
489
490 protected boolean isValid0() {
491 boolean result = true;
492 for (NuitonValidatorContext<O> context : contexts.values()) {
493 result = context.isValid();
494 if (!result) {
495 break;
496 }
497 }
498 return result;
499 }
500
501 protected void mergeMessages(NuitonValidatorContext<O> context,
502 NuitonValidatorResult newMessages) {
503
504 List<BeanListValidatorEvent> events = context.mergeMessages(
505 this, newMessages);
506
507 if (CollectionUtils.isNotEmpty(events)) {
508
509
510 for (BeanListValidatorEvent event : events) {
511 fireFieldChanged(event);
512 }
513 }
514 }
515
516 protected void fireFieldChanged(BeanListValidatorEvent evt) {
517
518 for (BeanListValidatorListener listener :
519 listenerList.getListeners(BeanListValidatorListener.class)) {
520 listener.onFieldChanged(evt);
521 }
522 }
523
524 public NuitonValidatorContext<O> getContext(O bean) {
525 NuitonValidatorContext<O> context = contexts.get(bean);
526 Preconditions.checkState(
527 context != null,
528 "Bean " + bean + " was not register in this list validator");
529 return context;
530 }
531
532
533 public static class NuitonValidatorContext<O> extends AbstractNuitonValidatorContext<O, BeanListValidator<O>, BeanListValidatorEvent> {
534
535 public NuitonValidatorContext(O bean, NuitonValidator<O> validator) {
536 setValidator(validator);
537 setBean(bean);
538 }
539
540 @Override
541 protected BeanListValidatorEvent createEvent(BeanListValidator<O> source,
542 O bean,
543 String field,
544 NuitonValidatorScope scope,
545 String[] toAdd,
546 String[] toDelete) {
547 return new BeanListValidatorEvent(
548 source,
549 bean,
550 field,
551 scope,
552 toAdd,
553 toDelete
554 );
555 }
556 }
557 }