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