1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.datadictionary.validator;
17
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.Map;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.kuali.rice.krad.datadictionary.DataDictionary;
26 import org.kuali.rice.krad.datadictionary.DataDictionaryEntry;
27 import org.kuali.rice.krad.datadictionary.DataDictionaryException;
28 import org.kuali.rice.krad.datadictionary.DefaultListableBeanFactory;
29 import org.kuali.rice.krad.uif.component.Component;
30 import org.kuali.rice.krad.uif.util.ExpressionUtils;
31 import org.kuali.rice.krad.uif.util.UifBeanFactoryPostProcessor;
32 import org.kuali.rice.krad.uif.view.View;
33 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
34 import org.springframework.core.io.FileSystemResource;
35 import org.springframework.core.io.Resource;
36 import org.springframework.core.io.ResourceLoader;
37
38
39
40
41
42
43 public class Validator {
44 private static final Log LOG = LogFactory.getLog(Validator.class);
45
46 private static ArrayList<ErrorReport> errorReports = new ArrayList<ErrorReport>();
47
48 private ValidationTrace tracerTemp;
49 private int numberOfErrors;
50 private int numberOfWarnings;
51
52
53
54
55 public Validator() {
56 tracerTemp = new ValidationTrace();
57 numberOfErrors = 0;
58 numberOfWarnings = 0;
59 }
60
61 public static void addErrorReport(ErrorReport report) {
62 errorReports.add(report);
63 }
64
65 public static void resetErrorReport() {
66 errorReports = new ArrayList<ErrorReport>();
67 }
68
69
70
71
72
73
74
75
76 private boolean runValidations(DefaultListableBeanFactory beans, boolean failOnWarning) {
77 LOG.info("Starting Dictionary Validation");
78 resetErrorReport();
79 Map<String, View> uifBeans;
80
81 try {
82 uifBeans = beans.getBeansOfType(View.class);
83 for (View views : uifBeans.values()) {
84 try {
85 ValidationTrace tracer = tracerTemp.getCopy();
86 if (doValidationOnUIFBean(views)) {
87 tracer.setValidationStage(ValidationTrace.START_UP);
88 runValidationsOnComponents(views, tracer);
89 }
90 } catch (Exception e) {
91 String value[] = {views.getId(), "Exception = " + e.getMessage()};
92 tracerTemp.createError("Error Validating Bean View", value);
93 }
94 }
95 } catch (Exception e) {
96 String value[] = {"Validation set = views", "Exception = " + e.getMessage()};
97 tracerTemp.createError("Error in Loading Spring Beans", value);
98 }
99
100 Map<String, DataDictionaryEntry> ddBeans;
101
102 try {
103 ddBeans = beans.getBeansOfType(DataDictionaryEntry.class);
104 for (DataDictionaryEntry entry : ddBeans.values()) {
105 try {
106
107 ValidationTrace tracer = tracerTemp.getCopy();
108 tracer.setValidationStage(ValidationTrace.BUILD);
109 entry.completeValidation(tracer);
110
111 } catch (Exception e) {
112 String value[] = {"Validation set = Data Dictionary Entries", "Exception = " + e.getMessage()};
113 tracerTemp.createError("Error in Loading Spring Beans", value);
114 }
115 }
116 } catch (Exception e) {
117 String value[] = {"Validation set = Data Dictionary Entries", "Exception = " + e.getMessage()};
118 tracerTemp.createError("Error in Loading Spring Beans", value);
119 }
120
121 compileFinalReport();
122
123 LOG.info("Completed Dictionary Validation");
124
125 if (numberOfErrors > 0) {
126 return false;
127 }
128 if (failOnWarning) {
129 if (numberOfWarnings > 0) {
130 return false;
131 }
132 }
133
134 return true;
135 }
136
137
138
139
140
141
142
143
144 public boolean validate(Component object, boolean failOnWarning) {
145 LOG.info("Starting Dictionary Validation");
146
147 if (doValidationOnUIFBean(object)) {
148 ValidationTrace tracer = tracerTemp.getCopy();
149 resetErrorReport();
150
151 tracer.setValidationStage(ValidationTrace.BUILD);
152
153 LOG.debug("Validating Component: " + object.getId());
154 object.completeValidation(tracer.getCopy());
155
156 runValidationsOnLifecycle(object, tracer.getCopy());
157
158 runValidationsOnPrototype(object, tracer.getCopy());
159 }
160
161 compileFinalReport();
162
163 LOG.info("Completed Dictionary Validation");
164
165 if (numberOfErrors > 0) {
166 return false;
167 }
168 if (failOnWarning) {
169 if (numberOfWarnings > 0) {
170 return false;
171 }
172 }
173
174 return true;
175 }
176
177
178
179
180
181
182
183 public boolean validate(String[] xmlFiles, boolean failOnWarning) {
184 DefaultListableBeanFactory beans = loadBeans(xmlFiles);
185
186 return runValidations(beans, failOnWarning);
187 }
188
189
190
191
192
193
194
195
196
197
198 public boolean validate(String xmlFiles[], ResourceLoader loader, DefaultListableBeanFactory beans,
199 boolean failOnWarning) {
200 tracerTemp = new ValidationTrace(xmlFiles, loader);
201 return runValidations(beans, failOnWarning);
202 }
203
204
205
206
207
208
209
210 private void runValidationsOnComponents(Component component, ValidationTrace tracer) {
211
212 try {
213 ExpressionUtils.populatePropertyExpressionsFromGraph(component, false);
214 } catch (Exception e) {
215 String value[] = {"view = " + component.getId()};
216 tracerTemp.createError("Error Validating Bean View while loading expressions", value);
217 }
218
219 LOG.debug("Validating View: " + component.getId());
220
221 try {
222 component.completeValidation(tracer.getCopy());
223 } catch (Exception e) {
224 String value[] = {component.getId()};
225 tracerTemp.createError("Error Validating Bean View", value);
226 }
227
228 try {
229 runValidationsOnLifecycle(component, tracer.getCopy());
230 } catch (Exception e) {
231 String value[] = {component.getId(), component.getComponentsForLifecycle().size() + "",
232 "Exception " + e.getMessage()};
233 tracerTemp.createError("Error Validating Bean Lifecycle", value);
234 }
235
236 try {
237 runValidationsOnPrototype(component, tracer.getCopy());
238 } catch (Exception e) {
239 String value[] = {component.getId(), component.getComponentPrototypes().size() + "",
240 "Exceptions : " + e.getLocalizedMessage()};
241 tracerTemp.createError("Error Validating Bean Prototypes", value);
242 }
243 }
244
245
246
247
248
249
250
251 private void runValidationsOnLifecycle(Component component, ValidationTrace tracer) {
252 List<Component> nestedComponents = component.getComponentsForLifecycle();
253 if (nestedComponents == null) {
254 return;
255 }
256 if (!doValidationOnUIFBean(component)) {
257 return;
258 }
259 tracer.addBean(component);
260 for (Component temp : nestedComponents) {
261 if (temp == null) {
262 continue;
263 }
264 if (tracer.getValidationStage() == ValidationTrace.START_UP) {
265 ExpressionUtils.populatePropertyExpressionsFromGraph(temp, false);
266 }
267 if (temp.isRender()) {
268 temp.completeValidation(tracer.getCopy());
269 runValidationsOnLifecycle(temp, tracer.getCopy());
270 }
271 }
272 }
273
274
275
276
277
278
279
280 private void runValidationsOnPrototype(Component component, ValidationTrace tracer) {
281 List<Component> componentPrototypes = component.getComponentPrototypes();
282 if (componentPrototypes == null) {
283 return;
284 }
285 if (!doValidationOnUIFBean(component)) {
286 return;
287 }
288 tracer.addBean(component);
289 for (Component temp : componentPrototypes) {
290 if (temp == null) {
291 continue;
292 }
293 if (tracer.getValidationStage() == ValidationTrace.START_UP) {
294 ExpressionUtils.populatePropertyExpressionsFromGraph(temp, false);
295 }
296 if (temp.isRender()) {
297 temp.completeValidation(tracer.getCopy());
298 runValidationsOnPrototype(temp, tracer.getCopy());
299 }
300 }
301 }
302
303
304
305
306
307
308
309 private boolean doValidationOnUIFBean(Component component) {
310 if (component.getId() == null) {
311 return true;
312 }
313 if (component.getId().length() < 3) {
314 return true;
315 }
316 String temp = component.getId().substring(0, 3).toLowerCase();
317 if (temp.contains("uif")) {
318 return false;
319 }
320 return true;
321 }
322
323
324
325
326
327
328
329 public static boolean validateSpringEL(String expression) {
330 if (expression == null) {
331 return true;
332 }
333 if (expression.compareTo("") == 0) {
334 return true;
335 }
336 if (expression.length() <= 3) {
337 return false;
338 }
339
340 if (!expression.substring(0, 1).contains("@") || !expression.substring(1, 2).contains("{") ||
341 !expression.substring(expression.length() - 1, expression.length()).contains("}")) {
342 return false;
343 }
344
345 expression = expression.substring(2, expression.length() - 2);
346
347 ArrayList<String> values = getExpressionValues(expression);
348
349 for (int i = 0; i < values.size(); i++) {
350 checkPropertyName(values.get(i));
351 }
352
353 return true;
354 }
355
356
357
358
359
360
361
362 private static ArrayList<String> getExpressionValues(String expression) {
363 expression = StringUtils.replace(expression, "!=", " != ");
364 expression = StringUtils.replace(expression, "==", " == ");
365 expression = StringUtils.replace(expression, ">", " > ");
366 expression = StringUtils.replace(expression, "<", " < ");
367 expression = StringUtils.replace(expression, "<=", " <= ");
368 expression = StringUtils.replace(expression, ">=", " >= ");
369
370 String stack = "";
371 ArrayList<String> controlNames = new ArrayList<String>();
372
373 boolean expectingSingleQuote = false;
374 boolean ignoreNext = false;
375 for (int i = 0; i < expression.length(); i++) {
376 char c = expression.charAt(i);
377 if (!expectingSingleQuote && !ignoreNext && (c == '(' || c == ' ' || c == ')')) {
378 ExpressionUtils.evaluateCurrentStack(stack.trim(), controlNames);
379
380 stack = "";
381 continue;
382 } else if (!ignoreNext && c == '\'') {
383 stack = stack + c;
384 expectingSingleQuote = !expectingSingleQuote;
385 } else if (c == '\\') {
386 stack = stack + c;
387 ignoreNext = !ignoreNext;
388 } else {
389 stack = stack + c;
390 ignoreNext = false;
391 }
392 }
393
394 if (StringUtils.isNotEmpty(stack)) {
395 ExpressionUtils.evaluateCurrentStack(stack.trim(), controlNames);
396 }
397
398 return controlNames;
399 }
400
401
402
403
404
405
406
407 private static boolean checkPropertyName(String name) {
408 if (!Character.isLetter(name.charAt(0))) {
409 return false;
410 }
411
412 return true;
413 }
414
415
416
417
418
419
420
421
422 public static boolean checkExpressions(Component object, String property) {
423 if (object.getPropertyExpressions().containsKey(property)) {
424 return true;
425 }
426 return false;
427 }
428
429
430
431
432 private void compileFinalReport() {
433 ArrayList<ErrorReport> reports = Validator.errorReports;
434 for (int i = 0; i < reports.size(); i++) {
435 if (reports.get(i).getErrorStatus() == ErrorReport.ERROR) {
436 numberOfErrors++;
437 } else if (reports.get(i).getErrorStatus() == ErrorReport.WARNING) {
438 numberOfWarnings++;
439 }
440 }
441 }
442
443
444
445
446
447
448
449 public DefaultListableBeanFactory loadBeans(String[] xmlFiles) {
450
451 LOG.info("Starting XML File Load");
452 DefaultListableBeanFactory beans = new DefaultListableBeanFactory();
453 XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(beans);
454
455 DataDictionary.setupProcessor(beans);
456
457 ArrayList<String> coreFiles = new ArrayList<String>();
458 ArrayList<String> testFiles = new ArrayList<String>();
459
460 for (int i = 0; i < xmlFiles.length; i++) {
461 if (xmlFiles[i].contains("classpath")) {
462 coreFiles.add(xmlFiles[i]);
463 } else {
464 testFiles.add(xmlFiles[i]);
465 }
466 }
467 String core[] = new String[coreFiles.size()];
468 coreFiles.toArray(core);
469
470 String test[] = new String[testFiles.size()];
471 testFiles.toArray(test);
472
473 try {
474 xmlReader.loadBeanDefinitions(core);
475 } catch (Exception e) {
476 LOG.error("Error loading bean definitions", e);
477 throw new DataDictionaryException("Error loading bean definitions: " + e.getLocalizedMessage());
478 }
479
480 try {
481 xmlReader.loadBeanDefinitions(getResources(test));
482 } catch (Exception e) {
483 LOG.error("Error loading bean definitions", e);
484 throw new DataDictionaryException("Error loading bean definitions: " + e.getLocalizedMessage());
485 }
486
487 UifBeanFactoryPostProcessor factoryPostProcessor = new UifBeanFactoryPostProcessor();
488 factoryPostProcessor.postProcessBeanFactory(beans);
489
490 tracerTemp = new ValidationTrace(xmlFiles, xmlReader.getResourceLoader());
491
492 LOG.info("Completed XML File Load");
493
494 return beans;
495 }
496
497
498
499
500
501
502
503 private Resource[] getResources(String files[]) {
504 Resource resources[] = new Resource[files.length];
505 for (int i = 0; i < files.length; i++) {
506 resources[0] = new FileSystemResource(files[i]);
507 }
508
509 return resources;
510 }
511
512
513
514
515
516
517 public int getNumberOfErrors() {
518 return numberOfErrors;
519 }
520
521
522
523
524
525
526 public int getNumberOfWarnings() {
527 return numberOfWarnings;
528 }
529
530
531
532
533
534
535
536 public ErrorReport getErrorReport(int index) {
537 return errorReports.get(index);
538 }
539
540
541
542
543
544
545 public int getErrorReportSize() {
546 return errorReports.size();
547 }
548 }