View Javadoc

1   /*
2    * Copyright 2005-2008 The Kuali Foundation
3    *
4    *
5    * Licensed under the Educational Community License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.opensource.org/licenses/ecl2.php
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.kuali.rice.kew.dto;
18  
19  import java.sql.Timestamp;
20  import java.util.ArrayList;
21  import java.util.Arrays;
22  import java.util.Collection;
23  import java.util.Date;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  
29  import javax.xml.parsers.DocumentBuilder;
30  import javax.xml.parsers.DocumentBuilderFactory;
31  
32  import org.apache.commons.lang.StringUtils;
33  import org.apache.log4j.Logger;
34  import org.kuali.rice.core.exception.RiceRuntimeException;
35  import org.kuali.rice.core.reflect.DataDefinition;
36  import org.kuali.rice.core.reflect.ObjectDefinition;
37  import org.kuali.rice.core.reflect.PropertyDefinition;
38  import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
39  import org.kuali.rice.kew.actionitem.ActionItem;
40  import org.kuali.rice.kew.actionrequest.ActionRequestFactory;
41  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
42  import org.kuali.rice.kew.actionrequest.KimGroupRecipient;
43  import org.kuali.rice.kew.actionrequest.KimPrincipalRecipient;
44  import org.kuali.rice.kew.actionrequest.Recipient;
45  import org.kuali.rice.kew.actions.AdHocRevoke;
46  import org.kuali.rice.kew.actions.MovePoint;
47  import org.kuali.rice.kew.actions.ValidActions;
48  import org.kuali.rice.kew.actiontaken.ActionTakenValue;
49  import org.kuali.rice.kew.definition.AttributeDefinition;
50  import org.kuali.rice.kew.docsearch.DocSearchCriteriaDTO;
51  import org.kuali.rice.kew.docsearch.DocSearchUtils;
52  import org.kuali.rice.kew.docsearch.DocumentSearchResult;
53  import org.kuali.rice.kew.docsearch.DocumentSearchResultComponents;
54  import org.kuali.rice.kew.docsearch.SearchableAttribute;
55  import org.kuali.rice.kew.docsearch.web.SearchAttributeFormContainer;
56  import org.kuali.rice.kew.docsearch.xml.GenericXMLSearchableAttribute;
57  import org.kuali.rice.kew.doctype.bo.DocumentType;
58  import org.kuali.rice.kew.documentlink.DocumentLink;
59  import org.kuali.rice.kew.engine.node.BranchState;
60  import org.kuali.rice.kew.engine.node.KeyValuePair;
61  import org.kuali.rice.kew.engine.node.Process;
62  import org.kuali.rice.kew.engine.node.RouteNode;
63  import org.kuali.rice.kew.engine.node.RouteNodeInstance;
64  import org.kuali.rice.kew.engine.node.State;
65  import org.kuali.rice.kew.engine.simulation.SimulationActionToTake;
66  import org.kuali.rice.kew.engine.simulation.SimulationCriteria;
67  import org.kuali.rice.kew.exception.DocumentTypeNotFoundException;
68  import org.kuali.rice.kew.exception.WorkflowException;
69  import org.kuali.rice.kew.exception.WorkflowRuntimeException;
70  import org.kuali.rice.kew.notes.Note;
71  import org.kuali.rice.kew.notes.service.NoteService;
72  import org.kuali.rice.kew.postprocessor.ActionTakenEvent;
73  import org.kuali.rice.kew.postprocessor.AfterProcessEvent;
74  import org.kuali.rice.kew.postprocessor.BeforeProcessEvent;
75  import org.kuali.rice.kew.postprocessor.DeleteEvent;
76  import org.kuali.rice.kew.postprocessor.DocumentLockingEvent;
77  import org.kuali.rice.kew.postprocessor.DocumentRouteLevelChange;
78  import org.kuali.rice.kew.postprocessor.DocumentRouteStatusChange;
79  import org.kuali.rice.kew.routeheader.DocumentContent;
80  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
81  import org.kuali.rice.kew.routeheader.DocumentStatusTransition;
82  import org.kuali.rice.kew.routeheader.StandardDocumentContent;
83  import org.kuali.rice.kew.rule.RuleBaseValues;
84  import org.kuali.rice.kew.rule.RuleDelegation;
85  import org.kuali.rice.kew.rule.RuleExtension;
86  import org.kuali.rice.kew.rule.RuleExtensionValue;
87  import org.kuali.rice.kew.rule.RuleResponsibility;
88  import org.kuali.rice.kew.rule.WorkflowAttribute;
89  import org.kuali.rice.kew.rule.WorkflowAttributeValidationError;
90  import org.kuali.rice.kew.rule.WorkflowAttributeXmlValidator;
91  import org.kuali.rice.kew.rule.bo.RuleAttribute;
92  import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute;
93  import org.kuali.rice.kew.service.KEWServiceLocator;
94  import org.kuali.rice.kew.user.RoleRecipient;
95  import org.kuali.rice.kew.util.KEWConstants;
96  import org.kuali.rice.kew.util.ResponsibleParty;
97  import org.kuali.rice.kew.util.Utilities;
98  import org.kuali.rice.kew.util.XmlHelper;
99  import org.kuali.rice.kew.web.KeyValueSort;
100 import org.kuali.rice.kim.bo.Group;
101 import org.kuali.rice.kim.bo.Person;
102 import org.kuali.rice.kim.bo.entity.KimPrincipal;
103 import org.kuali.rice.kim.bo.types.dto.AttributeSet;
104 import org.kuali.rice.kim.service.KIMServiceLocator;
105 import org.w3c.dom.Document;
106 import org.w3c.dom.Element;
107 import org.w3c.dom.NodeList;
108 
109 import org.kuali.rice.kew.engine.node.Branch;
110 
111 
112 /**
113  * Translates Workflow server side beans into client side VO beans.
114  *
115  * @author Kuali Rice Team (rice.collab@kuali.org)
116  */
117 public class DTOConverter {
118     private static final Logger LOG = Logger.getLogger(DTOConverter.class);
119     
120     public static RouteHeaderDTO convertRouteHeader(DocumentRouteHeaderValue routeHeader, String principalId) throws WorkflowException {
121         RouteHeaderDTO routeHeaderVO = new RouteHeaderDTO();
122         if (routeHeader == null) {
123             return null;
124         }
125         populateRouteHeaderVO(routeHeaderVO, routeHeader);
126 
127         if (principalId != null) {
128             routeHeaderVO.setUserBlanketApprover(false); // default to false
129             if (routeHeader.getDocumentType() != null) {
130             	boolean isBlanketApprover = KEWServiceLocator.getDocumentTypePermissionService().canBlanketApprove(principalId, routeHeader.getDocumentType(), routeHeader.getDocRouteStatus(), routeHeader.getInitiatorWorkflowId());
131                 routeHeaderVO.setUserBlanketApprover(isBlanketApprover);
132             }
133             AttributeSet actionsRequested = KEWServiceLocator.getActionRequestService().getActionsRequested(routeHeader, principalId, true);
134             for (String actionRequestCode : actionsRequested.keySet()) {
135 				if (KEWConstants.ACTION_REQUEST_FYI_REQ.equals(actionRequestCode)) {
136                     routeHeaderVO.setFyiRequested(Boolean.parseBoolean(actionsRequested.get(actionRequestCode)));					
137 				}
138 				else if (KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ.equals(actionRequestCode)) {
139                     routeHeaderVO.setAckRequested(Boolean.parseBoolean(actionsRequested.get(actionRequestCode)));
140 				}
141 				else if (KEWConstants.ACTION_REQUEST_APPROVE_REQ.equals(actionRequestCode)) {
142                     routeHeaderVO.setApproveRequested(Boolean.parseBoolean(actionsRequested.get(actionRequestCode)));					
143 				}
144 				else {
145                     routeHeaderVO.setCompleteRequested(Boolean.parseBoolean(actionsRequested.get(actionRequestCode)));
146 				}
147 			}
148             // Update notes and notesToDelete arrays in routeHeaderVO
149             routeHeaderVO.setNotesToDelete(null);
150             routeHeaderVO.setNotes(convertNotesArrayListToNoteVOArray(routeHeader.getNotes()));
151         }
152 
153 
154         if (principalId != null) {
155         	KimPrincipal principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(principalId);
156             routeHeaderVO.setValidActions(convertValidActions(KEWServiceLocator.getActionRegistry().getValidActions(principal, routeHeader)));
157         }
158         return routeHeaderVO;
159     }
160 
161     public static ValidActionsDTO convertValidActions(ValidActions validActions) {
162         ValidActionsDTO validActionsVO = new ValidActionsDTO();
163         for (Iterator<String> iter = validActions.getActionTakenCodes().iterator(); iter.hasNext();) {
164             String actionTakenCode = iter.next();
165             validActionsVO.addValidActionsAllowed(actionTakenCode);
166         }
167         return validActionsVO;
168     }
169 
170     private static void populateRouteHeaderVO(RouteHeaderDTO routeHeaderVO, DocumentRouteHeaderValue routeHeader) throws WorkflowException {
171         routeHeaderVO.setRouteHeaderId(routeHeader.getRouteHeaderId());
172         routeHeaderVO.setAppDocId(routeHeader.getAppDocId());
173         routeHeaderVO.setDateApproved(Utilities.convertTimestamp(routeHeader.getApprovedDate()));
174         routeHeaderVO.setDateCreated(Utilities.convertTimestamp(routeHeader.getCreateDate()));
175         routeHeaderVO.setDateFinalized(Utilities.convertTimestamp(routeHeader.getFinalizedDate()));
176         routeHeaderVO.setDateLastModified(Utilities.convertTimestamp(routeHeader.getStatusModDate()));
177         routeHeaderVO.setAppDocStatus(routeHeader.getAppDocStatus());
178         routeHeaderVO.setAppDocStatusDate(Utilities.convertTimestamp(routeHeader.getAppDocStatusDate()));
179         
180         /**
181          * This is the original code which set everything up for lazy loading of document content
182          */
183         // by default, a non-initialized document content object will be sent so that it can be fetched lazily
184         // DocumentContentVO documentContentVO = new DocumentContentVO();
185         // documentContentVO.setRouteHeaderId(routeHeader.getRouteHeaderId());
186         // routeHeaderVO.setDocumentContent(documentContentVO);
187         /**
188          * Since we removed the lazy loading in the 2.3 release, this is the code which bypasses lazy loading
189          */
190         // routeHeaderVO.setDocumentContent(convertDocumentContent(routeHeader.getDocContent(),
191         // routeHeader.getRouteHeaderId()));
192         routeHeaderVO.setDocRouteLevel(routeHeader.getDocRouteLevel());
193         routeHeaderVO.setCurrentRouteNodeNames(routeHeader.getCurrentRouteLevelName());
194 
195         /*
196          * Collection activeNodes =
197          * SpringServiceLocator.getRouteNodeService().getActiveNodeInstances(routeHeaderVO.getRouteHeaderId());
198          * routeHeaderVO.setNodeNames(new String[activeNodes.size()]); int index = 0; for (Iterator iterator =
199          * activeNodes.iterator(); iterator.hasNext();) { RouteNodeInstance nodeInstance = (RouteNodeInstance)
200          * iterator.next(); routeHeaderVO.getNodeNames()[index++] = nodeInstance.getRouteNode().getRouteNodeName(); }
201          */
202 
203         routeHeaderVO.setDocRouteStatus(routeHeader.getDocRouteStatus());
204         routeHeaderVO.setDocTitle(routeHeader.getDocTitle());
205         if (routeHeader.getDocumentType() != null) {
206             routeHeaderVO.setDocTypeName(routeHeader.getDocumentType().getName());
207             routeHeaderVO.setDocumentUrl(routeHeader.getDocumentType().getDocHandlerUrl());
208             routeHeaderVO.setDocTypeId(routeHeader.getDocumentTypeId());
209         }
210         routeHeaderVO.setDocVersion(routeHeader.getDocVersion());
211         routeHeaderVO.setInitiatorPrincipalId(routeHeader.getInitiatorWorkflowId());
212         routeHeaderVO.setRoutedByPrincipalId(routeHeader.getRoutedByUserWorkflowId());
213 
214         /* populate the routeHeaderVO with the document variables */
215         // FIXME: we assume there is only one for now
216         Branch routeNodeInstanceBranch = routeHeader.getRootBranch();
217         // Ok, we are using the "branch state" as the arbitrary convenient repository for flow/process/edoc variables
218         // so we need to stuff them into the VO
219         if (routeNodeInstanceBranch != null) {
220             List listOfBranchStates = routeNodeInstanceBranch.getBranchState();
221             Iterator it = listOfBranchStates.iterator();
222             while (it.hasNext()) {
223                 BranchState bs = (BranchState) it.next();
224                 if (bs.getKey() != null && bs.getKey().startsWith(BranchState.VARIABLE_PREFIX)) {
225                     LOG.debug("Setting branch state variable on vo: " + bs.getKey() + "=" + bs.getValue());
226                     routeHeaderVO.setVariable(bs.getKey().substring(BranchState.VARIABLE_PREFIX.length()), bs.getValue());
227                 }
228             }
229         }
230     }
231 
232     public static DocumentRouteHeaderValue convertRouteHeaderVO(RouteHeaderDTO routeHeaderVO) throws WorkflowException {
233         DocumentRouteHeaderValue routeHeader = new DocumentRouteHeaderValue();
234         routeHeader.setAppDocId(routeHeaderVO.getAppDocId());
235         routeHeader.setApprovedDate(Utilities.convertCalendar(routeHeaderVO.getDateApproved()));
236         routeHeader.setCreateDate(Utilities.convertCalendar(routeHeaderVO.getDateCreated()));
237         if (StringUtils.isEmpty(routeHeader.getDocContent())) {
238             routeHeader.setDocContent(KEWConstants.DEFAULT_DOCUMENT_CONTENT);
239         }
240         routeHeader.setDocRouteLevel(routeHeaderVO.getDocRouteLevel());
241         routeHeader.setDocRouteStatus(routeHeaderVO.getDocRouteStatus());
242         routeHeader.setDocTitle(routeHeaderVO.getDocTitle());
243         if (routeHeaderVO.getDocTypeName() != null) {
244             DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(routeHeaderVO.getDocTypeName());
245             if (documentType == null) {
246                 throw new DocumentTypeNotFoundException("Could not locate the given document type name: " + routeHeaderVO.getDocTypeName());
247             }
248             routeHeader.setDocumentTypeId(documentType.getDocumentTypeId());
249         }
250         routeHeader.setDocVersion(routeHeaderVO.getDocVersion());
251         routeHeader.setFinalizedDate(Utilities.convertCalendar(routeHeaderVO.getDateFinalized()));
252         routeHeader.setInitiatorWorkflowId(routeHeaderVO.getInitiatorPrincipalId());
253         routeHeader.setRoutedByUserWorkflowId(routeHeaderVO.getRoutedByPrincipalId());
254         routeHeader.setRouteHeaderId(routeHeaderVO.getRouteHeaderId());
255         routeHeader.setStatusModDate(Utilities.convertCalendar(routeHeaderVO.getDateLastModified()));
256         routeHeader.setAppDocStatus(routeHeaderVO.getAppDocStatus());
257         routeHeader.setAppDocStatusDate(Utilities.convertCalendar(routeHeaderVO.getAppDocStatusDate()));
258 
259         
260         // Convert the variables
261         List<KeyValueDTO> variables = routeHeaderVO.getVariables();
262         if( variables != null && !variables.isEmpty()){
263         	for(KeyValueDTO kvp : variables){
264         		routeHeader.setVariable(kvp.getKey(), kvp.getValue());
265         	}
266         }
267         
268         return routeHeader;
269     }
270 
271     public static ActionItemDTO convertActionItem(ActionItem actionItem) {
272         ActionItemDTO actionItemVO = new ActionItemDTO();
273         actionItemVO.setActionItemId(actionItem.getActionItemId());
274         actionItemVO.setActionItemIndex(actionItem.getActionItemIndex());
275         actionItemVO.setActionRequestCd(actionItem.getActionRequestCd());
276         actionItemVO.setActionRequestId(actionItem.getActionRequestId());
277         actionItemVO.setActionToTake(actionItem.getActionToTake());
278         actionItemVO.setDateAssigned(actionItem.getDateAssigned());
279         actionItemVO.setDateAssignedString(actionItem.getDateAssignedString());
280         actionItemVO.setDelegationType(actionItem.getDelegationType());
281         actionItemVO.setDelegatorPrincipalId(actionItem.getDelegatorWorkflowId());
282         actionItemVO.setDelegatorGroupId(actionItem.getDelegatorGroupId());
283         actionItemVO.setDocHandlerURL(actionItem.getDocHandlerURL());
284         actionItemVO.setDocLabel(actionItem.getDocLabel());
285         actionItemVO.setDocName(actionItem.getDocName());
286         actionItemVO.setDocTitle(actionItem.getDocTitle());
287         actionItemVO.setResponsibilityId(actionItem.getResponsibilityId());
288         actionItemVO.setRoleName(actionItem.getRoleName());
289         actionItemVO.setRouteHeaderId(actionItem.getRouteHeaderId());
290         actionItemVO.setPrincipalId(actionItem.getPrincipalId());
291         actionItemVO.setGroupId(actionItem.getGroupId());
292         return actionItemVO;
293     }
294 
295     /**
296      * Converts the given DocumentContentVO to a document content string. This method considers existing content on the
297      * document and updates approriately. The string returned will be the new document content for the document. If null is
298      * returned, then the document content is unchanged.
299      */
300     public static String buildUpdatedDocumentContent(DocumentContentDTO documentContentVO) throws WorkflowException {
301         DocumentType documentType = null;
302         String documentContent = KEWConstants.DEFAULT_DOCUMENT_CONTENT;
303         try {
304             // parse the existing content on the document
305             String existingDocContent = KEWConstants.DEFAULT_DOCUMENT_CONTENT;
306             if (documentContentVO.getRouteHeaderId() != null) {
307                 DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentContentVO.getRouteHeaderId());
308                 documentType = document.getDocumentType();
309                 existingDocContent = document.getDocContent();
310             }
311             StandardDocumentContent standardDocContent = new StandardDocumentContent(existingDocContent);
312             DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
313             Document document = builder.newDocument();
314             Element root = document.createElement(KEWConstants.DOCUMENT_CONTENT_ELEMENT);
315             document.appendChild(root);
316             Element applicationContentElement = standardDocContent.getApplicationContent();
317             if (documentContentVO.getApplicationContent() != null) {
318                 // application content has changed
319                 if (!Utilities.isEmpty(documentContentVO.getApplicationContent())) {
320                     applicationContentElement = document.createElement(KEWConstants.APPLICATION_CONTENT_ELEMENT);
321                     XmlHelper.appendXml(applicationContentElement, documentContentVO.getApplicationContent());
322                 } else {
323                     // they've cleared the application content
324                     applicationContentElement = null;
325                 }
326             }
327             Element attributeContentElement = createDocumentContentSection(document, standardDocContent.getAttributeContent(), documentContentVO.getAttributeDefinitions(), documentContentVO.getAttributeContent(), KEWConstants.ATTRIBUTE_CONTENT_ELEMENT, documentType);
328             Element searchableContentElement = createDocumentContentSection(document, standardDocContent.getSearchableContent(), documentContentVO.getSearchableDefinitions(), documentContentVO.getSearchableContent(), KEWConstants.SEARCHABLE_CONTENT_ELEMENT, documentType);
329             if (applicationContentElement != null) {
330                 root.appendChild(applicationContentElement);
331             }
332             if (attributeContentElement != null) {
333                 root.appendChild(attributeContentElement);
334             }
335             if (searchableContentElement != null) {
336                 root.appendChild(searchableContentElement);
337             }
338             documentContent = XmlHelper.writeNode(document);
339         } catch (Exception e) {
340             handleException("Error parsing document content.", e);
341         }
342         return documentContent;
343     }
344 
345     private static Element createDocumentContentSection(Document document, Element existingAttributeElement, WorkflowAttributeDefinitionDTO[] definitions, String content, String elementName, DocumentType documentType) throws Exception {
346         Element contentSectionElement = existingAttributeElement;
347         // if they've updated the content, we're going to re-build the content section element from scratch
348         if (content != null) {
349             if (!Utilities.isEmpty(content)) {
350                 contentSectionElement = document.createElement(elementName);
351                 // if they didn't merely clear the content, let's build the content section element by combining the children
352                 // of the incoming XML content
353                 Element incomingAttributeElement = XmlHelper.readXml(content).getDocumentElement();
354                 NodeList children = incomingAttributeElement.getChildNodes();
355                 for (int index = 0; index < children.getLength(); index++) {
356                     contentSectionElement.appendChild(document.importNode(children.item(index), true));
357                 }
358             } else {
359                 contentSectionElement = null;
360             }
361         }
362         // if they have new definitions we're going to append those to the existing content section
363         if (!Utilities.isEmpty(definitions)) {
364             String errorMessage = "";
365             boolean inError = false;
366             if (contentSectionElement == null) {
367                 contentSectionElement = document.createElement(elementName);
368             }
369             for (int index = 0; index < definitions.length; index++) {
370                 WorkflowAttributeDefinitionDTO definitionVO = definitions[index];
371                 AttributeDefinition definition = convertWorkflowAttributeDefinitionVO(definitionVO, documentType);
372                 RuleAttribute ruleAttribute = definition.getRuleAttribute();
373                 Object attribute = GlobalResourceLoader.getResourceLoader().getObject(definition.getObjectDefinition());
374                 boolean propertiesAsMap = false;
375                 if (KEWConstants.RULE_XML_ATTRIBUTE_TYPE.equals(ruleAttribute.getType())) {
376                     ((GenericXMLRuleAttribute) attribute).setRuleAttribute(ruleAttribute);
377                     propertiesAsMap = true;
378                 } else if (KEWConstants.SEARCHABLE_XML_ATTRIBUTE_TYPE.equals(ruleAttribute.getType())) {
379                     ((GenericXMLSearchableAttribute) attribute).setRuleAttribute(ruleAttribute);
380                     propertiesAsMap = true;
381                 }
382                 if (propertiesAsMap) {
383                     for (PropertyDefinitionDTO propertyDefinitionVO : definitionVO.getProperties()) {
384                         if (attribute instanceof GenericXMLRuleAttribute) {
385                             ((GenericXMLRuleAttribute) attribute).getParamMap().put(propertyDefinitionVO.getName(), propertyDefinitionVO.getValue());
386                         } else if (attribute instanceof GenericXMLSearchableAttribute) {
387                             ((GenericXMLSearchableAttribute) attribute).getParamMap().put(propertyDefinitionVO.getName(), propertyDefinitionVO.getValue());
388                         }
389                     }
390                 }
391 
392                 // validate inputs from client application if the attribute is capable
393                 if (attribute instanceof WorkflowAttributeXmlValidator) {
394                     List<WorkflowAttributeValidationError> errors = ((WorkflowAttributeXmlValidator) attribute).validateClientRoutingData();
395                     if (!errors.isEmpty()) {
396                         inError = true;
397                         errorMessage += "Error validating attribute " + definitions[index].getAttributeName() + " ";
398                         for (WorkflowAttributeValidationError error : errors) {
399                             errorMessage += error.getMessage() + " ";
400                         }
401                     }
402                 }
403                 // dont add to xml if attribute is in error
404                 if (!inError) {
405                     if (attribute instanceof WorkflowAttribute) {
406                         String attributeDocContent = ((WorkflowAttribute) attribute).getDocContent();
407                         if (!StringUtils.isEmpty(attributeDocContent)) {
408                             XmlHelper.appendXml(contentSectionElement, attributeDocContent);
409                         }
410                     } else if (attribute instanceof SearchableAttribute) {
411                         String searcheAttributeContent =
412                         	((SearchableAttribute) attribute).getSearchContent(DocSearchUtils.getDocumentSearchContext("", documentType.getName(), ""));
413                         if (!StringUtils.isEmpty(searcheAttributeContent)) {
414                             XmlHelper.appendXml(contentSectionElement, searcheAttributeContent);
415                         }
416                     }
417                 }
418             }
419             if (inError) {
420                 throw new WorkflowRuntimeException(errorMessage);
421             }
422 
423         }
424         if (contentSectionElement != null) {
425             // always be sure and import the element into the new document, if it originated from the existing doc content
426             // and
427             // appended to it, it will need to be imported
428             contentSectionElement = (Element) document.importNode(contentSectionElement, true);
429         }
430         return contentSectionElement;
431     }
432 
433     public static DocumentContentDTO convertDocumentContent(String documentContentValue, Long documentId) throws WorkflowException {
434         if (documentContentValue == null) {
435             return null;
436         }
437         DocumentContentDTO documentContentVO = new DocumentContentDTO();
438         // initialize the content fields
439         documentContentVO.setApplicationContent("");
440         documentContentVO.setAttributeContent("");
441         documentContentVO.setSearchableContent("");
442         documentContentVO.setRouteHeaderId(documentId);
443         try {
444             DocumentContent documentContent = new StandardDocumentContent(documentContentValue);
445             if (documentContent.getApplicationContent() != null) {
446                 documentContentVO.setApplicationContent(XmlHelper.writeNode(documentContent.getApplicationContent()));
447             }
448             if (documentContent.getAttributeContent() != null) {
449                 documentContentVO.setAttributeContent(XmlHelper.writeNode(documentContent.getAttributeContent()));
450             }
451             if (documentContent.getSearchableContent() != null) {
452                 documentContentVO.setSearchableContent(XmlHelper.writeNode(documentContent.getSearchableContent()));
453             }
454         } catch (Exception e) {
455             handleException("Error parsing document content.", e);
456         }
457         return documentContentVO;
458     }
459 
460     public static DocumentTypeDTO convertDocumentType(DocumentType docType) {
461         if (docType == null) {
462             return null;
463         }
464         DocumentTypeDTO docTypeVO = new DocumentTypeDTO();
465         docTypeVO.setDocTypeParentId(docType.getDocTypeParentId());
466         if (docType.getParentDocType() != null) {
467             docTypeVO.setDocTypeParentName(docType.getParentDocType().getName());
468         }
469 
470         docTypeVO.setDocTypeDescription(docType.getDescription());
471         docTypeVO.setDocTypeHandlerUrl(docType.getDocHandlerUrl());
472         docTypeVO.setHelpDefinitionUrl(docType.getHelpDefinitionUrl());
473         docTypeVO.setDocSearchHelpUrl(docType.getDocSearchHelpUrl());
474         docTypeVO.setDocTypeId(docType.getDocumentTypeId());
475         docTypeVO.setDocTypeLabel(docType.getLabel());
476         docTypeVO.setName(docType.getName());
477         docTypeVO.setDocTypeVersion(docType.getVersion());
478         Boolean currentInd = docType.getCurrentInd();
479         if (currentInd == null) {
480             docTypeVO.setDocTypeCurrentInd(null);
481         } else if (currentInd.booleanValue()) {
482             docTypeVO.setDocTypeCurrentInd(KEWConstants.ACTIVE_CD);
483         } else {
484             docTypeVO.setDocTypeCurrentInd(KEWConstants.INACTIVE_CD);
485         }
486         docTypeVO.setPostProcessorName(docType.getPostProcessorName());
487         docTypeVO.setDocTypeJndiFactoryClass(null);
488         docTypeVO.setDocTypeActiveInd(docType.getActive().booleanValue());
489         if (docType.getParentDocType() != null) {
490             docTypeVO.setDocTypeActiveInherited(true);
491         } else {
492             docTypeVO.setDocTypeActiveInherited(false);
493         }     
494         Group blanketGroup = docType.getBlanketApproveWorkgroup();
495         if (blanketGroup != null) {
496             docTypeVO.setBlanketApproveGroupId(blanketGroup.getGroupId());
497         }
498         docTypeVO.setBlanketApprovePolicy(docType.getBlanketApprovePolicy());
499         docTypeVO.setRoutePath(convertRoutePath(docType));
500         return docTypeVO;
501     }
502 
503     public static RoutePathDTO convertRoutePath(DocumentType documentType) {
504         RoutePathDTO routePath = new RoutePathDTO();
505         ProcessDTO[] processes = new ProcessDTO[documentType.getProcesses().size()];
506         int index = 0;
507         for (Iterator iterator = documentType.getProcesses().iterator(); iterator.hasNext();) {
508             Process process = (Process) iterator.next();
509             processes[index++] = convertProcess(process);
510         }
511         routePath.setProcesses(processes);
512         return routePath;
513     }
514 
515     public static ActionRequestDTO convertActionRequest(ActionRequestValue actionRequest) {
516     	return convertActionRequest(actionRequest, true);
517     }
518 
519     protected static ActionRequestDTO convertActionRequest(ActionRequestValue actionRequest, boolean includeActionTaken) {
520         ActionRequestDTO actionRequestVO = new ActionRequestDTO();
521         actionRequestVO.setActionRequested(actionRequest.getActionRequested());
522         actionRequestVO.setActionRequestId(actionRequest.getActionRequestId());
523 
524         if (includeActionTaken && (actionRequest.getActionTaken() != null)) {
525             actionRequestVO.setActionTakenId(actionRequest.getActionTakenId());
526             actionRequestVO.setActionTaken(convertActionTaken(actionRequest.getActionTaken()));
527         }
528 
529         actionRequestVO.setAnnotation(actionRequest.getAnnotation());
530         actionRequestVO.setDateCreated(Utilities.convertTimestamp(actionRequest.getCreateDate()));
531         actionRequestVO.setDocVersion(actionRequest.getDocVersion());
532         actionRequestVO.setPrincipalId(actionRequest.getPrincipalId());
533         actionRequestVO.setForceAction(actionRequest.getForceAction());
534         actionRequestVO.setPriority(actionRequest.getPriority());
535         actionRequestVO.setRecipientTypeCd(actionRequest.getRecipientTypeCd());
536         actionRequestVO.setResponsibilityDesc(actionRequest.getResponsibilityDesc());
537         actionRequestVO.setResponsibilityId(actionRequest.getResponsibilityId());
538         actionRequestVO.setRouteHeaderId(actionRequest.getRouteHeaderId());
539         actionRequestVO.setRouteLevel(actionRequest.getRouteLevel());
540         actionRequestVO.setNodeName(actionRequest.getPotentialNodeName());
541         actionRequestVO.setNodeInstanceId((actionRequest.getNodeInstance() == null ? null : actionRequest.getNodeInstance().getRouteNodeInstanceId()));
542         // TODO delyea - should below be using actionRequest.getRoleName()?
543         actionRequestVO.setRoleName(actionRequest.getQualifiedRoleName());
544         actionRequestVO.setQualifiedRoleName(actionRequest.getQualifiedRoleName());
545         actionRequestVO.setQualifiedRoleNameLabel(actionRequest.getQualifiedRoleNameLabel());
546         actionRequestVO.setStatus(actionRequest.getStatus());
547         actionRequestVO.setGroupId(actionRequest.getGroupId());
548         actionRequestVO.setDelegationType(actionRequest.getDelegationType());
549         actionRequestVO.setParentActionRequestId(actionRequest.getParentActionRequestId());
550         actionRequestVO.setRequestLabel(actionRequest.getRequestLabel());
551         ActionRequestDTO[] childRequestVOs = new ActionRequestDTO[actionRequest.getChildrenRequests().size()];
552         int index = 0;
553         for (ActionRequestValue childRequest : actionRequest.getChildrenRequests()) {
554             ActionRequestDTO childRequestVO = convertActionRequest(childRequest);
555             childRequestVOs[index++] = childRequestVO;
556         }
557         actionRequestVO.setChildrenRequests(childRequestVOs);
558         return actionRequestVO;
559     }
560 
561     public static ActionTakenDTO convertActionTakenWithActionRequests(ActionTakenValue actionTaken) {
562     	return convertActionTaken(actionTaken, true);
563     }
564 
565     public static ActionTakenDTO convertActionTaken(ActionTakenValue actionTaken) {
566     	return convertActionTaken(actionTaken, false);
567     }
568 
569     protected static ActionTakenDTO convertActionTaken(ActionTakenValue actionTaken, boolean fetchActionRequests) {
570         if (actionTaken == null) {
571             return null;
572         }
573         ActionTakenDTO actionTakenVO = new ActionTakenDTO();
574         actionTakenVO.setActionDate(Utilities.convertTimestamp(actionTaken.getActionDate()));
575         actionTakenVO.setActionTaken(actionTaken.getActionTaken());
576         actionTakenVO.setActionTakenId(actionTaken.getActionTakenId());
577         actionTakenVO.setAnnotation(actionTaken.getAnnotation());
578         actionTakenVO.setDocVersion(actionTaken.getDocVersion());
579         actionTakenVO.setRouteHeaderId(actionTaken.getRouteHeaderId());
580         actionTakenVO.setPrincipalId(actionTaken.getPrincipalId());
581         actionTakenVO.setDelegatorPrincpalId(actionTaken.getDelegatorPrincipalId());
582         actionTakenVO.setDelegatorGroupId(actionTaken.getDelegatorGroupId());
583         if (fetchActionRequests) {
584 	        ActionRequestDTO[] actionRequests = new ActionRequestDTO[actionTaken.getActionRequests().size()];
585 	        int index = 0;
586 	        for (Iterator iterator = actionTaken.getActionRequests().iterator(); iterator.hasNext();) {
587 	            ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
588 	            actionRequests[index++] = convertActionRequest(actionRequest, false);
589 	        }
590 	        actionTakenVO.setActionRequests(actionRequests);
591         }
592         return actionTakenVO;
593     }
594 
595     public static ResponsiblePartyDTO convertResponsibleParty(ResponsibleParty responsibleParty) {
596         if (responsibleParty == null) {
597             return null;
598         }
599         ResponsiblePartyDTO responsiblePartyVO = new ResponsiblePartyDTO();
600         responsiblePartyVO.setGroupId(responsibleParty.getGroupId());
601         responsiblePartyVO.setPrincipalId(responsibleParty.getPrincipalId());
602         responsiblePartyVO.setRoleName(responsibleParty.getRoleName());
603         return responsiblePartyVO;
604     }
605 
606     public static ResponsibleParty convertResponsiblePartyVO(ResponsiblePartyDTO responsiblePartyVO) {
607         if (responsiblePartyVO == null) {
608             return null;
609         }
610         ResponsibleParty responsibleParty = new ResponsibleParty();
611         responsibleParty.setGroupId(responsiblePartyVO.getGroupId());
612         responsibleParty.setPrincipalId(responsiblePartyVO.getPrincipalId());
613         responsibleParty.setRoleName(responsiblePartyVO.getRoleName());
614         return responsibleParty;
615     }
616 
617     /**
618      * refactor name to convertResponsiblePartyVO when ResponsibleParty object is gone
619      *
620      * @param responsiblePartyVO
621      * @return
622      */
623     public static Recipient convertResponsiblePartyVOtoRecipient(ResponsiblePartyDTO responsiblePartyVO) {
624         if (responsiblePartyVO == null) {
625             return null;
626         }
627         if (responsiblePartyVO.getRoleName() != null) {
628             return new RoleRecipient(responsiblePartyVO.getRoleName());
629         }
630         String groupId = responsiblePartyVO.getGroupId();
631         if (groupId != null) {
632         	Group group = KIMServiceLocator.getIdentityManagementService().getGroup(groupId);
633         	if (group == null) {
634         		throw new RiceRuntimeException("Failed to locate group with ID: " + groupId);
635         	}
636             return new KimGroupRecipient(group);
637         }
638         String principalId = responsiblePartyVO.getPrincipalId();
639         if (principalId != null) {
640             return new KimPrincipalRecipient(principalId);
641         }
642         throw new WorkflowRuntimeException("ResponsibleParty of unknown type");
643     }
644 
645     /**
646      * Interface for a simple service providing RouteNodeInstanceS based on their IDs 
647      */
648     public static interface RouteNodeInstanceLoader {
649     	RouteNodeInstance load(Long routeNodeInstanceID);
650     }
651     
652     /**
653      * Converts an ActionRequestVO to an ActionRequest. The ActionRequestDTO passed in must be the root action request in the
654      * graph, otherwise an IllegalArgumentException is thrown. This is to avoid potentially sticky issues with circular
655      * references in the conversion. NOTE: This method's primary purpose is to convert ActionRequestVOs returned from a
656      * RouteModule. Incidentally, the DTO's returned from the route module will be lacking some information (like the node
657      * instance) so no attempts are made to convert this data since further initialization is handled by a higher level
658      * component (namely ActionRequestService.initializeActionRequestGraph).
659      */
660     public static ActionRequestValue convertActionRequestDTO(ActionRequestDTO actionRequestDTO) {
661     	return convertActionRequestDTO(actionRequestDTO, null);
662     }
663     
664     /**
665      * Converts an ActionRequestVO to an ActionRequest. The ActionRequestDTO passed in must be the root action request in the
666      * graph, otherwise an IllegalArgumentException is thrown. This is to avoid potentially sticky issues with circular
667      * references in the conversion. 
668      * @param routeNodeInstanceLoader a service that will provide routeNodeInstanceS based on their IDs.
669      */
670     public static ActionRequestValue convertActionRequestDTO(ActionRequestDTO actionRequestDTO, 
671     		RouteNodeInstanceLoader routeNodeInstanceLoader) {
672     	
673         if (actionRequestDTO == null) {
674             return null;
675         }
676         if (actionRequestDTO.getParentActionRequestId() != null) {
677             throw new IllegalArgumentException("Cannot convert a non-root ActionRequestVO");
678         }
679         ActionRequestValue actionRequest = new ActionRequestFactory().createBlankActionRequest();
680         populateActionRequest(actionRequest, actionRequestDTO, routeNodeInstanceLoader);
681         if (actionRequestDTO.getChildrenRequests() != null) {
682             for (int i = 0; i < actionRequestDTO.getChildrenRequests().length; i++) {
683                 ActionRequestDTO childVO = actionRequestDTO.getChildrenRequests()[i];
684                 actionRequest.getChildrenRequests().add(convertActionRequestVO(childVO, actionRequest, routeNodeInstanceLoader));
685             }
686         }
687         return actionRequest;
688     }
689 
690     // TODO: should this be private?  If so, rename to convertActionRequestDTO for consistency.
691     protected static ActionRequestValue convertActionRequestVO(ActionRequestDTO actionRequestDTO, ActionRequestValue parentActionRequest,
692     		RouteNodeInstanceLoader routeNodeInstanceLoader) {
693         if (actionRequestDTO == null) {
694             return null;
695         }
696         ActionRequestValue actionRequest = new ActionRequestFactory().createBlankActionRequest();
697         populateActionRequest(actionRequest, actionRequestDTO, routeNodeInstanceLoader);
698         actionRequest.setParentActionRequest(parentActionRequest);
699         actionRequest.setParentActionRequestId(parentActionRequest.getActionRequestId());
700         if (actionRequestDTO.getChildrenRequests() != null) {
701             for (int i = 0; i < actionRequestDTO.getChildrenRequests().length; i++) {
702                 ActionRequestDTO childVO = actionRequestDTO.getChildrenRequests()[i];
703                 actionRequest.getChildrenRequests().add(convertActionRequestVO(childVO, actionRequest, routeNodeInstanceLoader));
704             }
705         }
706         return actionRequest;
707     }
708 
709     /**
710      * This method converts everything except for the parent and child requests
711      */
712     private static void populateActionRequest(ActionRequestValue actionRequest, ActionRequestDTO actionRequestDTO, 
713     		RouteNodeInstanceLoader routeNodeInstanceLoader) {
714 
715         actionRequest.setActionRequested(actionRequestDTO.getActionRequested());
716         actionRequest.setActionRequestId(actionRequestDTO.getActionRequestId());
717         actionRequest.setActionTakenId(actionRequestDTO.getActionTakenId());
718         actionRequest.setAnnotation(actionRequestDTO.getAnnotation());
719         actionRequest.setApprovePolicy(actionRequestDTO.getApprovePolicy());
720         actionRequest.setCreateDate(new Timestamp(new Date().getTime()));
721         actionRequest.setCurrentIndicator(actionRequestDTO.getCurrentIndicator());
722         actionRequest.setDelegationType(actionRequestDTO.getDelegationType());
723         actionRequest.setDocVersion(actionRequestDTO.getDocVersion());
724         actionRequest.setForceAction(actionRequestDTO.getForceAction());
725         actionRequest.setPriority(actionRequestDTO.getPriority());
726         actionRequest.setQualifiedRoleName(actionRequestDTO.getQualifiedRoleName());
727         actionRequest.setQualifiedRoleNameLabel(actionRequestDTO.getQualifiedRoleNameLabel());
728         actionRequest.setRecipientTypeCd(actionRequestDTO.getRecipientTypeCd());
729         actionRequest.setResponsibilityDesc(actionRequestDTO.getResponsibilityDesc());
730         actionRequest.setResponsibilityId(actionRequestDTO.getResponsibilityId());
731         actionRequest.setRoleName(actionRequestDTO.getRoleName());
732         Long routeHeaderId = actionRequestDTO.getRouteHeaderId();
733         if (routeHeaderId != null) {
734             actionRequest.setRouteHeaderId(routeHeaderId);
735             actionRequest.setRouteHeader(KEWServiceLocator.getRouteHeaderService().getRouteHeader(routeHeaderId));
736         }
737         actionRequest.setRouteLevel(actionRequestDTO.getRouteLevel());
738 
739         actionRequest.setStatus(actionRequestDTO.getStatus());
740         actionRequest.setPrincipalId(actionRequestDTO.getPrincipalId());
741         actionRequest.setGroupId(actionRequestDTO.getGroupId());
742         
743         if (routeNodeInstanceLoader != null && actionRequestDTO.getNodeInstanceId() != null) {
744         	actionRequest.setNodeInstance(routeNodeInstanceLoader.load(actionRequestDTO.getNodeInstanceId()));
745         }
746     }
747 
748     public static ActionTakenValue convertActionTakenVO(ActionTakenDTO actionTakenVO) {
749         if (actionTakenVO == null) {
750             return null;
751         }
752         ActionTakenValue actionTaken = new ActionTakenValue();
753         actionTaken.setActionDate(new Timestamp(actionTakenVO.getActionDate().getTimeInMillis()));
754         actionTaken.setActionTaken(actionTakenVO.getActionTaken());
755         actionTaken.setActionTakenId(actionTakenVO.getActionTakenId());
756         actionTaken.setAnnotation(actionTakenVO.getAnnotation());
757         actionTaken.setCurrentIndicator(Boolean.TRUE);
758         actionTaken.setPrincipalId(actionTakenVO.getPrincipalId());
759         actionTaken.setDelegatorPrincipalId(actionTakenVO.getDelegatorPrincpalId());
760         actionTaken.setDelegatorGroupId(actionTakenVO.getDelegatorGroupId());
761         actionTaken.setDocVersion(actionTakenVO.getDocVersion());
762         DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(actionTakenVO.getRouteHeaderId());
763         actionTaken.setRouteHeader(routeHeader);
764         actionTaken.setRouteHeaderId(actionTaken.getRouteHeaderId());
765         return actionTaken;
766     }
767 
768     public static DocumentRouteStatusChangeDTO convertDocumentRouteStatusChange(DocumentRouteStatusChange statusChange) {
769         if (statusChange == null) {
770             return null;
771         }
772         DocumentRouteStatusChangeDTO statusChangeVO = new DocumentRouteStatusChangeDTO();
773         statusChangeVO.setRouteHeaderId(statusChange.getRouteHeaderId());
774         statusChangeVO.setAppDocId(statusChange.getAppDocId());
775         statusChangeVO.setOldRouteStatus(statusChange.getOldRouteStatus());
776         statusChangeVO.setNewRouteStatus(statusChange.getNewRouteStatus());
777         return statusChangeVO;
778     }
779 
780     public static DocumentRouteLevelChangeDTO convertDocumentRouteLevelChange(DocumentRouteLevelChange routeLevelChange) {
781         if (routeLevelChange == null) {
782             return null;
783         }
784         DocumentRouteLevelChangeDTO routeLevelChangeVO = new DocumentRouteLevelChangeDTO();
785         routeLevelChangeVO.setRouteHeaderId(routeLevelChange.getRouteHeaderId());
786         routeLevelChangeVO.setAppDocId(routeLevelChange.getAppDocId());
787         routeLevelChangeVO.setOldRouteLevel(routeLevelChange.getOldRouteLevel());
788         routeLevelChangeVO.setNewRouteLevel(routeLevelChange.getNewRouteLevel());
789         routeLevelChangeVO.setOldNodeName(routeLevelChange.getOldNodeName());
790         routeLevelChangeVO.setNewNodeName(routeLevelChange.getNewNodeName());
791         routeLevelChangeVO.setOldNodeInstanceId(routeLevelChange.getOldNodeInstanceId());
792         routeLevelChangeVO.setNewNodeInstanceId(routeLevelChange.getNewNodeInstanceId());
793         return routeLevelChangeVO;
794     }
795 
796     public static DeleteEventDTO convertDeleteEvent(DeleteEvent deleteEvent) {
797         if (deleteEvent == null) {
798             return null;
799         }
800         DeleteEventDTO deleteEventVO = new DeleteEventDTO();
801         deleteEventVO.setRouteHeaderId(deleteEvent.getRouteHeaderId());
802         deleteEventVO.setAppDocId(deleteEvent.getAppDocId());
803         return deleteEventVO;
804     }
805 
806     public static ActionTakenEventDTO convertActionTakenEvent(ActionTakenEvent actionTakenEvent) {
807         if (actionTakenEvent == null) {
808             return null;
809         }
810         ActionTakenEventDTO actionTakenEventVO = new ActionTakenEventDTO();
811         actionTakenEventVO.setRouteHeaderId(actionTakenEvent.getRouteHeaderId());
812         actionTakenEventVO.setAppDocId(actionTakenEvent.getAppDocId());
813         actionTakenEventVO.setActionTaken(convertActionTaken(actionTakenEvent.getActionTaken()));
814         return actionTakenEventVO;
815     }
816 
817     public static BeforeProcessEventDTO convertBeforeProcessEvent(BeforeProcessEvent event) {
818         if (event == null) {
819             return null;
820         }
821         BeforeProcessEventDTO beforeProcessEvent = new BeforeProcessEventDTO();
822         beforeProcessEvent.setRouteHeaderId(event.getRouteHeaderId());
823         beforeProcessEvent.setAppDocId(event.getAppDocId());
824         beforeProcessEvent.setNodeInstanceId(event.getNodeInstanceId());
825         return beforeProcessEvent;
826     }
827 
828     public static AfterProcessEventDTO convertAfterProcessEvent(AfterProcessEvent event) {
829         if (event == null) {
830             return null;
831         }
832         AfterProcessEventDTO afterProcessEvent = new AfterProcessEventDTO();
833         afterProcessEvent.setRouteHeaderId(event.getRouteHeaderId());
834         afterProcessEvent.setAppDocId(event.getAppDocId());
835         afterProcessEvent.setNodeInstanceId(event.getNodeInstanceId());
836         afterProcessEvent.setSuccessfullyProcessed(event.isSuccessfullyProcessed());
837         return afterProcessEvent;
838     }
839 
840     public static DocumentLockingEventDTO convertDocumentLockingEvent(DocumentLockingEvent event) {
841         if (event == null) {
842             return null;
843         }
844         DocumentLockingEventDTO documentLockingEvent = new DocumentLockingEventDTO();
845         documentLockingEvent.setRouteHeaderId(event.getRouteHeaderId());
846         documentLockingEvent.setAppDocId(event.getAppDocId());
847         return documentLockingEvent;
848     }
849 
850     
851     public static AttributeDefinition convertWorkflowAttributeDefinitionVO(WorkflowAttributeDefinitionDTO definitionVO, org.kuali.rice.kew.doctype.bo.DocumentType documentType) {
852         if (definitionVO == null) {
853             return null;
854         }
855         // get the rule attribute so we can get's it's message antity and not blow up if it's remote
856         RuleAttribute ruleAttribute = KEWServiceLocator.getRuleAttributeService().findByClassName(definitionVO.getAttributeName());
857         if (ruleAttribute == null) {
858             ruleAttribute = KEWServiceLocator.getRuleAttributeService().findByName(definitionVO.getAttributeName());
859         }
860         if (ruleAttribute == null) {
861             throw new WorkflowRuntimeException("Attribute " + definitionVO.getAttributeName() + " not found");
862         }
863 
864         ObjectDefinition definition = new ObjectDefinition(ruleAttribute.getClassName());
865         for (int index = 0; index < definitionVO.getConstructorParameters().length; index++) {
866             String parameter = definitionVO.getConstructorParameters()[index];
867             definition.addConstructorParameter(new DataDefinition(parameter, String.class));
868         }
869         boolean propertiesAsMap = KEWConstants.RULE_XML_ATTRIBUTE_TYPE.equals(ruleAttribute.getType()) || KEWConstants.SEARCHABLE_XML_ATTRIBUTE_TYPE.equals(ruleAttribute.getType());
870         if (!propertiesAsMap) {
871             for (int index = 0; index < definitionVO.getProperties().length; index++) {
872                 PropertyDefinitionDTO propertyDefVO = definitionVO.getProperties()[index];
873                 definition.addProperty(new PropertyDefinition(propertyDefVO.getName(), new DataDefinition(propertyDefVO.getValue(), String.class)));
874             }
875         }
876 
877         // this is likely from an EDL validate call and ME may needed to be added to the AttDefinitionVO.
878         if (ruleAttribute.getServiceNamespace() != null) {
879             definition.setServiceNamespace(ruleAttribute.getServiceNamespace());
880         } else {
881             // get the me from the document type if it's been passed in - the document is having action taken on it.
882             if (documentType != null) {
883                 definition.setServiceNamespace(documentType.getServiceNamespace());
884             }
885         }
886 
887         return new AttributeDefinition(ruleAttribute, definition);
888     }
889 
890     public static DocumentDetailDTO convertDocumentDetail(DocumentRouteHeaderValue routeHeader) throws WorkflowException {
891         if (routeHeader == null) {
892             return null;
893         }
894         DocumentDetailDTO detail = new DocumentDetailDTO();
895         populateRouteHeaderVO(detail, routeHeader);
896         Map nodeInstances = new HashMap();
897         List actionRequestVOs = new ArrayList();
898         List rootActionRequests = KEWServiceLocator.getActionRequestService().getRootRequests(routeHeader.getActionRequests());
899         for (Iterator iterator = rootActionRequests.iterator(); iterator.hasNext();) {
900             ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
901             actionRequestVOs.add(convertActionRequest(actionRequest));
902             RouteNodeInstance nodeInstance = actionRequest.getNodeInstance();
903             if (nodeInstance == null) {
904                 continue;
905             }
906             if (nodeInstance.getRouteNodeInstanceId() == null) {
907                 throw new WorkflowException("Error creating document detail structure because of NULL node instance id.");
908             }
909             nodeInstances.put(nodeInstance.getRouteNodeInstanceId(), nodeInstance);
910         }
911         detail.setActionRequests((ActionRequestDTO[]) actionRequestVOs.toArray(new ActionRequestDTO[0]));
912         List nodeInstanceVOs = new ArrayList();
913         for (Iterator iterator = nodeInstances.values().iterator(); iterator.hasNext();) {
914             RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator.next();
915             nodeInstanceVOs.add(convertRouteNodeInstance(nodeInstance));
916         }
917         detail.setNodeInstances((RouteNodeInstanceDTO[]) nodeInstanceVOs.toArray(new RouteNodeInstanceDTO[0]));
918         List actionTakenVOs = new ArrayList();
919         for (Iterator iterator = routeHeader.getActionsTaken().iterator(); iterator.hasNext();) {
920             ActionTakenValue actionTaken = (ActionTakenValue) iterator.next();
921             actionTakenVOs.add(convertActionTaken(actionTaken));
922         }
923         detail.setActionsTaken((ActionTakenDTO[]) actionTakenVOs.toArray(new ActionTakenDTO[0]));
924         return detail;
925     }
926 
927     public static RouteNodeInstanceDTO convertRouteNodeInstance(RouteNodeInstance nodeInstance) throws WorkflowException {
928         if (nodeInstance == null) {
929             return null;
930         }
931         RouteNodeInstanceDTO nodeInstanceVO = new RouteNodeInstanceDTO();
932         nodeInstanceVO.setActive(nodeInstance.isActive());
933         nodeInstanceVO.setBranchId(nodeInstance.getBranch().getBranchId());
934         nodeInstanceVO.setComplete(nodeInstance.isComplete());
935         nodeInstanceVO.setDocumentId(nodeInstance.getDocumentId());
936         nodeInstanceVO.setInitial(nodeInstance.isInitial());
937         nodeInstanceVO.setName(nodeInstance.getName());
938         nodeInstanceVO.setProcessId(nodeInstance.getProcess() != null ? nodeInstance.getProcess().getRouteNodeInstanceId() : null);
939         nodeInstanceVO.setRouteNodeId(nodeInstance.getRouteNode().getRouteNodeId());
940         nodeInstanceVO.setRouteNodeInstanceId(nodeInstance.getRouteNodeInstanceId());
941         nodeInstanceVO.setState(convertStates(nodeInstance.getState()));
942 
943         nodeInstanceVO.setNextNodes(new RouteNodeInstanceDTO[nodeInstance.getNextNodeInstances().size()]);
944         int i = 0;
945         for (Iterator iter = nodeInstance.getNextNodeInstances().iterator(); iter.hasNext(); i++) {
946             RouteNodeInstance nextNodeInstance = (RouteNodeInstance) iter.next();
947             nodeInstanceVO.getNextNodes()[i] = convertRouteNodeInstance(nextNodeInstance);
948         }
949 
950         return nodeInstanceVO;
951     }
952 
953     public static StateDTO[] convertStates(Collection states) {
954         if (states == null) {
955             return null;
956         }
957         StateDTO[] stateVOs = new StateDTO[states.size()];
958         int index = 0;
959         for (Iterator iterator = states.iterator(); iterator.hasNext();) {
960             State state = (State) iterator.next();
961             stateVOs[index++] = convertState(state);
962         }
963         return stateVOs;
964     }
965 
966     public static StateDTO convertState(State nodeState) {
967         if (nodeState == null) {
968             return null;
969         }
970         StateDTO stateVO = new StateDTO();
971         stateVO.setStateId(nodeState.getStateId());
972         stateVO.setKey(nodeState.getKey());
973         stateVO.setValue(nodeState.getValue());
974         return stateVO;
975     }
976 
977     public static RouteNodeDTO convertRouteNode(RouteNode node) {
978         if (node == null) {
979             return null;
980         }
981         RouteNodeDTO nodeVO = new RouteNodeDTO();
982         nodeVO.setActivationType(node.getActivationType());
983         nodeVO.setBranchName(node.getBranch() != null ? node.getBranch().getName() : null);
984         nodeVO.setDocumentTypeId(node.getDocumentTypeId());
985         nodeVO.setExceptionGroupId(node.getExceptionWorkgroupId());
986         nodeVO.setFinalApprovalInd(node.getFinalApprovalInd().booleanValue());
987         nodeVO.setMandatoryRouteInd(node.getMandatoryRouteInd().booleanValue());
988         nodeVO.setNodeType(node.getNodeType());
989         nodeVO.setRouteMethodCode(node.getRouteMethodCode());
990         nodeVO.setRouteMethodName(node.getRouteMethodName());
991         nodeVO.setRouteNodeId(node.getRouteNodeId());
992         nodeVO.setRouteNodeName(node.getRouteNodeName());
993         int index = 0;
994         Long[] previousNodeIds = new Long[node.getPreviousNodes().size()];
995         for (Iterator iterator = node.getPreviousNodes().iterator(); iterator.hasNext();) {
996             RouteNode prevNode = (RouteNode) iterator.next();
997             previousNodeIds[index++] = prevNode.getRouteNodeId();
998         }
999         nodeVO.setPreviousNodeIds(previousNodeIds);
1000         index = 0;
1001         Long[] nextNodeIds = new Long[node.getNextNodes().size()];
1002         for (Iterator iterator = node.getNextNodes().iterator(); iterator.hasNext();) {
1003             RouteNode nextNode = (RouteNode) iterator.next();
1004             nextNodeIds[index++] = nextNode.getRouteNodeId();
1005         }
1006         nodeVO.setNextNodeIds(nextNodeIds);
1007         return nodeVO;
1008     }
1009 
1010     public static ProcessDTO convertProcess(Process process) {
1011         ProcessDTO processVO = new ProcessDTO();
1012         processVO.setInitial(process.isInitial());
1013         processVO.setInitialRouteNode(convertRouteNode(process.getInitialRouteNode()));
1014         processVO.setName(process.getName());
1015         processVO.setProcessId(process.getProcessId());
1016         return processVO;
1017     }
1018 
1019     public static MovePoint convertMovePointVO(MovePointDTO movePointVO) {
1020         MovePoint movePoint = new MovePoint();
1021         movePoint.setStartNodeName(movePointVO.getStartNodeName());
1022         movePoint.setStepsToMove(movePointVO.getStepsToMove());
1023         return movePoint;
1024     }
1025 
1026     public static AdHocRevoke convertAdHocRevokeVO(AdHocRevokeDTO revokeVO) throws WorkflowException {
1027         AdHocRevoke revoke = new AdHocRevoke();
1028         revoke.setActionRequestId(revokeVO.getActionRequestId());
1029         revoke.setNodeName(revokeVO.getNodeName());
1030         revoke.setPrincipalId(revokeVO.getPrincipalId());
1031         revoke.setGroupId(revokeVO.getGroupId());
1032         return revoke;
1033     }
1034 
1035     public static WorkflowAttributeValidationErrorDTO convertWorkflowAttributeValidationError(WorkflowAttributeValidationError error) {
1036         return new WorkflowAttributeValidationErrorDTO(error.getKey(), error.getMessage());
1037     }
1038 
1039     // Method added for updating notes on server sites based on NoteVO change. Modfy on April 7, 2006
1040     public static void updateNotes(RouteHeaderDTO routeHeaderVO, Long routeHeaderId) {
1041         NoteDTO[] notes = routeHeaderVO.getNotes();
1042         NoteDTO[] notesToDelete = routeHeaderVO.getNotesToDelete();
1043         Note noteToDelete = null;
1044         Note noteToSave = null;
1045 
1046         // Add or update notes to note table based on notes array in RouteHeaderVO
1047         if (notes != null) {
1048             for (int i = 0; i < notes.length; i++) {
1049                 if (notes[i] != null) {
1050                     noteToSave = new Note();
1051                     noteToSave.setNoteId(notes[i].getNoteId());
1052                     noteToSave.setRouteHeaderId(routeHeaderId);
1053                     noteToSave.setNoteAuthorWorkflowId(notes[i].getNoteAuthorWorkflowId());
1054                     noteToSave.setNoteCreateDate(Utilities.convertCalendar(notes[i].getNoteCreateDate()));
1055                     noteToSave.setNoteText(notes[i].getNoteText());
1056                     noteToSave.setLockVerNbr(notes[i].getLockVerNbr());
1057                     // if notes[i].getNoteId() == null, add note to note table, otherwise update note to note table
1058                     getNoteService().saveNote(noteToSave);
1059                 }
1060             }
1061 
1062         }
1063 
1064         // Delete notes from note table based on notesToDelete array in RouteHeaderVO
1065         if (notesToDelete != null) {
1066             for (int i = 0; i < notesToDelete.length; i++) {
1067                 noteToDelete = getNoteService().getNoteByNoteId(notesToDelete[i].getNoteId());
1068                 if (noteToDelete != null) {
1069                     getNoteService().deleteNote(noteToDelete);
1070                 }
1071             }
1072             routeHeaderVO.setNotesToDelete(null);
1073         }
1074     }
1075 
1076     private static NoteService getNoteService() {
1077         return (NoteService) KEWServiceLocator.getService(KEWServiceLocator.NOTE_SERVICE);
1078     }
1079 
1080     private static NoteDTO[] convertNotesArrayListToNoteVOArray(List notesArrayList) {
1081         if (notesArrayList.size() > 0) {
1082             NoteDTO[] noteVOArray = new NoteDTO[notesArrayList.size()];
1083             int i = 0;
1084             Note tempNote;
1085             NoteDTO tempNoteVO;
1086             for (Iterator it = notesArrayList.iterator(); it.hasNext();) {
1087                 tempNote = (Note) it.next();
1088                 tempNoteVO = new NoteDTO();
1089                 tempNoteVO.setNoteId(tempNote.getNoteId());
1090                 tempNoteVO.setRouteHeaderId(tempNote.getRouteHeaderId());
1091                 tempNoteVO.setNoteAuthorWorkflowId(tempNote.getNoteAuthorWorkflowId());
1092                 tempNoteVO.setNoteCreateDate(Utilities.convertTimestamp(tempNote.getNoteCreateDate()));
1093                 tempNoteVO.setNoteText(tempNote.getNoteText());
1094                 tempNoteVO.setLockVerNbr(tempNote.getLockVerNbr());
1095                 noteVOArray[i] = tempNoteVO;
1096                 i++;
1097             }
1098             return noteVOArray;
1099         } else {
1100             return null;
1101         }
1102     }
1103 
1104     public static SimulationCriteria convertReportCriteriaDTO(ReportCriteriaDTO criteriaVO) {
1105         if (criteriaVO == null) {
1106             return null;
1107         }
1108         SimulationCriteria criteria = new SimulationCriteria();
1109         criteria.setDestinationNodeName(criteriaVO.getTargetNodeName());
1110         criteria.setDocumentId(criteriaVO.getRouteHeaderId());
1111         criteria.setDocumentTypeName(criteriaVO.getDocumentTypeName());
1112         criteria.setXmlContent(criteriaVO.getXmlContent());
1113         criteria.setActivateRequests(criteriaVO.getActivateRequests());
1114         criteria.setFlattenNodes(criteriaVO.isFlattenNodes());
1115         if (criteriaVO.getRoutingPrincipalId() != null) {
1116         	KimPrincipal kPrinc = KEWServiceLocator.getIdentityHelperService().getPrincipal(criteriaVO.getRoutingPrincipalId());
1117             Person user = KIMServiceLocator.getPersonService().getPerson(kPrinc.getPrincipalId());
1118             if (user == null) {
1119                 throw new RiceRuntimeException("Could not locate user for the given id: " + criteriaVO.getRoutingPrincipalId());
1120             }
1121             criteria.setRoutingUser(user);
1122         }
1123         if (criteriaVO.getRuleTemplateNames() != null) {
1124             for (int index = 0; index < criteriaVO.getRuleTemplateNames().length; index++) {
1125                 String ruleTemplateName = criteriaVO.getRuleTemplateNames()[index];
1126                 criteria.getRuleTemplateNames().add(ruleTemplateName);
1127             }
1128         }
1129         if (criteriaVO.getNodeNames() != null) {
1130             for (int i = 0; i < criteriaVO.getNodeNames().length; i++) {
1131                 String nodeName = criteriaVO.getNodeNames()[i];
1132                 criteria.getNodeNames().add(nodeName);
1133             }
1134         }
1135         if (criteriaVO.getTargetPrincipalIds() != null) {
1136             for (String targetPrincipalId : criteriaVO.getTargetPrincipalIds()) {
1137                 KimPrincipal principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(targetPrincipalId);
1138                 criteria.getDestinationRecipients().add(new KimPrincipalRecipient(principal));
1139             }
1140         }
1141         if (criteriaVO.getActionsToTake() != null) {
1142             for (int index = 0; index < criteriaVO.getActionsToTake().length; index++) {
1143                 ReportActionToTakeDTO actionToTakeVO = criteriaVO.getActionsToTake()[index];
1144                 criteria.getActionsToTake().add(convertReportActionToTakeVO(actionToTakeVO));
1145             }
1146         }
1147         return criteria;
1148     }
1149 
1150     public static SimulationActionToTake convertReportActionToTakeVO(ReportActionToTakeDTO actionToTakeVO) {
1151         if (actionToTakeVO == null) {
1152             return null;
1153         }
1154         SimulationActionToTake actionToTake = new SimulationActionToTake();
1155         actionToTake.setNodeName(actionToTakeVO.getNodeName());
1156         if (StringUtils.isBlank(actionToTakeVO.getActionToPerform())) {
1157             throw new IllegalArgumentException("ReportActionToTakeVO must contain an action taken code and does not");
1158         }
1159         actionToTake.setActionToPerform(actionToTakeVO.getActionToPerform());
1160         if (actionToTakeVO.getPrincipalId() == null) {
1161             throw new IllegalArgumentException("ReportActionToTakeVO must contain a principalId and does not");
1162         }
1163         KimPrincipal kPrinc = KEWServiceLocator.getIdentityHelperService().getPrincipal(actionToTakeVO.getPrincipalId());
1164         Person user = KIMServiceLocator.getPersonService().getPerson(kPrinc.getPrincipalId());
1165         if (user == null) {
1166             throw new RiceRuntimeException("Could not locate Person for the given id: " + actionToTakeVO.getPrincipalId());
1167         }
1168         actionToTake.setUser(user);
1169         return actionToTake;
1170     }
1171 
1172     public static RuleDelegationDTO convertRuleDelegation(RuleDelegation ruleDelegation) throws WorkflowException {
1173         if (ruleDelegation == null) {
1174             return null;
1175         }
1176         RuleDelegationDTO ruleDelegationVO = new RuleDelegationDTO();
1177         ruleDelegationVO.setDelegationType(ruleDelegation.getDelegationType());
1178         ruleDelegationVO.setDelegationRule(convertRule(ruleDelegation.getDelegationRuleBaseValues()));
1179         return ruleDelegationVO;
1180     }
1181 
1182     // public static RuleDelegation convertRuleExtensionVO(RuleExtensionVO ruleExtensionVO) throws WorkflowException {}
1183 
1184     public static Collection<RuleExtensionDTO> convertRuleExtension(RuleExtension ruleExtension) throws WorkflowException {
1185         if (ruleExtension == null) {
1186             return null;
1187         }
1188         List<RuleExtensionDTO> extensionVOs = new ArrayList<RuleExtensionDTO>();
1189         for (Iterator iter = ruleExtension.getExtensionValues().iterator(); iter.hasNext();) {
1190             RuleExtensionValue extensionValue = (RuleExtensionValue) iter.next();
1191             extensionVOs.add(new RuleExtensionDTO(extensionValue.getKey(), extensionValue.getValue()));
1192         }
1193         return extensionVOs;
1194     }
1195 
1196     public static KeyValuePair convertRuleExtensionVO(RuleExtensionDTO ruleExtensionVO) throws WorkflowException {
1197         if (ruleExtensionVO == null) {
1198             return null;
1199         }
1200         return new KeyValuePair(ruleExtensionVO.getKey(), ruleExtensionVO.getValue());
1201     }
1202 
1203     public static RuleResponsibilityDTO convertRuleResponsibility(RuleResponsibility ruleResponsibility) throws WorkflowException {
1204         if (ruleResponsibility == null) {
1205             return null;
1206         }
1207         RuleResponsibilityDTO ruleResponsibilityVO = new RuleResponsibilityDTO();
1208         ruleResponsibilityVO.setActionRequestedCd(ruleResponsibility.getActionRequestedCd());
1209         ruleResponsibilityVO.setApprovePolicy(ruleResponsibility.getApprovePolicy());
1210         ruleResponsibilityVO.setPriority(ruleResponsibility.getPriority());
1211         ruleResponsibilityVO.setResponsibilityId(ruleResponsibility.getResponsibilityId());
1212         ruleResponsibilityVO.setRoleName(ruleResponsibility.getRole());
1213         if (ruleResponsibility.getPrincipal() != null) {
1214         	ruleResponsibilityVO.setPrincipalId(ruleResponsibility.getPrincipal().getPrincipalId());
1215         } else if (ruleResponsibility.getGroup() != null) {
1216         	ruleResponsibilityVO.setGroupId(ruleResponsibility.getGroup().getGroupId());
1217         } else if (ruleResponsibility.getRole() != null) {
1218         	ruleResponsibilityVO.setRoleName(ruleResponsibility.getRole());
1219         }
1220         for (Iterator iter = ruleResponsibility.getDelegationRules().iterator(); iter.hasNext();) {
1221             RuleDelegation ruleDelegation = (RuleDelegation) iter.next();
1222             ruleResponsibilityVO.addDelegationRule(convertRuleDelegation(ruleDelegation));
1223         }
1224         return ruleResponsibilityVO;
1225     }
1226 
1227     // public static KeyValuePair convertRuleResponsibilityVO(RuleResponsibilityVO ruleResponsibilityVO) throws
1228     // WorkflowException {}
1229 
1230     public static RuleDTO convertRule(RuleBaseValues ruleValues) throws WorkflowException {
1231         if (ruleValues == null) {
1232             return null;
1233         }
1234         RuleDTO rule = new RuleDTO();
1235         rule.setActiveInd(ruleValues.getActiveInd());
1236         rule.setDescription(ruleValues.getDescription());
1237         rule.setDocTypeName(ruleValues.getDocTypeName());
1238         rule.setFromDate(ruleValues.getFromDateString());
1239         rule.setToDate(ruleValues.getToDateString());
1240         rule.setForceAction(ruleValues.getForceAction());
1241         rule.setRuleTemplateId(ruleValues.getRuleTemplateId());
1242         rule.setRuleTemplateName(ruleValues.getRuleTemplateName());
1243 
1244         // get keyPair values to setup RuleExtensionVOs
1245         for (Iterator iter = ruleValues.getRuleExtensions().iterator(); iter.hasNext();) {
1246             RuleExtension ruleExtension = (RuleExtension) iter.next();
1247             rule.addRuleExtensions(convertRuleExtension(ruleExtension));
1248         }
1249         // get keyPair values to setup RuleExtensionVOs
1250         for (Iterator iter = ruleValues.getResponsibilities().iterator(); iter.hasNext();) {
1251             RuleResponsibility ruleResponsibility = (RuleResponsibility) iter.next();
1252             rule.addRuleResponsibility(convertRuleResponsibility(ruleResponsibility));
1253         }
1254         return rule;
1255     }
1256 
1257     public static DocSearchCriteriaDTO convertDocumentSearchCriteriaDTO(DocumentSearchCriteriaDTO criteriaVO) throws WorkflowException {
1258         DocSearchCriteriaDTO criteria = new DocSearchCriteriaDTO();
1259         criteria.setAppDocId(criteriaVO.getAppDocId());
1260         criteria.setApprover(criteriaVO.getApprover());
1261         criteria.setDocRouteStatus(criteriaVO.getDocRouteStatus());
1262         criteria.setDocTitle(criteriaVO.getDocTitle());
1263         criteria.setDocTypeFullName(criteriaVO.getDocTypeFullName());
1264         criteria.setDocVersion(criteriaVO.getDocVersion());
1265         criteria.setFromDateApproved(criteriaVO.getFromDateApproved());
1266         criteria.setFromDateCreated(criteriaVO.getFromDateCreated());
1267         criteria.setFromDateFinalized(criteriaVO.getFromDateFinalized());
1268         criteria.setFromDateLastModified(criteriaVO.getFromDateLastModified());
1269         criteria.setInitiator(criteriaVO.getInitiator());
1270         criteria.setIsAdvancedSearch((criteriaVO.isAdvancedSearch()) ? DocSearchCriteriaDTO.ADVANCED_SEARCH_INDICATOR_STRING : "NO");
1271         criteria.setSuperUserSearch((criteriaVO.isSuperUserSearch()) ? DocSearchCriteriaDTO.SUPER_USER_SEARCH_INDICATOR_STRING : "NO");
1272         criteria.setRouteHeaderId(criteriaVO.getRouteHeaderId());
1273         criteria.setViewer(criteriaVO.getViewer());
1274         criteria.setWorkgroupViewerName(criteriaVO.getGroupViewerName());
1275         criteria.setToDateApproved(criteriaVO.getToDateApproved());
1276         criteria.setToDateCreated(criteriaVO.getToDateCreated());
1277         criteria.setToDateFinalized(criteriaVO.getToDateFinalized());
1278         criteria.setToDateLastModified(criteriaVO.getToDateLastModified());
1279         criteria.setThreshold(criteriaVO.getThreshold());
1280         criteria.setSaveSearchForUser(criteriaVO.isSaveSearchForUser());
1281 
1282         // generate the route node criteria
1283         if ( (StringUtils.isNotBlank(criteriaVO.getDocRouteNodeName())) && (StringUtils.isBlank(criteriaVO.getDocTypeFullName())) ) {
1284             throw new WorkflowException("No document type name specified when attempting to search by route node name '" + criteriaVO.getDocRouteNodeName() + "'");
1285         } else if ( (StringUtils.isNotBlank(criteriaVO.getDocRouteNodeName())) && (StringUtils.isNotBlank(criteriaVO.getDocTypeFullName())) ) {
1286             criteria.setDocRouteNodeLogic(criteriaVO.getDocRouteNodeLogic());
1287             List routeNodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodes(getDocumentTypeByName(criteria.getDocTypeFullName()), true);
1288             boolean foundRouteNode = false;
1289             for (Iterator iterator = routeNodes.iterator(); iterator.hasNext();) {
1290                 RouteNode routeNode = (RouteNode) iterator.next();
1291                 if (criteriaVO.getDocRouteNodeName().equals(routeNode.getRouteNodeName())) {
1292                     foundRouteNode = true;
1293                     break;
1294                 }
1295             }
1296             if (!foundRouteNode) {
1297                 throw new WorkflowException("Could not find route node name '" + criteriaVO.getDocRouteNodeName() + "' for document type name '" + criteriaVO.getDocTypeFullName() + "'");
1298             }
1299             criteria.setDocRouteNodeId(criteriaVO.getDocRouteNodeName());
1300         }
1301 
1302         // build a map of the search attributes passed in from the client creating lists where keys are duplicated
1303         HashMap<String, List<String>> searchAttributeValues = new HashMap<String,List<String>>();
1304         for (KeyValueDTO keyValueVO : criteriaVO.getSearchAttributeValues()) {
1305             if (searchAttributeValues.containsKey(keyValueVO.getKey())) {
1306                 searchAttributeValues.get(keyValueVO.getKey()).add(keyValueVO.getValue());
1307             } else {
1308                 searchAttributeValues.put(keyValueVO.getKey(), Arrays.asList(new String[]{keyValueVO.getValue()}));
1309             }
1310         }
1311         // build the list of SearchAttributeFormContainer objects
1312         List propertyFields = new ArrayList();
1313         for (String key : searchAttributeValues.keySet()) {
1314             List<String> values = searchAttributeValues.get(key);
1315             SearchAttributeFormContainer container = null;
1316             if (values.size() == 1) {
1317                 container = new SearchAttributeFormContainer(key, values.get(0));
1318             } else if (values.size() > 1) {
1319                 container = new SearchAttributeFormContainer(key, (String[])values.toArray());
1320             }
1321             if (container != null) {
1322                 propertyFields.add(container);
1323             }
1324         }
1325         DocSearchUtils.addSearchableAttributesToCriteria(criteria, propertyFields, true);
1326         return criteria;
1327     }
1328 
1329     private static DocumentType getDocumentTypeByName(String documentTypeName) {
1330         return KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
1331     }
1332 
1333     public static DocumentSearchResultDTO convertDocumentSearchResultComponents(DocumentSearchResultComponents searchResult) throws WorkflowException {
1334         DocumentSearchResultDTO resultsVO = new DocumentSearchResultDTO();
1335         resultsVO.setSearchResults(convertDocumentSearchResults(searchResult.getSearchResults()));
1336         return resultsVO;
1337     }
1338 
1339     private static List<DocumentSearchResultRowDTO> convertDocumentSearchResults(List<DocumentSearchResult> searchResults) throws WorkflowException {
1340         List<DocumentSearchResultRowDTO> rowVOs = new ArrayList<DocumentSearchResultRowDTO>();
1341         for (DocumentSearchResult documentSearchResult : searchResults) {
1342             rowVOs.add(convertDocumentSearchResult(documentSearchResult));
1343         }
1344         return rowVOs;
1345     }
1346 
1347     public static DocumentSearchResultRowDTO convertDocumentSearchResult(DocumentSearchResult resultRow) throws WorkflowException {
1348         DocumentSearchResultRowDTO rowVO = new DocumentSearchResultRowDTO();
1349         List<KeyValueDTO> fieldValues = new ArrayList<KeyValueDTO>();
1350         for (KeyValueSort keyValueSort : resultRow.getResultContainers()) {
1351             fieldValues.add(new KeyValueDTO(keyValueSort.getKey(),keyValueSort.getValue(),keyValueSort.getUserDisplayValue()));
1352         }
1353         rowVO.setFieldValues(fieldValues);
1354         return rowVO;
1355     }
1356 
1357     public static DocumentStatusTransitionDTO convertDocumentStatusTransition(DocumentStatusTransition transition) throws WorkflowException {
1358     	DocumentStatusTransitionDTO tranVO = new DocumentStatusTransitionDTO();
1359     	tranVO.setStatusTransitionId(transition.getStatusTransitionId());
1360     	tranVO.setRouteHeaderId(transition.getRouteHeaderId());
1361     	tranVO.setOldAppDocStatus(transition.getOldAppDocStatus());
1362     	tranVO.setNewAppDocStatus(transition.getNewAppDocStatus());
1363     	tranVO.setStatusTransitionDate(transition.getStatusTransitionDate());    	
1364     	return tranVO;
1365     }
1366     
1367     //    public static RuleBaseValues convertRuleVO(RuleVO ruleVO) throws WorkflowException {}
1368 
1369     private static void handleException(String message, Exception e) throws WorkflowException {
1370         if (e instanceof RuntimeException) {
1371             throw (RuntimeException) e;
1372         } else if (e instanceof WorkflowException) {
1373             throw (WorkflowException) e;
1374         }
1375         throw new WorkflowException(message, e);
1376     }
1377 
1378     //convert DocumentLink beans to array of DocumentLinkDTO
1379     public static DocumentLinkDTO[] convertDocumentLink(Collection<DocumentLink> links) {
1380         if (links == null) {
1381             return null;
1382         }
1383         DocumentLinkDTO[] docLinkVOs = new DocumentLinkDTO[links.size()];
1384         
1385         int index = 0;
1386         
1387         for (DocumentLink link: links) {
1388             docLinkVOs[index++] = convertDocumentLink(link);
1389         }
1390         return docLinkVOs;
1391     }
1392     
1393     //convert DocumentLink beans to list of DocumentLinkDTO
1394     public static List<DocumentLinkDTO> convertDocumentLinkToArrayList(Collection<DocumentLink> links) {
1395         if (links == null) {
1396             return null;
1397         }
1398         List<DocumentLinkDTO> docLinkVOs = new ArrayList<DocumentLinkDTO>(links.size());
1399         
1400         for (DocumentLink link: links) {
1401             docLinkVOs.add(convertDocumentLink(link));
1402         }
1403         return docLinkVOs;
1404     }
1405     
1406     //covert DocumentLink bean to DocumentLinkDTO
1407     public static DocumentLinkDTO convertDocumentLink(DocumentLink link) {
1408         if (link == null) {
1409             return null;
1410         }
1411         DocumentLinkDTO linkVO = new DocumentLinkDTO();
1412         linkVO.setLinbkId(link.getDocLinkId());
1413         linkVO.setOrgnDocId(link.getOrgnDocId());
1414         linkVO.setDestDocId(link.getDestDocId());
1415         
1416         return linkVO;
1417     }
1418 
1419 }