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