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 }
128 return documentContent;
129 }
130
131 private static Element createDocumentContentSection(Document document, Element existingAttributeElement,
132 List<WorkflowAttributeDefinition> definitions, String content, String elementName,
133 String documentTypeName) throws SAXException, IOException, ParserConfigurationException {
134 Element contentSectionElement = existingAttributeElement;
135
136 if (content != null) {
137 if (!org.apache.commons.lang.StringUtils.isEmpty(content)) {
138 contentSectionElement = document.createElement(elementName);
139
140
141 Element incomingAttributeElement = XmlHelper.readXml(content).getDocumentElement();
142 NodeList children = incomingAttributeElement.getChildNodes();
143 for (int index = 0; index < children.getLength(); index++) {
144 contentSectionElement.appendChild(document.importNode(children.item(index), true));
145 }
146 } else {
147 contentSectionElement = null;
148 }
149 }
150
151 if (definitions != null && !definitions.isEmpty()) {
152 String errorMessage = "";
153 boolean inError = false;
154 if (contentSectionElement == null) {
155 contentSectionElement = document.createElement(elementName);
156 }
157 for (WorkflowAttributeDefinition definitionVO : definitions) {
158 AttributeDefinition definition = convertWorkflowAttributeDefinition(definitionVO);
159 ExtensionDefinition extensionDefinition = definition.getExtensionDefinition();
160
161 Object attribute = null;
162 attribute = GlobalResourceLoader.getObject(definition.getObjectDefinition());
163 if (attribute == null) {
164 attribute = GlobalResourceLoader.getService(QName.valueOf(
165 definition.getExtensionDefinition().getResourceDescriptor()));
166 }
167
168 if (attribute instanceof XmlConfiguredAttribute) {
169 ((XmlConfiguredAttribute)attribute).setExtensionDefinition(definition.getExtensionDefinition());
170 }
171 boolean propertiesAsMap = false;
172 if (KewApiConstants.RULE_XML_ATTRIBUTE_TYPE.equals(extensionDefinition.getType())) {
173 propertiesAsMap = true;
174 }
175 if (propertiesAsMap) {
176 for (org.kuali.rice.kew.api.document.PropertyDefinition propertyDefinitionVO : definitionVO
177 .getPropertyDefinitions()) {
178 if (attribute instanceof GenericXMLRuleAttribute) {
179 ((GenericXMLRuleAttribute) attribute).getParamMap().put(propertyDefinitionVO.getName(),
180 propertyDefinitionVO.getValue());
181 }
182 }
183 }
184
185
186 if (attribute instanceof WorkflowAttributeXmlValidator) {
187 List<? extends RemotableAttributeErrorContract> errors =
188 ((WorkflowAttributeXmlValidator) attribute).validateClientRoutingData();
189 if (!errors.isEmpty()) {
190 inError = true;
191 errorMessage += "Error validating attribute " + definitionVO.getAttributeName() + " ";
192 errorMessage += Joiner.on("; ").join(Iterables.transform(errors, Functions.toStringFunction()));
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 = null;
235 List<RuleAttribute> ruleAttribute = KEWServiceLocator.getRuleAttributeService().findByClassName(definition.getAttributeName());
236 if (ruleAttribute == null || ruleAttribute.isEmpty()) {
237 extensionDefinition = KewApiServiceLocator.getExtensionRepositoryService().getExtensionByName(definition.getAttributeName());
238 }else{
239
240 RuleAttribute tmpAttr = ruleAttribute.get(0);
241 extensionDefinition = RuleAttribute.to(tmpAttr);
242 if(ruleAttribute.size() > 1){
243 LOG.warn("AttributeDefinition lookup (findByClassName) returned multiple attribute for the same class name. This should not happen, investigation recommended for classname: "
244 + definition.getAttributeName() + " which has " + ruleAttribute.size() + " entries.");
245 }
246 }
247
248 if (extensionDefinition == null) {
249 throw new WorkflowRuntimeException("Extension " + definition.getAttributeName() + " not found");
250 }
251
252
253
254
255
256 ObjectDefinition objectDefinition = new ObjectDefinition(extensionDefinition.getResourceDescriptor());
257 if (definition.getParameters() != null) {
258 for (String parameter : definition.getParameters()) {
259 objectDefinition.addConstructorParameter(new DataDefinition(parameter, String.class));
260 }
261 }
262 boolean propertiesAsMap = KewApiConstants.RULE_XML_ATTRIBUTE_TYPE.equals(extensionDefinition.getType()) || KewApiConstants
263 .SEARCHABLE_XML_ATTRIBUTE_TYPE.equals(extensionDefinition.getType());
264 if (!propertiesAsMap && definition.getPropertyDefinitions() != null) {
265 for (org.kuali.rice.kew.api.document.PropertyDefinition propertyDefinition : definition
266 .getPropertyDefinitions()) {
267 objectDefinition.addProperty(new PropertyDefinition(propertyDefinition.getName(), new DataDefinition(
268 propertyDefinition.getValue(), String.class)));
269 }
270 }
271
272 return new AttributeDefinition(extensionDefinition, objectDefinition);
273 }
274
275
276
277
278 public static interface RouteNodeInstanceLoader {
279 RouteNodeInstance load(String routeNodeInstanceID);
280 }
281
282
283 public static DocumentDetail convertDocumentDetailNew(DocumentRouteHeaderValue routeHeader) {
284 if (routeHeader == null) {
285 return null;
286 }
287 org.kuali.rice.kew.api.document.Document document = DocumentRouteHeaderValue.to(routeHeader);
288 DocumentDetail.Builder detail = DocumentDetail.Builder.create(document);
289 Map<String, RouteNodeInstance> nodeInstances = new HashMap<String, RouteNodeInstance>();
290 List<ActionRequest> actionRequestVOs = new ArrayList<ActionRequest>();
291 List<ActionRequestValue> rootActionRequests = KEWServiceLocator.getActionRequestService().getRootRequests(
292 routeHeader.getActionRequests());
293 for (Iterator<ActionRequestValue> iterator = rootActionRequests.iterator(); iterator.hasNext(); ) {
294 ActionRequestValue actionRequest = iterator.next();
295 actionRequestVOs.add(ActionRequestValue.to(actionRequest));
296 RouteNodeInstance nodeInstance = actionRequest.getNodeInstance();
297 if (nodeInstance == null) {
298 continue;
299 }
300 if (nodeInstance.getRouteNodeInstanceId() == null) {
301 throw new IllegalStateException(
302 "Error creating document detail structure because of NULL node instance id.");
303 }
304 nodeInstances.put(nodeInstance.getRouteNodeInstanceId(), nodeInstance);
305 }
306 detail.setActionRequests(actionRequestVOs);
307 List<org.kuali.rice.kew.api.document.node.RouteNodeInstance> nodeInstanceVOs =
308 new ArrayList<org.kuali.rice.kew.api.document.node.RouteNodeInstance>();
309 for (Iterator<RouteNodeInstance> iterator = nodeInstances.values().iterator(); iterator.hasNext(); ) {
310 RouteNodeInstance nodeInstance = iterator.next();
311 nodeInstanceVOs.add(RouteNodeInstance.to(nodeInstance));
312 }
313 detail.setRouteNodeInstances(nodeInstanceVOs);
314 List<ActionTaken> actionTakenVOs = new ArrayList<ActionTaken>();
315 for (Object element : routeHeader.getActionsTaken()) {
316 ActionTakenValue actionTaken = (ActionTakenValue) element;
317 actionTakenVOs.add(ActionTakenValue.to(actionTaken));
318 }
319 detail.setActionsTaken(actionTakenVOs);
320 return detail.build();
321 }
322
323 }