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