View Javadoc

1   /**
2    * Copyright 2005-2014 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.api.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  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  		if (edlContext.getUserAction().isValidatableAction()) {
58  			try {
59  				Document edlDef = EdlServiceLocator.getEDocLiteService().getDefinitionXml(edlContext.getEdocLiteAssociation());
60  				List<EDLValidation> validations = parseValidations(edlDef);
61  				if (!validations.isEmpty()) {
62  					XPath xpath = XPathHelper.newXPath(dom);
63  					for (EDLValidation validation : validations) {
64  						executeValidation(xpath, dom, validation, edlContext);
65  					}
66  				}
67  			} catch (Exception e) {
68  				if (e instanceof RuntimeException) {
69  					throw (RuntimeException)e;
70  				}
71  				throw new WorkflowRuntimeException("Failed to execute EDL validations.", e);
72  			}
73  		}
74  	}
75  
76  	protected List<EDLValidation> parseValidations(Document document) throws Exception {
77  		List<EDLValidation> validations = new ArrayList<EDLValidation>();
78  		XPath xpath = XPathHelper.newXPath(document);
79  		NodeList validationNodes = (NodeList)xpath.evaluate("/edl/validations/validation", document, XPathConstants.NODESET);
80  		for (int index = 0; index < validationNodes.getLength(); index++) {
81  			Element validationElem = (Element)validationNodes.item(index);
82  			EDLValidation validation = new EDLValidation();
83  			String type = validationElem.getAttribute("type");
84  			String key = validationElem.getAttribute("key");
85  			String expression = EDLXmlUtils.getChildElementTextValue(validationElem, "expression");
86  			String message = EDLXmlUtils.getChildElementTextValue(validationElem, "message");
87  			if (StringUtils.isBlank(type)) {
88  				throw new WorkflowRuntimeException("An improperly configured validation was found with an empty type.");
89  			}
90  			if (StringUtils.isBlank(expression)) {
91  				throw new WorkflowRuntimeException("An improperly configured validation was found with an empty expression.");
92  			}
93  			if (StringUtils.isBlank(message)) {
94  				throw new WorkflowRuntimeException("An improperly configured validation was found with an empty message.");
95  			}
96  			validation.setType(type);
97  			validation.setKey(key);
98  			validation.setExpression(expression);
99  			validation.setMessage(message);
100 			validations.add(validation);
101 		}
102 		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 		if (XPATH_TYPE.equals(validation.getType())) {
108 			Boolean result = (Boolean)xpath.evaluate(validation.getExpression(), dom, XPathConstants.BOOLEAN);
109 			// if validation returns false, we'll flag the error
110 			if (!result) {
111 				String key = validation.getKey();
112 				if (!StringUtils.isEmpty(key)) {
113 					Map<String, String> fieldErrors = (Map<String, String>)edlContext.getRequestParser().getAttribute(RequestParser.GLOBAL_FIELD_ERRORS_KEY);
114 					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 				} else {
138 					List globalErrors = (List)edlContext.getRequestParser().getAttribute(RequestParser.GLOBAL_ERRORS_KEY);
139 					globalErrors.add(validation.getMessage());
140 				}
141 				edlContext.setInError(true);
142 			}
143 		} else {
144 			throw new WorkflowRuntimeException("Illegal validation type specified.  Only 'xpath' is currently supported.");
145 		}
146 	}
147 
148 
149 }