1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.dto;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.apache.log4j.Logger;
20 import org.kuali.rice.core.api.exception.RiceRuntimeException;
21 import org.kuali.rice.core.api.reflect.DataDefinition;
22 import org.kuali.rice.core.api.reflect.ObjectDefinition;
23 import org.kuali.rice.core.api.reflect.PropertyDefinition;
24 import org.kuali.rice.core.api.util.xml.XmlHelper;
25 import org.kuali.rice.core.api.util.xml.XmlJotter;
26 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
27 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
28 import org.kuali.rice.kew.api.KewApiServiceLocator;
29 import org.kuali.rice.kew.api.WorkflowRuntimeException;
30 import org.kuali.rice.kew.api.action.ActionRequest;
31 import org.kuali.rice.kew.api.action.ActionTaken;
32 import org.kuali.rice.kew.api.document.DocumentContentUpdate;
33 import org.kuali.rice.kew.api.document.DocumentDetail;
34 import org.kuali.rice.kew.api.document.InvalidDocumentContentException;
35 import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition;
36 import org.kuali.rice.kew.api.extension.ExtensionDefinition;
37 import org.kuali.rice.kew.api.extension.ExtensionUtils;
38 import org.kuali.rice.kew.definition.AttributeDefinition;
39 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
40 import org.kuali.rice.kew.framework.document.attribute.SearchableAttribute;
41 import org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent;
42 import org.kuali.rice.kew.framework.postprocessor.AfterProcessEvent;
43 import org.kuali.rice.kew.framework.postprocessor.BeforeProcessEvent;
44 import org.kuali.rice.kew.framework.postprocessor.DeleteEvent;
45 import org.kuali.rice.kew.framework.postprocessor.DocumentLockingEvent;
46 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
47 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
48 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
49 import org.kuali.rice.kew.routeheader.StandardDocumentContent;
50 import org.kuali.rice.kew.rule.WorkflowRuleAttribute;
51 import org.kuali.rice.kew.rule.WorkflowAttributeValidationError;
52 import org.kuali.rice.kew.rule.WorkflowAttributeXmlValidator;
53 import org.kuali.rice.kew.rule.XmlConfiguredAttribute;
54 import org.kuali.rice.kew.rule.bo.RuleAttribute;
55 import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute;
56 import org.kuali.rice.kew.service.KEWServiceLocator;
57 import org.kuali.rice.kew.api.KewApiConstants;
58 import org.w3c.dom.Document;
59 import org.w3c.dom.Element;
60 import org.w3c.dom.NodeList;
61 import org.xml.sax.SAXException;
62
63 import javax.xml.parsers.DocumentBuilder;
64 import javax.xml.parsers.DocumentBuilderFactory;
65 import javax.xml.parsers.ParserConfigurationException;
66 import javax.xml.transform.TransformerException;
67 import java.io.IOException;
68 import java.util.ArrayList;
69 import java.util.HashMap;
70 import java.util.Iterator;
71 import java.util.List;
72 import java.util.Map;
73
74
75
76
77
78
79 public class DTOConverter {
80 private static final Logger LOG = Logger.getLogger(DTOConverter.class);
81
82 public static String buildUpdatedDocumentContent(String existingDocContent,
83 DocumentContentUpdate documentContentUpdate, String documentTypeName) {
84 if (existingDocContent == null) {
85 existingDocContent = KewApiConstants.DEFAULT_DOCUMENT_CONTENT;
86 }
87 String documentContent = KewApiConstants.DEFAULT_DOCUMENT_CONTENT;
88 StandardDocumentContent standardDocContent = new StandardDocumentContent(existingDocContent);
89 try {
90 DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
91 Document document = builder.newDocument();
92 Element root = document.createElement(KewApiConstants.DOCUMENT_CONTENT_ELEMENT);
93 document.appendChild(root);
94 Element applicationContentElement = standardDocContent.getApplicationContent();
95 if (documentContentUpdate.getApplicationContent() != null) {
96
97 if (!StringUtils.isEmpty(documentContentUpdate.getApplicationContent())) {
98 applicationContentElement = document.createElement(KewApiConstants.APPLICATION_CONTENT_ELEMENT);
99 XmlHelper.appendXml(applicationContentElement, documentContentUpdate.getApplicationContent());
100 } else {
101
102 applicationContentElement = null;
103 }
104 }
105 Element attributeContentElement = createDocumentContentSection(document,
106 standardDocContent.getAttributeContent(), documentContentUpdate.getAttributeDefinitions(),
107 documentContentUpdate.getAttributeContent(), KewApiConstants.ATTRIBUTE_CONTENT_ELEMENT,
108 documentTypeName);
109 Element searchableContentElement = createDocumentContentSection(document,
110 standardDocContent.getSearchableContent(), documentContentUpdate.getSearchableDefinitions(),
111 documentContentUpdate.getSearchableContent(), KewApiConstants.SEARCHABLE_CONTENT_ELEMENT,
112 documentTypeName);
113 if (applicationContentElement != null) {
114 root.appendChild(applicationContentElement);
115 }
116 if (attributeContentElement != null) {
117 root.appendChild(attributeContentElement);
118 }
119 if (searchableContentElement != null) {
120 root.appendChild(searchableContentElement);
121 }
122 documentContent = XmlJotter.jotNode(document);
123 } catch (ParserConfigurationException e) {
124 throw new RiceRuntimeException("Failed to initialize XML parser.", e);
125 } catch (SAXException e) {
126 throw new InvalidDocumentContentException("Failed to parse XML.", e);
127 } catch (IOException e) {
128 throw new InvalidDocumentContentException("Failed to parse XML.", e);
129 } catch (TransformerException e) {
130 throw new InvalidDocumentContentException("Failed to parse XML.", e);
131 }
132 return documentContent;
133 }
134
135 private static Element createDocumentContentSection(Document document, Element existingAttributeElement,
136 List<WorkflowAttributeDefinition> definitions, String content, String elementName,
137 String documentTypeName) throws TransformerException, SAXException, IOException, ParserConfigurationException {
138 Element contentSectionElement = existingAttributeElement;
139
140 if (content != null) {
141 if (!org.apache.commons.lang.StringUtils.isEmpty(content)) {
142 contentSectionElement = document.createElement(elementName);
143
144
145 Element incomingAttributeElement = XmlHelper.readXml(content).getDocumentElement();
146 NodeList children = incomingAttributeElement.getChildNodes();
147 for (int index = 0; index < children.getLength(); index++) {
148 contentSectionElement.appendChild(document.importNode(children.item(index), true));
149 }
150 } else {
151 contentSectionElement = null;
152 }
153 }
154
155 if (definitions != null && !definitions.isEmpty()) {
156 String errorMessage = "";
157 boolean inError = false;
158 if (contentSectionElement == null) {
159 contentSectionElement = document.createElement(elementName);
160 }
161 for (WorkflowAttributeDefinition definitionVO : definitions) {
162 AttributeDefinition definition = convertWorkflowAttributeDefinition(definitionVO);
163 ExtensionDefinition extensionDefinition = definition.getExtensionDefinition();
164 Object attribute = ExtensionUtils.loadExtension(extensionDefinition);
165
166 if (attribute instanceof XmlConfiguredAttribute) {
167 ((XmlConfiguredAttribute)attribute).setExtensionDefinition(RuleAttribute.to(definition.getRuleAttribute()));
168 }
169 boolean propertiesAsMap = false;
170 if (KewApiConstants.RULE_XML_ATTRIBUTE_TYPE.equals(extensionDefinition.getType())) {
171 propertiesAsMap = true;
172 }
173 if (propertiesAsMap) {
174 for (org.kuali.rice.kew.api.document.PropertyDefinition propertyDefinitionVO : definitionVO
175 .getPropertyDefinitions()) {
176 if (attribute instanceof GenericXMLRuleAttribute) {
177 ((GenericXMLRuleAttribute) attribute).getParamMap().put(propertyDefinitionVO.getName(),
178 propertyDefinitionVO.getValue());
179 }
180 }
181 }
182
183
184 if (attribute instanceof WorkflowAttributeXmlValidator) {
185 List<WorkflowAttributeValidationError> errors =
186 ((WorkflowAttributeXmlValidator) attribute).validateClientRoutingData();
187 if (!errors.isEmpty()) {
188 inError = true;
189 errorMessage += "Error validating attribute " + definitionVO.getAttributeName() + " ";
190 for (WorkflowAttributeValidationError error : errors) {
191 errorMessage += error.getMessage() + " ";
192 }
193 }
194 }
195
196 if (!inError) {
197 if (attribute instanceof WorkflowRuleAttribute) {
198 String attributeDocContent = ((WorkflowRuleAttribute) attribute).getDocContent();
199 if (!StringUtils.isEmpty(attributeDocContent)) {
200 XmlHelper.appendXml(contentSectionElement, attributeDocContent);
201 }
202 } else if (attribute instanceof SearchableAttribute) {
203 SearchableAttribute searchableAttribute = (SearchableAttribute) attribute;
204 String searchableAttributeContent = searchableAttribute.generateSearchContent(extensionDefinition, documentTypeName,
205 definitionVO);
206 if (!StringUtils.isBlank(searchableAttributeContent)) {
207 XmlHelper.appendXml(contentSectionElement, searchableAttributeContent);
208 }
209 }
210 }
211 }
212 if (inError) {
213 throw new WorkflowRuntimeException(errorMessage);
214 }
215
216 }
217 if (contentSectionElement != null) {
218
219
220
221 contentSectionElement = (Element) document.importNode(contentSectionElement, true);
222 }
223 return contentSectionElement;
224 }
225
226
227
228
229 public static AttributeDefinition convertWorkflowAttributeDefinition(WorkflowAttributeDefinition definition) {
230 if (definition == null) {
231 return null;
232 }
233
234 ExtensionDefinition extensionDefinition = KewApiServiceLocator.getExtensionRepositoryService().getExtensionByName(definition.getAttributeName());
235 if (extensionDefinition == null) {
236 throw new WorkflowRuntimeException("Extension " + definition.getAttributeName() + " not found");
237 }
238 RuleAttribute ruleAttribute = KEWServiceLocator.getRuleAttributeService().findByName(definition.getAttributeName());
239 if (ruleAttribute == null) {
240 throw new WorkflowRuntimeException("Attribute " + definition.getAttributeName() + " not found");
241 }
242
243 ObjectDefinition objectDefinition = new ObjectDefinition(extensionDefinition.getResourceDescriptor());
244 if (definition.getParameters() != null) {
245 for (String parameter : definition.getParameters()) {
246 objectDefinition.addConstructorParameter(new DataDefinition(parameter, String.class));
247 }
248 }
249 boolean propertiesAsMap = KewApiConstants.RULE_XML_ATTRIBUTE_TYPE.equals(extensionDefinition.getType()) || KewApiConstants
250 .SEARCHABLE_XML_ATTRIBUTE_TYPE.equals(extensionDefinition.getType());
251 if (!propertiesAsMap && definition.getPropertyDefinitions() != null) {
252 for (org.kuali.rice.kew.api.document.PropertyDefinition propertyDefinition : definition
253 .getPropertyDefinitions()) {
254 objectDefinition.addProperty(new PropertyDefinition(propertyDefinition.getName(), new DataDefinition(
255 propertyDefinition.getValue(), String.class)));
256 }
257 }
258
259 return new AttributeDefinition(ruleAttribute, extensionDefinition, objectDefinition);
260 }
261
262
263
264
265 public static interface RouteNodeInstanceLoader {
266 RouteNodeInstance load(String routeNodeInstanceID);
267 }
268
269
270 public static DocumentDetail convertDocumentDetailNew(DocumentRouteHeaderValue routeHeader) {
271 if (routeHeader == null) {
272 return null;
273 }
274 org.kuali.rice.kew.api.document.Document document = DocumentRouteHeaderValue.to(routeHeader);
275 DocumentDetail.Builder detail = DocumentDetail.Builder.create(document);
276 Map<String, RouteNodeInstance> nodeInstances = new HashMap<String, RouteNodeInstance>();
277 List<ActionRequest> actionRequestVOs = new ArrayList<ActionRequest>();
278 List<ActionRequestValue> rootActionRequests = KEWServiceLocator.getActionRequestService().getRootRequests(
279 routeHeader.getActionRequests());
280 for (Iterator<ActionRequestValue> iterator = rootActionRequests.iterator(); iterator.hasNext(); ) {
281 ActionRequestValue actionRequest = iterator.next();
282 actionRequestVOs.add(ActionRequestValue.to(actionRequest));
283 RouteNodeInstance nodeInstance = actionRequest.getNodeInstance();
284 if (nodeInstance == null) {
285 continue;
286 }
287 if (nodeInstance.getRouteNodeInstanceId() == null) {
288 throw new IllegalStateException(
289 "Error creating document detail structure because of NULL node instance id.");
290 }
291 nodeInstances.put(nodeInstance.getRouteNodeInstanceId(), nodeInstance);
292 }
293 detail.setActionRequests(actionRequestVOs);
294 List<org.kuali.rice.kew.api.document.node.RouteNodeInstance> nodeInstanceVOs =
295 new ArrayList<org.kuali.rice.kew.api.document.node.RouteNodeInstance>();
296 for (Iterator<RouteNodeInstance> iterator = nodeInstances.values().iterator(); iterator.hasNext(); ) {
297 RouteNodeInstance nodeInstance = iterator.next();
298 nodeInstanceVOs.add(RouteNodeInstance.to(nodeInstance));
299 }
300 detail.setRouteNodeInstances(nodeInstanceVOs);
301 List<ActionTaken> actionTakenVOs = new ArrayList<ActionTaken>();
302 for (Object element : routeHeader.getActionsTaken()) {
303 ActionTakenValue actionTaken = (ActionTakenValue) element;
304 actionTakenVOs.add(ActionTakenValue.to(actionTaken));
305 }
306 detail.setActionsTaken(actionTakenVOs);
307 return detail.build();
308 }
309
310 }