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