1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
package org.kuali.student.common.validator.old; |
17 | |
|
18 | |
import java.util.ArrayList; |
19 | |
import java.util.Collection; |
20 | |
import java.util.Date; |
21 | |
import java.util.HashMap; |
22 | |
import java.util.Iterator; |
23 | |
import java.util.List; |
24 | |
import java.util.Map; |
25 | |
import java.util.Stack; |
26 | |
|
27 | |
import org.kuali.student.common.util.MessageUtils; |
28 | |
import org.kuali.student.core.dictionary.old.dto.CaseConstraint; |
29 | |
import org.kuali.student.core.dictionary.old.dto.ConstraintDescriptor; |
30 | |
import org.kuali.student.core.dictionary.old.dto.ConstraintSelector; |
31 | |
import org.kuali.student.core.dictionary.old.dto.Field; |
32 | |
import org.kuali.student.core.dictionary.old.dto.LookupConstraint; |
33 | |
import org.kuali.student.core.dictionary.old.dto.ObjectStructure; |
34 | |
import org.kuali.student.core.dictionary.old.dto.OccursConstraint; |
35 | |
import org.kuali.student.core.dictionary.old.dto.RequireConstraint; |
36 | |
import org.kuali.student.core.dictionary.old.dto.State; |
37 | |
import org.kuali.student.core.dictionary.old.dto.Type; |
38 | |
import org.kuali.student.core.dictionary.old.dto.TypeStateCaseConstraint; |
39 | |
import org.kuali.student.core.dictionary.old.dto.ValidCharsConstraint; |
40 | |
import org.kuali.student.core.dictionary.old.dto.WhenConstraint; |
41 | |
import org.kuali.student.core.messages.dto.Message; |
42 | |
import org.kuali.student.core.messages.service.MessageService; |
43 | |
import org.kuali.student.core.validation.dto.ValidationResultInfo; |
44 | |
|
45 | 41 | public class Validator { |
46 | |
|
47 | |
|
48 | |
private static final String DEFAULT_STATE = "*"; |
49 | |
|
50 | 1 | private static final String UNBOUNDED_CHECK = null; |
51 | |
|
52 | 9 | private MessageService messageService = null; |
53 | |
|
54 | 9 | private String messageLocaleKey = "en"; |
55 | |
|
56 | 9 | private String messageGroupKey = "validation"; |
57 | |
|
58 | 9 | private DateParser dateParser = new ServerDateParser(); |
59 | |
|
60 | 9 | private boolean serverSide = true; |
61 | |
|
62 | |
public MessageService getMessageService() { |
63 | 0 | return messageService; |
64 | |
} |
65 | |
|
66 | |
public void setMessageService(MessageService messageService) { |
67 | 9 | this.messageService = messageService; |
68 | 9 | } |
69 | |
|
70 | |
public String getMessageLocaleKey() { |
71 | 0 | return messageLocaleKey; |
72 | |
} |
73 | |
|
74 | |
public void setMessageLocaleKey(String messageLocaleKey) { |
75 | 0 | this.messageLocaleKey = messageLocaleKey; |
76 | 0 | } |
77 | |
|
78 | |
public String getMessageGroupKey() { |
79 | 0 | return messageGroupKey; |
80 | |
} |
81 | |
|
82 | |
public void setMessageGroupKey(String messageGroupKey) { |
83 | 0 | this.messageGroupKey = messageGroupKey; |
84 | 0 | } |
85 | |
|
86 | |
public void setDateParser(DateParser dateParser) { |
87 | 9 | this.dateParser = dateParser; |
88 | 9 | } |
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
public boolean isServerSide() { |
94 | 0 | return serverSide; |
95 | |
} |
96 | |
|
97 | |
|
98 | |
|
99 | |
|
100 | |
|
101 | |
public void setServerSide(boolean serverSide) { |
102 | 0 | this.serverSide = serverSide; |
103 | 0 | } |
104 | |
|
105 | |
|
106 | |
|
107 | |
|
108 | |
public DateParser getDateParser() { |
109 | 0 | return dateParser; |
110 | |
} |
111 | |
|
112 | |
|
113 | |
|
114 | |
|
115 | |
|
116 | |
|
117 | |
|
118 | |
|
119 | |
|
120 | |
|
121 | |
|
122 | |
public List<ValidationResultInfo> validateTypeStateObject(Object data, |
123 | |
ObjectStructure objStructure) { |
124 | |
|
125 | 9 | Stack<String> elementStack = new Stack<String>(); |
126 | 9 | return validateTypeStateObject(data, objStructure, elementStack); |
127 | |
} |
128 | |
|
129 | |
private List<ValidationResultInfo> validateTypeStateObject(Object data, |
130 | |
ObjectStructure objStructure, Stack<String> elementStack) { |
131 | |
|
132 | 10 | List<ValidationResultInfo> results = new ArrayList<ValidationResultInfo>(); |
133 | |
|
134 | 10 | ConstraintDataProvider dataProvider = new BeanConstraintDataProvider(); |
135 | 10 | dataProvider.initialize(data); |
136 | |
|
137 | 10 | boolean isTypeStateObject = (dataProvider.hasField("type") && dataProvider |
138 | |
.hasField("state")); |
139 | |
|
140 | |
|
141 | 10 | StringBuilder objXPathElement = new StringBuilder(dataProvider |
142 | |
.getPath()); |
143 | 10 | if (null != dataProvider.getObjectId()) { |
144 | 10 | objXPathElement.append("[id='" + dataProvider.getObjectId() + "']"); |
145 | |
} else { |
146 | 0 | objXPathElement.append("[id='null']"); |
147 | |
} |
148 | 10 | elementStack.push(objXPathElement.toString()); |
149 | |
|
150 | |
|
151 | |
|
152 | |
|
153 | |
|
154 | 10 | if (!isTypeStateObject || null == objStructure) { |
155 | 0 | return results; |
156 | |
} |
157 | |
|
158 | |
|
159 | 10 | List<Type> types = objStructure.getType(); |
160 | 10 | for (Type t : types) { |
161 | 10 | if (t.getKey().equalsIgnoreCase( |
162 | |
(String) dataProvider.getValue("type"))) { |
163 | 10 | for (State s : t.getState()) { |
164 | 10 | if (s.getKey().equalsIgnoreCase( |
165 | |
(String) dataProvider.getValue("state")) |
166 | |
|| s.getKey().equalsIgnoreCase(DEFAULT_STATE)) { |
167 | 10 | for (Field f : s.getField()) { |
168 | 35 | List<ValidationResultInfo> l = validateField(f, t, |
169 | |
s, objStructure, dataProvider, elementStack); |
170 | 35 | results.addAll(l); |
171 | 35 | } |
172 | 10 | break; |
173 | |
} |
174 | |
} |
175 | 10 | break; |
176 | |
} |
177 | |
} |
178 | 10 | elementStack.pop(); |
179 | |
|
180 | |
|
181 | |
|
182 | |
|
183 | |
|
184 | |
|
185 | |
|
186 | |
|
187 | |
|
188 | |
|
189 | 10 | return results; |
190 | |
} |
191 | |
|
192 | |
public List<ValidationResultInfo> validateField(Field field, Type type, |
193 | |
State state, ObjectStructure objStruct, |
194 | |
ConstraintDataProvider dataProvider, Stack<String> elementStack) { |
195 | |
|
196 | 35 | Object value = dataProvider.getValue(field.getKey()); |
197 | 35 | List<ValidationResultInfo> results = new ArrayList<ValidationResultInfo>(); |
198 | |
|
199 | 35 | ConstraintDescriptor cd = field.getConstraintDescriptor(); |
200 | |
|
201 | |
|
202 | 35 | if (value == null || "".equals(value.toString().trim())) { |
203 | 19 | if (isNullable(field) == false) { |
204 | 9 | ValidationResultInfo valInfo = new ValidationResultInfo( |
205 | |
getElementXpath(elementStack) + field.getKey()); |
206 | 9 | valInfo.setError(getMessage("validation.required")); |
207 | 9 | results.add(valInfo); |
208 | |
} |
209 | 19 | return results; |
210 | |
} |
211 | |
|
212 | |
|
213 | |
|
214 | |
|
215 | |
|
216 | |
|
217 | |
|
218 | 16 | if ("complex" |
219 | |
.equalsIgnoreCase(field.getFieldDescriptor().getDataType())) { |
220 | 1 | ObjectStructure nestedObjStruct = null; |
221 | |
|
222 | 1 | if(null != field.getFieldDescriptor().getObjectStructure()) { |
223 | 1 | nestedObjStruct = field.getFieldDescriptor() |
224 | |
.getObjectStructure(); |
225 | |
} |
226 | 0 | else if (hasText(field.getFieldDescriptor().getObjectStructureRef())) { |
227 | |
|
228 | |
|
229 | |
|
230 | |
} |
231 | |
|
232 | 1 | BaseConstraintBean bcb = new BaseConstraintBean(); |
233 | 1 | if(null != cd) { |
234 | 0 | for(ConstraintSelector constraint: cd.getConstraint()) { |
235 | 0 | computeBaseConstraints(constraint, bcb, field); |
236 | |
} |
237 | |
} |
238 | |
|
239 | 1 | elementStack.push(field.getKey()); |
240 | |
|
241 | 1 | if (value instanceof Collection<?>) { |
242 | |
|
243 | 1 | String xPath = getElementXpath(elementStack) + "/"; |
244 | |
|
245 | 1 | for (Object o : (Collection<?>) value) { |
246 | 1 | processNestedObjectStructure(results, o, nestedObjStruct, |
247 | |
field, elementStack); |
248 | |
} |
249 | 1 | if (bcb.minOccurs > ((Collection<?>) value).size()) { |
250 | 0 | ValidationResultInfo valRes = new ValidationResultInfo( |
251 | |
xPath); |
252 | 0 | valRes.setError(MessageUtils.interpolate(getMessage("validation.minOccurs"), bcb.toMap())); |
253 | 0 | results.add(valRes); |
254 | |
} |
255 | |
|
256 | 1 | Integer maxOccurs = tryParse(bcb.maxOccurs); |
257 | 1 | if (maxOccurs != null |
258 | |
&& maxOccurs < ((Collection<?>) value).size()) { |
259 | 0 | ValidationResultInfo valRes = new ValidationResultInfo( |
260 | |
xPath); |
261 | 0 | valRes.setError(MessageUtils.interpolate(getMessage("validation.maxOccurs"), bcb.toMap())); |
262 | 0 | results.add(valRes); |
263 | |
} |
264 | 1 | } else { |
265 | 0 | if(null != value) { |
266 | 0 | processNestedObjectStructure(results, value, nestedObjStruct, |
267 | |
field, elementStack); |
268 | |
} else { |
269 | 0 | if (bcb.minOccurs != null && bcb.minOccurs > 0) { |
270 | 0 | ValidationResultInfo val = new ValidationResultInfo( |
271 | |
getElementXpath(elementStack) + "[value='null']/"); |
272 | 0 | val.setError(getMessage("validation.required")); |
273 | 0 | results.add(val); |
274 | |
} |
275 | |
} |
276 | |
} |
277 | |
|
278 | 1 | elementStack.pop(); |
279 | |
|
280 | 1 | } else { |
281 | 15 | if (null != cd) { |
282 | 15 | List<ConstraintSelector> constraints = cd.getConstraint(); |
283 | |
|
284 | 15 | if (value instanceof Collection<?>) { |
285 | 0 | BaseConstraintBean bcb = new BaseConstraintBean(); |
286 | 0 | for (Object o : (Collection<?>) value) { |
287 | 0 | for (ConstraintSelector constraint : constraints) { |
288 | 0 | processConstraint(results, constraint, field, type, |
289 | |
state, objStruct, o, dataProvider, bcb, elementStack); |
290 | |
} |
291 | 0 | processBaseConstraints(results, bcb, field, o, elementStack); |
292 | 0 | if(!bcb.initialized) { |
293 | 0 | bcb.initialized = true; |
294 | |
} |
295 | |
} |
296 | |
|
297 | 0 | String xPath = getElementXpath(elementStack) + field.getKey() + "/"; |
298 | 0 | if (bcb.minOccurs > ((Collection<?>) value).size()) { |
299 | 0 | ValidationResultInfo valRes = new ValidationResultInfo( |
300 | |
xPath); |
301 | 0 | valRes.setError(MessageUtils.interpolate(getMessage("validation.minOccurs"), bcb.toMap())); |
302 | 0 | results.add(valRes); |
303 | |
} |
304 | |
|
305 | 0 | Integer maxOccurs = tryParse(bcb.maxOccurs); |
306 | 0 | if (maxOccurs != null |
307 | |
&& maxOccurs < ((Collection<?>) value).size()) { |
308 | 0 | ValidationResultInfo valRes = new ValidationResultInfo( |
309 | |
xPath); |
310 | 0 | valRes.setError(MessageUtils.interpolate(getMessage("validation.maxOccurs"), bcb.toMap())); |
311 | 0 | results.add(valRes); |
312 | |
} |
313 | 0 | } else { |
314 | 15 | BaseConstraintBean bcb = new BaseConstraintBean(); |
315 | 15 | for (ConstraintSelector constraint : constraints) { |
316 | 24 | processConstraint(results, constraint, field, type, |
317 | |
state, objStruct, value, dataProvider, bcb, elementStack); |
318 | |
} |
319 | 15 | processBaseConstraints(results, bcb, field, value, elementStack); |
320 | |
} |
321 | |
} |
322 | |
} |
323 | 16 | return results; |
324 | |
} |
325 | |
|
326 | |
private boolean isNullable(Field field) { |
327 | 19 | ConstraintDescriptor cd = field.getConstraintDescriptor(); |
328 | 19 | if (null != cd) { |
329 | 19 | List<ConstraintSelector> constraintList = cd.getConstraint(); |
330 | 19 | for (ConstraintSelector cs : constraintList) { |
331 | 19 | if (cs.getMinOccurs() != null && cs.getMinOccurs() > 0) { |
332 | 9 | return false; |
333 | |
} |
334 | |
} |
335 | |
} |
336 | 10 | return true; |
337 | |
} |
338 | |
|
339 | |
private Integer tryParse(String s) { |
340 | 31 | Integer result = null; |
341 | 31 | if (s != null) { |
342 | |
try { |
343 | 18 | result = Integer.valueOf(s); |
344 | 0 | } catch (NumberFormatException e) { |
345 | |
|
346 | 18 | } |
347 | |
} |
348 | 31 | return result; |
349 | |
} |
350 | |
|
351 | |
private void processNestedObjectStructure( |
352 | |
List<ValidationResultInfo> results, Object value, |
353 | |
ObjectStructure nestedObjStruct, Field field, Stack<String> elementStack) { |
354 | |
|
355 | 1 | results.addAll(validateTypeStateObject(value, nestedObjStruct, elementStack)); |
356 | |
|
357 | 1 | ConstraintDescriptor cd = field.getConstraintDescriptor(); |
358 | 1 | if (null != cd) { |
359 | 0 | ConstraintSelector cs = cd.getConstraint().get(0); |
360 | 0 | TypeStateCaseConstraint tscs = cs.getTypeStateCaseConstraint(); |
361 | 0 | if (null != tscs) { |
362 | |
|
363 | |
|
364 | |
|
365 | |
|
366 | |
} |
367 | |
} |
368 | 1 | } |
369 | |
|
370 | |
private void computeBaseConstraints(ConstraintSelector constraint, |
371 | |
BaseConstraintBean bcb, Field field) { |
372 | 24 | if (null != constraint.getMinLength()) { |
373 | 10 | bcb.minLength = (bcb.minLength > constraint.getMinLength()) ? bcb.minLength |
374 | |
: constraint.getMinLength(); |
375 | |
} |
376 | |
|
377 | 24 | if (null != constraint.getMinOccurs()) { |
378 | 13 | bcb.minOccurs = (bcb.minOccurs > constraint.getMinOccurs()) ? bcb.minOccurs |
379 | |
: constraint.getMinOccurs(); |
380 | |
} |
381 | |
|
382 | 24 | if (null != constraint.getMinValue()) { |
383 | 4 | bcb.minValue = (null == bcb.minValue || ValidatorUtils |
384 | |
.compareValues(bcb.minValue, constraint.getMinValue(), |
385 | |
field.getFieldDescriptor().getDataType(), |
386 | |
"GREATER_THAN", dateParser)) ? constraint |
387 | |
.getMinValue() : bcb.minValue; |
388 | |
} |
389 | |
|
390 | 24 | if (null != constraint.getMaxValue()) { |
391 | 1 | bcb.maxValue = (null == bcb.maxValue || ValidatorUtils |
392 | |
.compareValues(bcb.maxValue, constraint.getMaxValue(), |
393 | |
field.getFieldDescriptor().getDataType(), |
394 | |
"LESS_THAN", dateParser)) ? constraint |
395 | |
.getMaxValue() : bcb.maxValue; |
396 | |
} |
397 | |
|
398 | 24 | if (hasText(constraint.getMaxLength())) { |
399 | 9 | Integer maxLength = tryParse(bcb.maxLength); |
400 | 9 | Integer constraintMaxLength = tryParse(constraint.getMaxLength()); |
401 | 9 | if (maxLength == null) { |
402 | 9 | bcb.maxLength = constraint.getMaxLength(); |
403 | 0 | } else if (constraintMaxLength != null) { |
404 | 0 | if (constraintMaxLength > maxLength) { |
405 | 0 | bcb.maxLength = constraint.getMaxLength(); |
406 | |
} |
407 | |
} |
408 | |
} |
409 | |
|
410 | 24 | if (hasText(constraint.getMaxOccurs())) { |
411 | 1 | Integer maxOccurs = tryParse(bcb.maxOccurs); |
412 | 1 | Integer constraintMaxOccurs = tryParse(constraint.getMaxOccurs()); |
413 | 1 | if (maxOccurs == null) { |
414 | 1 | bcb.maxOccurs = constraint.getMaxOccurs(); |
415 | 0 | } else if (constraintMaxOccurs != null) { |
416 | 0 | if (constraintMaxOccurs > maxOccurs) { |
417 | 0 | bcb.maxOccurs = constraint.getMaxOccurs(); |
418 | |
} |
419 | |
} |
420 | |
} |
421 | 24 | } |
422 | |
|
423 | |
private void processConstraint(List<ValidationResultInfo> valResults, |
424 | |
ConstraintSelector constraint, Field field, Type type, State state, |
425 | |
ObjectStructure objStructure, Object value, |
426 | |
ConstraintDataProvider dataProvider, BaseConstraintBean bcb, |
427 | |
Stack<String> elementStack) { |
428 | |
|
429 | |
|
430 | 24 | if (hasText(constraint.getClassName()) || constraint.isServerSide() |
431 | |
&& !serverSide) { |
432 | 0 | return; |
433 | |
} |
434 | |
|
435 | 24 | String elementPath = getElementXpath(elementStack) + field.getKey() |
436 | |
+ "[value='" + value.toString() + "']/"; |
437 | |
|
438 | 24 | if(!bcb.initialized) { |
439 | 24 | computeBaseConstraints(constraint, bcb, field); |
440 | |
} |
441 | |
|
442 | |
|
443 | 24 | if (null != constraint.getValidChars()) { |
444 | 9 | ValidationResultInfo val = processValidCharConstraint(elementPath, |
445 | |
constraint.getValidChars(), dataProvider, value); |
446 | 9 | if (null != val) { |
447 | 2 | valResults.add(val); |
448 | |
} |
449 | |
} |
450 | |
|
451 | |
|
452 | 24 | if (value != null && !"".equals(value.toString().trim())) { |
453 | 24 | if (null != constraint.getRequireConstraint() |
454 | |
&& constraint.getRequireConstraint().size() > 0) { |
455 | 1 | for (RequireConstraint rc : constraint.getRequireConstraint()) { |
456 | 1 | ValidationResultInfo val = processRequireConstraint( |
457 | |
elementPath, rc, field, objStructure, dataProvider); |
458 | 1 | if (null != val) { |
459 | 1 | valResults.add(val); |
460 | |
} |
461 | 1 | } |
462 | |
} |
463 | |
} |
464 | |
|
465 | |
|
466 | 24 | if (null != constraint.getOccursConstraint() |
467 | |
&& constraint.getOccursConstraint().size() > 0) { |
468 | 0 | for (OccursConstraint oc : constraint.getOccursConstraint()) { |
469 | 0 | ValidationResultInfo val = processOccursConstraint(elementPath, |
470 | |
oc, field, type, state, objStructure, dataProvider); |
471 | 0 | if (null != val) { |
472 | 0 | valResults.add(val); |
473 | |
} |
474 | 0 | } |
475 | |
} |
476 | |
|
477 | |
|
478 | 24 | if (null != constraint.getLookupConstraint() |
479 | |
&& constraint.getLookupConstraint().size() > 0) { |
480 | 0 | for (LookupConstraint lc : constraint.getLookupConstraint()) { |
481 | 0 | processLookupConstraint(valResults); |
482 | |
} |
483 | |
} |
484 | |
|
485 | |
|
486 | 24 | if (null != constraint.getCaseConstraint() |
487 | |
&& constraint.getCaseConstraint().size() > 0) { |
488 | 0 | for (CaseConstraint cc : constraint.getCaseConstraint()) { |
489 | 0 | processCaseConstraint(valResults, cc, field, type, state, |
490 | |
objStructure, value, dataProvider, bcb, elementStack); |
491 | |
} |
492 | |
} |
493 | 24 | } |
494 | |
|
495 | |
private ValidationResultInfo processRequireConstraint(String element, |
496 | |
RequireConstraint constraint, Field field, |
497 | |
ObjectStructure objStructure, ConstraintDataProvider dataProvider) { |
498 | |
|
499 | 1 | ValidationResultInfo val = null; |
500 | |
|
501 | 1 | String fieldName = constraint.getField(); |
502 | 1 | Object fieldValue = dataProvider.getValue(fieldName); |
503 | |
|
504 | 1 | boolean result = true; |
505 | |
|
506 | 1 | if (fieldValue instanceof java.lang.String) { |
507 | 1 | result = hasText((String) fieldValue); |
508 | 0 | } else if (fieldValue instanceof Collection<?>) { |
509 | 0 | result = (((Collection<?>) fieldValue).size() > 0); |
510 | |
} else { |
511 | 0 | result = (null != fieldValue) ? true : false; |
512 | |
} |
513 | |
|
514 | 1 | if (!result) { |
515 | 1 | Map<String, Object> rMap = new HashMap<String, Object>(); |
516 | 1 | rMap.put("field1", field.getKey()); |
517 | 1 | rMap.put("field2", fieldName); |
518 | 1 | val = new ValidationResultInfo(element); |
519 | 1 | val.setError(MessageUtils.interpolate( |
520 | |
getMessage("validation.requiresField"), rMap)); |
521 | |
} |
522 | |
|
523 | 1 | return val; |
524 | |
} |
525 | |
|
526 | |
|
527 | |
|
528 | |
|
529 | |
|
530 | |
|
531 | |
|
532 | |
|
533 | |
|
534 | |
private void processCaseConstraint(List<ValidationResultInfo> valResults, |
535 | |
CaseConstraint constraint, Field field, Type type, State state, |
536 | |
ObjectStructure objStructure, Object value, |
537 | |
ConstraintDataProvider dataProvider, BaseConstraintBean bcb, |
538 | |
Stack<String> elementStack) { |
539 | |
|
540 | 0 | String operator = (hasText(constraint.getOperator())) ? constraint |
541 | |
.getOperator() : "EQUALS"; |
542 | 0 | Field caseField = (hasText(constraint.getField())) ? ValidatorUtils |
543 | |
.getField(constraint.getField(), objStructure, type.getKey(), |
544 | |
state.getKey()) : null; |
545 | |
|
546 | |
|
547 | 0 | Object fieldValue = (null != caseField) ? dataProvider |
548 | |
.getValue(caseField.getKey()) : value; |
549 | |
|
550 | |
|
551 | 0 | for (WhenConstraint wc : constraint.getWhenConstraint()) { |
552 | 0 | String whenValue = wc.getValue(); |
553 | |
|
554 | 0 | if (ValidatorUtils.compareValues(fieldValue, whenValue, caseField |
555 | |
.getFieldDescriptor().getDataType(), operator, dateParser)) { |
556 | 0 | processConstraint(valResults, wc.getConstraint(), field, type, |
557 | |
state, objStructure, value, dataProvider, bcb, |
558 | |
elementStack); |
559 | |
} |
560 | 0 | } |
561 | 0 | } |
562 | |
|
563 | |
private ValidationResultInfo processValidCharConstraint(String element, |
564 | |
ValidCharsConstraint vcConstraint, |
565 | |
ConstraintDataProvider dataProvider, Object value) { |
566 | |
|
567 | 9 | ValidationResultInfo val = null; |
568 | |
|
569 | 9 | StringBuilder fieldValue = new StringBuilder(); |
570 | 9 | String validChars = vcConstraint.getValue(); |
571 | 9 | String fields = vcConstraint.getFields(); |
572 | |
|
573 | 9 | if (hasText(fields)) { |
574 | 0 | String separator = vcConstraint.getSeparator(); |
575 | 0 | String[] fieldNameList = fields.split(","); |
576 | |
|
577 | 0 | int sz = fieldNameList.length; |
578 | |
|
579 | 0 | for (String fieldName : fieldNameList) { |
580 | 0 | Object v = dataProvider.getValue(fieldName); |
581 | 0 | fieldValue.append(ValidatorUtils.getString(v)); |
582 | |
|
583 | 0 | if (--sz > 0) { |
584 | 0 | fieldValue.append(separator); |
585 | |
} |
586 | |
} |
587 | 0 | } else { |
588 | 9 | fieldValue.append(ValidatorUtils.getString(value)); |
589 | |
} |
590 | |
|
591 | 9 | int typIdx = validChars.indexOf(":"); |
592 | 9 | String processorType = "regex"; |
593 | 9 | if (-1 == typIdx) { |
594 | 0 | validChars = "[" + validChars + "]*"; |
595 | |
} else { |
596 | 9 | processorType = validChars.substring(0, typIdx); |
597 | 9 | validChars = validChars.substring(typIdx + 1); |
598 | |
} |
599 | |
|
600 | |
|
601 | 9 | if ("regex".equalsIgnoreCase(processorType)) { |
602 | |
|
603 | 9 | if (fieldValue == null) { |
604 | 0 | val = new ValidationResultInfo(element); |
605 | 0 | val.setError(getMessage("validation.validCharsFailed")); |
606 | 9 | } else if (fieldValue != null |
607 | |
&& !fieldValue.toString().matches(validChars)) { |
608 | 2 | val = new ValidationResultInfo(element); |
609 | 2 | val.setError(getMessage("validation.validCharsFailed")); |
610 | |
} |
611 | |
} |
612 | |
|
613 | 9 | return val; |
614 | |
} |
615 | |
|
616 | |
|
617 | |
|
618 | |
|
619 | |
|
620 | |
|
621 | |
|
622 | |
|
623 | |
|
624 | |
|
625 | |
|
626 | |
|
627 | |
|
628 | |
|
629 | |
private ValidationResultInfo processOccursConstraint(String element, |
630 | |
OccursConstraint constraint, Field field, Type type, State state, |
631 | |
ObjectStructure objStructure, ConstraintDataProvider dataProvider) { |
632 | |
|
633 | 0 | boolean result = false; |
634 | 0 | int trueCount = 0; |
635 | |
|
636 | 0 | ValidationResultInfo val = null; |
637 | |
|
638 | 0 | for (RequireConstraint rc : constraint.getRequire()) { |
639 | 0 | trueCount += (processRequireConstraint("", rc, field, objStructure, |
640 | |
dataProvider) != null) ? 1 : 0; |
641 | |
} |
642 | |
|
643 | 0 | for (OccursConstraint oc : constraint.getOccurs()) { |
644 | 0 | trueCount += (processOccursConstraint("", oc, field, type, state, |
645 | |
objStructure, dataProvider) != null) ? 1 : 0; |
646 | |
} |
647 | |
|
648 | 0 | result = (trueCount >= constraint.getMin() && trueCount <= constraint |
649 | |
.getMax()) ? true : false; |
650 | |
|
651 | 0 | if (!result) { |
652 | 0 | val = new ValidationResultInfo(element); |
653 | 0 | val.setError(getMessage("validation.occurs")); |
654 | |
} |
655 | |
|
656 | 0 | return val; |
657 | |
} |
658 | |
|
659 | |
|
660 | |
private void processLookupConstraint(List<ValidationResultInfo> valResults) { |
661 | 0 | } |
662 | |
|
663 | |
|
664 | |
private void processTypeStateCaseConstraint( |
665 | |
List<ValidationResultInfo> valResults) { |
666 | 0 | } |
667 | |
|
668 | |
private void processBaseConstraints(List<ValidationResultInfo> valResults, |
669 | |
BaseConstraintBean bcb, Field field, Object value, |
670 | |
Stack<String> elementStack) { |
671 | |
|
672 | 15 | String dataType = field.getFieldDescriptor().getDataType(); |
673 | |
|
674 | 15 | if (value == null || "".equals(value.toString().trim())) { |
675 | 0 | if (bcb.minOccurs != null && bcb.minOccurs > 0) { |
676 | 0 | ValidationResultInfo val = new ValidationResultInfo( |
677 | |
getElementXpath(elementStack) + field.getKey() |
678 | |
+ "[value='null']/"); |
679 | 0 | val.setError(getMessage("validation.required")); |
680 | 0 | valResults.add(val); |
681 | 0 | return; |
682 | |
} |
683 | |
} |
684 | |
|
685 | 15 | String elementPath = getElementXpath(elementStack) + field.getKey() |
686 | |
+ "[value='" + value.toString() + "']/"; |
687 | |
|
688 | 15 | if ("string".equalsIgnoreCase(dataType)) { |
689 | 10 | validateString(value, bcb, elementPath, valResults); |
690 | 5 | } else if ("integer".equalsIgnoreCase(dataType)) { |
691 | 1 | validateInteger(value, bcb, elementPath, valResults); |
692 | 4 | } else if ("long".equalsIgnoreCase(dataType)) { |
693 | 0 | validateLong(value, bcb, elementPath, valResults); |
694 | 4 | } else if ("double".equalsIgnoreCase(dataType)) { |
695 | 1 | validateDouble(value, bcb, elementPath, valResults); |
696 | 3 | } else if ("float".equalsIgnoreCase(dataType)) { |
697 | 0 | validateFloat(value, bcb, elementPath, valResults); |
698 | 3 | } else if ("boolean".equalsIgnoreCase(dataType)) { |
699 | 0 | validateBoolean(value, bcb, elementPath, valResults); |
700 | 3 | } else if ("date".equalsIgnoreCase(dataType)) { |
701 | 3 | validateDate(value, bcb, elementPath, valResults, dateParser); |
702 | |
} |
703 | 15 | } |
704 | |
|
705 | |
private void validateBoolean(Object value, BaseConstraintBean bcb, |
706 | |
String element, List<ValidationResultInfo> results) { |
707 | 0 | if (!(value instanceof Boolean)) { |
708 | |
try { |
709 | 0 | Boolean.valueOf(value.toString()); |
710 | 0 | } catch (Exception e) { |
711 | 0 | ValidationResultInfo val = new ValidationResultInfo(element); |
712 | 0 | val.setError(getMessage("validation.mustBeBoolean")); |
713 | 0 | results.add(val); |
714 | 0 | } |
715 | |
} |
716 | 0 | } |
717 | |
|
718 | |
private void validateDouble(Object value, BaseConstraintBean bcb, |
719 | |
String element, List<ValidationResultInfo> results) { |
720 | 1 | Double v = null; |
721 | |
|
722 | 1 | ValidationResultInfo val = new ValidationResultInfo(element); |
723 | |
|
724 | 1 | if (value instanceof Number) { |
725 | 1 | v = ((Number) value).doubleValue(); |
726 | |
} else { |
727 | |
try { |
728 | 0 | v = Double.valueOf(value.toString()); |
729 | 0 | } catch (Exception e) { |
730 | 0 | val.setError(getMessage("validation.mustBeDouble")); |
731 | 0 | } |
732 | |
} |
733 | |
|
734 | 1 | if (val.isOk()) { |
735 | 1 | Double maxValue = ValidatorUtils.getDouble(bcb.maxValue); |
736 | 1 | Double minValue = ValidatorUtils.getDouble(bcb.minValue); |
737 | |
|
738 | 1 | if (maxValue != null && minValue != null) { |
739 | |
|
740 | 1 | if (v > maxValue || v < minValue) { |
741 | 1 | val.setError(MessageUtils.interpolate( |
742 | |
getMessage("validation.outOfRange"), bcb.toMap())); |
743 | |
} |
744 | 0 | } else if (maxValue != null) { |
745 | 0 | if (v > maxValue) { |
746 | 0 | val.setError(MessageUtils.interpolate( |
747 | |
getMessage("validation.maxValueFailed"), bcb |
748 | |
.toMap())); |
749 | |
} |
750 | 0 | } else if (minValue != null) { |
751 | 0 | if (v < minValue) { |
752 | 0 | val.setError(MessageUtils.interpolate( |
753 | |
getMessage("validation.minValueFailed"), bcb |
754 | |
.toMap())); |
755 | |
} |
756 | |
} |
757 | |
} |
758 | |
|
759 | 1 | if (!val.isOk()) { |
760 | 1 | results.add(val); |
761 | |
} |
762 | 1 | } |
763 | |
|
764 | |
private void validateFloat(Object value, BaseConstraintBean bcb, |
765 | |
String element, List<ValidationResultInfo> results) { |
766 | 0 | Float v = null; |
767 | |
|
768 | 0 | ValidationResultInfo val = new ValidationResultInfo(element); |
769 | 0 | if (value instanceof Number) { |
770 | 0 | v = ((Number) value).floatValue(); |
771 | |
} else { |
772 | |
try { |
773 | 0 | v = Float.valueOf(value.toString()); |
774 | 0 | } catch (Exception e) { |
775 | 0 | val.setError(getMessage("validation.mustBeFloat")); |
776 | 0 | } |
777 | |
} |
778 | |
|
779 | 0 | if (val.isOk()) { |
780 | 0 | Float maxValue = ValidatorUtils.getFloat(bcb.maxValue); |
781 | 0 | Float minValue = ValidatorUtils.getFloat(bcb.minValue); |
782 | |
|
783 | 0 | if (maxValue != null && minValue != null) { |
784 | |
|
785 | 0 | if (v > maxValue || v < minValue) { |
786 | 0 | val.setError(MessageUtils.interpolate( |
787 | |
getMessage("validation.outOfRange"), bcb.toMap())); |
788 | |
} |
789 | 0 | } else if (maxValue != null) { |
790 | 0 | if (v > maxValue) { |
791 | 0 | val.setError(MessageUtils.interpolate( |
792 | |
getMessage("validation.maxValueFailed"), bcb |
793 | |
.toMap())); |
794 | |
} |
795 | 0 | } else if (minValue != null) { |
796 | 0 | if (v < minValue) { |
797 | 0 | val.setError(MessageUtils.interpolate( |
798 | |
getMessage("validation.minValueFailed"), bcb |
799 | |
.toMap())); |
800 | |
} |
801 | |
} |
802 | |
} |
803 | |
|
804 | 0 | if (!val.isOk()) { |
805 | 0 | results.add(val); |
806 | |
} |
807 | 0 | } |
808 | |
|
809 | |
private void validateLong(Object value, BaseConstraintBean bcb, |
810 | |
String element, List<ValidationResultInfo> results) { |
811 | 0 | Long v = null; |
812 | |
|
813 | 0 | ValidationResultInfo val = new ValidationResultInfo(element); |
814 | 0 | if (value instanceof Number) { |
815 | 0 | v = ((Number) value).longValue(); |
816 | |
} else { |
817 | |
try { |
818 | 0 | v = Long.valueOf(value.toString()); |
819 | 0 | } catch (Exception e) { |
820 | 0 | val.setError(getMessage("validation.mustBeLong")); |
821 | 0 | } |
822 | |
} |
823 | |
|
824 | 0 | if (val.isOk()) { |
825 | 0 | Long maxValue = ValidatorUtils.getLong(bcb.maxValue); |
826 | 0 | Long minValue = ValidatorUtils.getLong(bcb.minValue); |
827 | |
|
828 | 0 | if (maxValue != null && minValue != null) { |
829 | |
|
830 | 0 | if (v > maxValue || v < minValue) { |
831 | 0 | val.setError(MessageUtils.interpolate( |
832 | |
getMessage("validation.outOfRange"), bcb.toMap())); |
833 | |
} |
834 | 0 | } else if (maxValue != null) { |
835 | 0 | if (v > maxValue) { |
836 | 0 | val.setError(MessageUtils.interpolate( |
837 | |
getMessage("validation.maxValueFailed"), bcb |
838 | |
.toMap())); |
839 | |
} |
840 | 0 | } else if (minValue != null) { |
841 | 0 | if (v < minValue) { |
842 | 0 | val.setError(MessageUtils.interpolate( |
843 | |
getMessage("validation.minValueFailed"), bcb |
844 | |
.toMap())); |
845 | |
} |
846 | |
} |
847 | |
} |
848 | |
|
849 | 0 | if (!val.isOk()) { |
850 | 0 | results.add(val); |
851 | |
} |
852 | |
|
853 | 0 | } |
854 | |
|
855 | |
private void validateInteger(Object value, BaseConstraintBean bcb, |
856 | |
String element, List<ValidationResultInfo> results) { |
857 | 1 | Integer v = null; |
858 | |
|
859 | 1 | ValidationResultInfo val = new ValidationResultInfo(element); |
860 | |
|
861 | 1 | if (value instanceof Number) { |
862 | 0 | v = ((Number) value).intValue(); |
863 | |
} else { |
864 | |
try { |
865 | 1 | v = Integer.valueOf(value.toString()); |
866 | 1 | } catch (Exception e) { |
867 | 1 | val.setError(getMessage("validation.mustBeInteger")); |
868 | 0 | } |
869 | |
} |
870 | |
|
871 | 1 | if (val.isOk()) { |
872 | 0 | Integer maxValue = ValidatorUtils.getInteger(bcb.maxValue); |
873 | 0 | Integer minValue = ValidatorUtils.getInteger(bcb.minValue); |
874 | |
|
875 | 0 | if (maxValue != null && minValue != null) { |
876 | |
|
877 | 0 | if (v > maxValue || v < minValue) { |
878 | 0 | val.setError(MessageUtils.interpolate( |
879 | |
getMessage("validation.outOfRange"), bcb.toMap())); |
880 | |
} |
881 | 0 | } else if (maxValue != null) { |
882 | 0 | if (v > maxValue) { |
883 | 0 | val.setError(MessageUtils.interpolate( |
884 | |
getMessage("validation.maxValueFailed"), bcb |
885 | |
.toMap())); |
886 | |
} |
887 | 0 | } else if (minValue != null) { |
888 | 0 | if (v < minValue) { |
889 | 0 | val.setError(MessageUtils.interpolate( |
890 | |
getMessage("validation.minValueFailed"), bcb |
891 | |
.toMap())); |
892 | |
} |
893 | |
} |
894 | |
} |
895 | |
|
896 | 1 | if (!val.isOk()) { |
897 | 1 | results.add(val); |
898 | |
} |
899 | 1 | } |
900 | |
|
901 | |
private void validateDate(Object value, BaseConstraintBean bcb, |
902 | |
String element, List<ValidationResultInfo> results, |
903 | |
DateParser dateParser) { |
904 | 3 | ValidationResultInfo val = new ValidationResultInfo(element); |
905 | |
|
906 | 3 | Date v = null; |
907 | |
|
908 | 3 | if (value instanceof Date) { |
909 | 3 | v = (Date) value; |
910 | |
} else { |
911 | |
try { |
912 | 0 | v = dateParser.parseDate(value.toString()); |
913 | 0 | } catch (Exception e) { |
914 | 0 | val.setError(getMessage("validation.mustBeDate")); |
915 | 0 | } |
916 | |
} |
917 | |
|
918 | 3 | if (val.isOk()) { |
919 | 3 | Date maxValue = ValidatorUtils.getDate(bcb.maxValue, dateParser); |
920 | 3 | Date minValue = ValidatorUtils.getDate(bcb.minValue, dateParser); |
921 | |
|
922 | 3 | if (maxValue != null && minValue != null) { |
923 | |
|
924 | 0 | if (v.getTime() > maxValue.getTime() |
925 | |
|| v.getTime() < minValue.getTime()) { |
926 | 0 | val.setError(MessageUtils.interpolate( |
927 | |
getMessage("validation.outOfRange"), bcb.toMap())); |
928 | |
} |
929 | 3 | } else if (maxValue != null) { |
930 | 0 | if (v.getTime() > maxValue.getTime()) { |
931 | 0 | val.setError(MessageUtils.interpolate( |
932 | |
getMessage("validation.maxValueFailed"), bcb |
933 | |
.toMap())); |
934 | |
} |
935 | 3 | } else if (minValue != null) { |
936 | 3 | if (v.getTime() < minValue.getTime()) { |
937 | 1 | val.setError(MessageUtils.interpolate( |
938 | |
getMessage("validation.minValueFailed"), bcb |
939 | |
.toMap())); |
940 | |
} |
941 | |
} |
942 | |
} |
943 | |
|
944 | 3 | if (!val.isOk()) { |
945 | 1 | results.add(val); |
946 | |
} |
947 | 3 | } |
948 | |
|
949 | |
private void validateString(Object value, BaseConstraintBean bcb, |
950 | |
String element, List<ValidationResultInfo> results) { |
951 | |
|
952 | 10 | if (value == null) { |
953 | 0 | value = ""; |
954 | |
} |
955 | 10 | String s = value.toString().trim(); |
956 | |
|
957 | 10 | ValidationResultInfo val = new ValidationResultInfo(element); |
958 | |
|
959 | 10 | Integer maxLength = tryParse(bcb.maxLength); |
960 | 10 | if (maxLength != null && bcb.minLength > 0) { |
961 | 7 | if (s.length() > maxLength || s.length() < bcb.minLength) { |
962 | 1 | val |
963 | |
.setError(MessageUtils.interpolate( |
964 | |
getMessage("validation.lengthOutOfRange"), bcb |
965 | |
.toMap())); |
966 | |
} |
967 | 3 | } else if (maxLength != null) { |
968 | 1 | if (s.length() > Integer.parseInt(bcb.maxLength)) { |
969 | 1 | val.setError(MessageUtils.interpolate( |
970 | |
getMessage("validation.maxLengthFailed"), bcb.toMap())); |
971 | |
} |
972 | 2 | } else if (bcb.minLength > 0) { |
973 | 1 | if (s.length() < bcb.minLength) { |
974 | 1 | val.setError(MessageUtils.interpolate( |
975 | |
getMessage("validation.minLengthFailed"), bcb.toMap())); |
976 | |
} |
977 | |
} |
978 | |
|
979 | 10 | if (!val.isOk()) { |
980 | 3 | results.add(val); |
981 | |
} |
982 | 10 | } |
983 | |
|
984 | |
private String getMessage(String messageId) { |
985 | 18 | if (null == messageService) { |
986 | 18 | return messageId; |
987 | |
} |
988 | |
|
989 | 0 | Message msg = messageService.getMessage(messageLocaleKey, |
990 | |
messageGroupKey, messageId); |
991 | |
|
992 | 0 | return msg.getValue(); |
993 | |
} |
994 | |
|
995 | |
private String getElementXpath(Stack<String> elementStack) { |
996 | 49 | StringBuilder xPath = new StringBuilder(); |
997 | 49 | xPath.append("/"); |
998 | 49 | Iterator<String> itr = elementStack.iterator(); |
999 | 107 | while (itr.hasNext()) { |
1000 | 58 | xPath.append(itr.next() + "/"); |
1001 | |
} |
1002 | |
|
1003 | 49 | return xPath.toString(); |
1004 | |
} |
1005 | |
|
1006 | |
|
1007 | |
|
1008 | |
|
1009 | |
private boolean hasText(String string) { |
1010 | |
|
1011 | 82 | if (string == null || string.length() < 1) { |
1012 | 72 | return false; |
1013 | |
} |
1014 | 10 | int stringLength = string.length(); |
1015 | |
|
1016 | 10 | for (int i = 0; i < stringLength; i++) { |
1017 | 10 | char currentChar = string.charAt(i); |
1018 | 10 | if (' ' != currentChar || '\t' != currentChar |
1019 | |
|| '\n' != currentChar) { |
1020 | 10 | return true; |
1021 | |
} |
1022 | |
} |
1023 | |
|
1024 | 0 | return false; |
1025 | |
} |
1026 | |
|
1027 | 32 | private static class BaseConstraintBean { |
1028 | 16 | public boolean initialized = false; |
1029 | 16 | public Integer minOccurs = 0; |
1030 | 16 | public String maxOccurs = UNBOUNDED_CHECK; |
1031 | 16 | public Integer minLength = 0; |
1032 | 16 | public String maxLength = UNBOUNDED_CHECK; |
1033 | 16 | public String dataType = null; |
1034 | 16 | public String minValue = null; |
1035 | 16 | public String maxValue = null; |
1036 | |
|
1037 | |
public Map<String, Object> toMap() { |
1038 | 5 | Map<String, Object> result = new HashMap<String, Object>(); |
1039 | 5 | result.put("minOccurs", minOccurs); |
1040 | 5 | result.put("maxOccurs", maxOccurs); |
1041 | 5 | result.put("minLength", minLength); |
1042 | 5 | result.put("maxLength", maxLength); |
1043 | 5 | result.put("minValue", minValue); |
1044 | 5 | result.put("maxValue", maxValue); |
1045 | 5 | result.put("dataType", dataType); |
1046 | |
|
1047 | 5 | return result; |
1048 | |
} |
1049 | |
} |
1050 | |
} |