Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ValidationComponent |
|
| 7.0;7 |
1 | /* | |
2 | * Copyright 2008-2009 The Kuali Foundation | |
3 | * | |
4 | * Licensed under the Educational Community License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.opensource.org/licenses/ecl2.php | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | package org.kuali.rice.edl.impl.components; | |
17 | ||
18 | import java.util.ArrayList; | |
19 | import java.util.List; | |
20 | import java.util.Map; | |
21 | ||
22 | import javax.xml.xpath.XPath; | |
23 | import javax.xml.xpath.XPathConstants; | |
24 | ||
25 | import org.apache.commons.lang.StringUtils; | |
26 | import org.kuali.rice.edl.impl.EDLContext; | |
27 | import org.kuali.rice.edl.impl.EDLModelComponent; | |
28 | import org.kuali.rice.edl.impl.EDLXmlUtils; | |
29 | import org.kuali.rice.edl.impl.RequestParser; | |
30 | import org.kuali.rice.edl.impl.service.EdlServiceLocator; | |
31 | import org.kuali.rice.kew.exception.WorkflowRuntimeException; | |
32 | import org.kuali.rice.kew.rule.xmlrouting.XPathHelper; | |
33 | import org.w3c.dom.Document; | |
34 | import org.w3c.dom.Element; | |
35 | import org.w3c.dom.NodeList; | |
36 | ||
37 | ||
38 | /** | |
39 | * Executes validations that are defined on the EDL Definitions. These validation exist in a form | |
40 | * similiar to the following: | |
41 | * | |
42 | * <validations> | |
43 | * <validation type="xpath"> | |
44 | * <expression>wf:field('grade') = 'other' and not(wf:empty(wf:field('otherGrade'))</expression> | |
45 | * <message>Other Grade is required when grade is marked as 'other'</message> | |
46 | * </validation> | |
47 | * </validations> | |
48 | * | |
49 | * @author Kuali Rice Team (rice.collab@kuali.org) | |
50 | */ | |
51 | 0 | public class ValidationComponent extends SimpleWorkflowEDLConfigComponent implements EDLModelComponent { |
52 | ||
53 | private static final String XPATH_TYPE = "xpath"; | |
54 | private EDLContext edlContext; | |
55 | ||
56 | public void updateDOM(Document dom, Element configElement, EDLContext edlContext) { | |
57 | 0 | if (edlContext.getUserAction().isValidatableAction()) { |
58 | try { | |
59 | 0 | Document edlDef = EdlServiceLocator.getEDocLiteService().getDefinitionXml(edlContext.getEdocLiteAssociation()); |
60 | 0 | List<EDLValidation> validations = parseValidations(edlDef); |
61 | 0 | if (!validations.isEmpty()) { |
62 | 0 | XPath xpath = XPathHelper.newXPath(dom); |
63 | 0 | for (EDLValidation validation : validations) { |
64 | 0 | executeValidation(xpath, dom, validation, edlContext); |
65 | } | |
66 | } | |
67 | 0 | } catch (Exception e) { |
68 | 0 | if (e instanceof RuntimeException) { |
69 | 0 | throw (RuntimeException)e; |
70 | } | |
71 | 0 | throw new WorkflowRuntimeException("Failed to execute EDL validations.", e); |
72 | 0 | } |
73 | } | |
74 | 0 | } |
75 | ||
76 | protected List<EDLValidation> parseValidations(Document document) throws Exception { | |
77 | 0 | List<EDLValidation> validations = new ArrayList<EDLValidation>(); |
78 | 0 | XPath xpath = XPathHelper.newXPath(document); |
79 | 0 | NodeList validationNodes = (NodeList)xpath.evaluate("/edl/validations/validation", document, XPathConstants.NODESET); |
80 | 0 | for (int index = 0; index < validationNodes.getLength(); index++) { |
81 | 0 | Element validationElem = (Element)validationNodes.item(index); |
82 | 0 | EDLValidation validation = new EDLValidation(); |
83 | 0 | String type = validationElem.getAttribute("type"); |
84 | 0 | String key = validationElem.getAttribute("key"); |
85 | 0 | String expression = EDLXmlUtils.getChildElementTextValue(validationElem, "expression"); |
86 | 0 | String message = EDLXmlUtils.getChildElementTextValue(validationElem, "message"); |
87 | 0 | if (StringUtils.isBlank(type)) { |
88 | 0 | throw new WorkflowRuntimeException("An improperly configured validation was found with an empty type."); |
89 | } | |
90 | 0 | if (StringUtils.isBlank(expression)) { |
91 | 0 | throw new WorkflowRuntimeException("An improperly configured validation was found with an empty expression."); |
92 | } | |
93 | 0 | if (StringUtils.isBlank(message)) { |
94 | 0 | throw new WorkflowRuntimeException("An improperly configured validation was found with an empty message."); |
95 | } | |
96 | 0 | validation.setType(type); |
97 | 0 | validation.setKey(key); |
98 | 0 | validation.setExpression(expression); |
99 | 0 | validation.setMessage(message); |
100 | 0 | validations.add(validation); |
101 | } | |
102 | 0 | return validations; |
103 | } | |
104 | ||
105 | protected void executeValidation(XPath xpath, Document dom, EDLValidation validation, EDLContext edlContext) throws Exception { | |
106 | // TODO: in the future, allow this to be pluggable, hardcode for now | |
107 | 0 | if (XPATH_TYPE.equals(validation.getType())) { |
108 | 0 | Boolean result = (Boolean)xpath.evaluate(validation.getExpression(), dom, XPathConstants.BOOLEAN); |
109 | // if validation returns false, we'll flag the error | |
110 | 0 | if (!result) { |
111 | 0 | String key = validation.getKey(); |
112 | 0 | if (!StringUtils.isEmpty(key)) { |
113 | 0 | Map<String, String> fieldErrors = (Map<String, String>)edlContext.getRequestParser().getAttribute(RequestParser.GLOBAL_FIELD_ERRORS_KEY); |
114 | 0 | fieldErrors.put(key, validation.getMessage()); |
115 | ||
116 | // set invalid attribute to true on corresponding field | |
117 | //TODO remove - handled this in the widgets | |
118 | // Element edlElement = EDLXmlUtils.getEDLContent(dom, false); | |
119 | // Element edlSubElement = EDLXmlUtils.getOrCreateChildElement(edlElement, "data", true); | |
120 | // NodeList versionNodes = edlSubElement.getChildNodes(); | |
121 | // for (int i = 0; i < versionNodes.getLength(); i++) { | |
122 | // Element version = (Element) versionNodes.item(i); | |
123 | // String current = version.getAttribute("current"); | |
124 | // if (current == "true") { | |
125 | // NodeList fieldNodes = version.getChildNodes(); | |
126 | // for (int j = 0; j < fieldNodes.getLength(); j++) { | |
127 | // Element field = (Element) fieldNodes.item(j); | |
128 | // String fieldName = field.getAttribute("name"); | |
129 | // if(fieldName.equals(key)) { | |
130 | // field.setAttribute("invalid", "true"); | |
131 | // break; | |
132 | // } | |
133 | // } | |
134 | // } | |
135 | // } | |
136 | ||
137 | 0 | } else { |
138 | 0 | List globalErrors = (List)edlContext.getRequestParser().getAttribute(RequestParser.GLOBAL_ERRORS_KEY); |
139 | 0 | globalErrors.add(validation.getMessage()); |
140 | } | |
141 | 0 | edlContext.setInError(true); |
142 | } | |
143 | 0 | } else { |
144 | 0 | throw new WorkflowRuntimeException("Illegal validation type specified. Only 'xpath' is currently supported."); |
145 | } | |
146 | 0 | } |
147 | ||
148 | ||
149 | } |