1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.rule;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.jdom.Document;
20 import org.jdom.Element;
21 import org.kuali.rice.core.api.util.xml.XmlHelper;
22 import org.kuali.rice.kew.api.WorkflowRuntimeException;
23 import org.kuali.rice.kew.doctype.bo.DocumentType;
24 import org.kuali.rice.kew.doctype.service.DocumentTypeService;
25 import org.kuali.rice.kew.exception.WorkflowServiceError;
26 import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
27 import org.kuali.rice.kew.routeheader.DocumentContent;
28 import org.kuali.rice.kew.rule.xmlrouting.XPathHelper;
29 import org.kuali.rice.kew.service.KEWServiceLocator;
30 import org.kuali.rice.kns.web.ui.Field;
31 import org.kuali.rice.kns.web.ui.Row;
32
33 import javax.xml.xpath.XPath;
34 import javax.xml.xpath.XPathExpressionException;
35 import java.io.StringReader;
36 import java.util.ArrayList;
37 import java.util.Collection;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Map;
41
42
43
44
45
46
47
48
49 public class RuleRoutingAttribute implements WorkflowRuleAttribute {
50
51 private static final long serialVersionUID = -8884711461398770563L;
52
53 private static final String DOC_TYPE_NAME_PROPERTY = "docTypeFullName";
54 private static final String DOC_TYPE_NAME_KEY = "docTypeFullName";
55
56 private static final String LOOKUPABLE_CLASS = "org.kuali.rice.kew.doctype.bo.DocumentType";
57 private static final String DOC_TYPE_NAME_LABEL = "Document type name";
58
59 private static final String DOC_TYPE_NAME_XPATH = "//newMaintainableObject/businessObject/docTypeName";
60 private static final String DOC_TYPE_NAME_DEL_XPATH = "//newMaintainableObject/businessObject/delegationRuleBaseValues/docTypeName";
61
62 private String doctypeName;
63 private List<Row> rows;
64 private boolean required;
65
66 public RuleRoutingAttribute(String docTypeName) {
67 this();
68 setDoctypeName(docTypeName);
69 }
70
71 public RuleRoutingAttribute() {
72 buildRows();
73 }
74
75 private void buildRows() {
76 rows = new ArrayList<Row>();
77
78 List<Field> fields = new ArrayList<Field>();
79 fields.add(new Field(DOC_TYPE_NAME_LABEL, "", Field.TEXT, false, DOC_TYPE_NAME_PROPERTY, "", false, false, null, LOOKUPABLE_CLASS));
80
81 rows.add(new Row(fields));
82 }
83
84 public boolean isMatch(DocumentContent docContent, List ruleExtensions) {
85 setDoctypeName(getRuleDocumentTypeFromRuleExtensions(ruleExtensions));
86 DocumentTypeService service = (DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
87
88 try {
89 String docTypeName = getDocTypNameFromXML(docContent);
90 if (docTypeName.equals(getDoctypeName())) {
91 return true;
92 }
93 DocumentType documentType = service.findByName(docTypeName);
94 while (documentType != null && documentType.getParentDocType() != null) {
95 documentType = documentType.getParentDocType();
96 if(documentType.getName().equals(getDoctypeName())){
97 return true;
98 }
99 }
100 } catch (XPathExpressionException e) {
101 throw new WorkflowRuntimeException(e);
102 }
103
104
105 if (ruleExtensions.isEmpty()) {
106 return true;
107 }
108 return false;
109 }
110
111 protected String getRuleDocumentTypeFromRuleExtensions(List ruleExtensions) {
112 for (Iterator extensionsIterator = ruleExtensions.iterator(); extensionsIterator.hasNext();) {
113 RuleExtensionBo extension = (RuleExtensionBo) extensionsIterator.next();
114 if (extension.getRuleTemplateAttribute().getRuleAttribute().getResourceDescriptor().equals(getClass().getName())) {
115 for (Iterator valuesIterator = extension.getExtensionValues().iterator(); valuesIterator.hasNext();) {
116 RuleExtensionValue extensionValue = (RuleExtensionValue) valuesIterator.next();
117 String key = extensionValue.getKey();
118 String value = extensionValue.getValue();
119 if (key.equals(DOC_TYPE_NAME_KEY)) {
120 return value;
121 }
122 }
123 }
124 }
125 return null;
126 }
127
128 public List getRuleRows() {
129 return rows;
130 }
131
132 public List getRoutingDataRows() {
133 return rows;
134 }
135
136 public String getDocContent() {
137 if (!org.apache.commons.lang.StringUtils.isEmpty(getDoctypeName())) {
138 return "<ruleRouting><doctype>" + getDoctypeName() + "</doctype></ruleRouting>";
139 } else {
140 return "";
141 }
142 }
143
144
145 private String getDocTypNameFromXML(DocumentContent docContent) throws XPathExpressionException {
146 XPath xPath = XPathHelper.newXPath();
147 String docTypeName = xPath.evaluate(DOC_TYPE_NAME_XPATH, docContent.getDocument());
148
149 if (StringUtils.isBlank(docTypeName)) {
150 docTypeName = xPath.evaluate(DOC_TYPE_NAME_DEL_XPATH, docContent.getDocument());
151
152 if (StringUtils.isBlank(docTypeName)) {
153 throw new WorkflowRuntimeException("Could not locate Document Type Name on the document: " +
154 docContent.getRouteContext().getDocument().getDocumentId());
155 }
156 }
157 return docTypeName;
158 }
159
160
161 public List<RuleRoutingAttribute> parseDocContent(DocumentContent docContent) {
162 try {
163 Document doc2 = (Document) XmlHelper.buildJDocument(new StringReader(docContent.getDocContent()));
164
165 List<RuleRoutingAttribute> doctypeAttributes = new ArrayList<RuleRoutingAttribute>();
166 Collection<Element> ruleRoutings = XmlHelper.findElements(doc2.getRootElement(), "docTypeName");
167 List<String> usedDTs = new ArrayList<String>();
168 for (Iterator<Element> iter = ruleRoutings.iterator(); iter.hasNext();) {
169 Element ruleRoutingElement = (Element) iter.next();
170
171
172 Element docTypeElement = ruleRoutingElement;
173 String elTxt = docTypeElement.getText();
174 if (docTypeElement != null && !usedDTs.contains(elTxt)) {
175 usedDTs.add(elTxt);
176 doctypeAttributes.add(new RuleRoutingAttribute(elTxt));
177 }
178 }
179
180 return doctypeAttributes;
181 } catch (Exception e) {
182 throw new RuntimeException(e);
183 }
184 }
185
186 public List getRuleExtensionValues() {
187 List extensions = new ArrayList();
188
189 if (!org.apache.commons.lang.StringUtils.isEmpty(getDoctypeName())) {
190 RuleExtensionValue extension = new RuleExtensionValue();
191 extension.setKey(DOC_TYPE_NAME_KEY);
192 extension.setValue(getDoctypeName());
193 extensions.add(extension);
194 }
195
196 return extensions;
197 }
198
199 public List<WorkflowServiceError> validateRoutingData(Map paramMap) {
200 List<WorkflowServiceError> errors = new ArrayList<WorkflowServiceError>();
201 setDoctypeName((String) paramMap.get(DOC_TYPE_NAME_PROPERTY));
202 if (isRequired() && org.apache.commons.lang.StringUtils.isEmpty(getDoctypeName())) {
203 errors.add(new WorkflowServiceErrorImpl("doc type is not valid.", "routetemplate.ruleroutingattribute.doctype.invalid"));
204 }
205
206 if (!org.apache.commons.lang.StringUtils.isEmpty(getDoctypeName())) {
207 DocumentTypeService service = (DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
208 DocumentType documentType = service.findByName(getDoctypeName());
209 if (documentType == null) {
210 errors.add(new WorkflowServiceErrorImpl("doc type is not valid", "routetemplate.ruleroutingattribute.doctype.invalid"));
211 }
212 }
213 return errors;
214 }
215
216 public List<WorkflowServiceError> validateRuleData(Map paramMap) {
217 return validateRoutingData(paramMap);
218 }
219
220 public String getDoctypeName() {
221 return this.doctypeName;
222 }
223
224 public void setDoctypeName(String docTypeName) {
225 this.doctypeName = docTypeName;
226 }
227
228 public void setRequired(boolean required) {
229 this.required = required;
230 }
231
232 public boolean isRequired() {
233 return required;
234 }
235 }