Coverage Report - org.kuali.rice.kew.xml.export.DocumentTypeXmlExporter
 
Classes in this File Line Coverage Branch Coverage Complexity
DocumentTypeXmlExporter
0%
0/238
0%
0/124
4.333
DocumentTypeXmlExporter$1
N/A
N/A
4.333
DocumentTypeXmlExporter$DocumentTypeParentComparator
0%
0/10
0%
0/2
4.333
DocumentTypeXmlExporter$SplitJoinContext
0%
0/3
N/A
4.333
 
 1  
 /*
 2  
  * Copyright 2005-2007 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.xml.export;
 18  
 
 19  
 import java.io.IOException;
 20  
 import java.io.StringReader;
 21  
 import java.util.Collection;
 22  
 import java.util.Collections;
 23  
 import java.util.Comparator;
 24  
 import java.util.Iterator;
 25  
 import java.util.List;
 26  
 
 27  
 import org.apache.commons.lang.StringUtils;
 28  
 import org.jdom.Document;
 29  
 import org.jdom.Element;
 30  
 import org.jdom.JDOMException;
 31  
 import org.jdom.input.SAXBuilder;
 32  
 import org.kuali.rice.kew.doctype.DocumentTypeAttribute;
 33  
 import org.kuali.rice.kew.doctype.DocumentTypePolicy;
 34  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 35  
 import org.kuali.rice.kew.engine.node.BranchPrototype;
 36  
 import org.kuali.rice.kew.engine.node.NodeType;
 37  
 import org.kuali.rice.kew.engine.node.Process;
 38  
 import org.kuali.rice.kew.engine.node.RouteNode;
 39  
 import org.kuali.rice.kew.exception.InvalidXmlException;
 40  
 import org.kuali.rice.kew.exception.ResourceUnavailableException;
 41  
 import org.kuali.rice.kew.exception.WorkflowRuntimeException;
 42  
 import org.kuali.rice.kew.export.ExportDataSet;
 43  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 44  
 import org.kuali.rice.kew.util.KEWConstants;
 45  
 import org.kuali.rice.kew.util.Utilities;
 46  
 import org.kuali.rice.kew.util.XmlHelper;
 47  
 import org.kuali.rice.kew.xml.XmlConstants;
 48  
 import org.kuali.rice.kew.xml.XmlRenderer;
 49  
 import org.kuali.rice.kim.bo.Group;
 50  
 
 51  
 
 52  
 /**
 53  
  * Exports {@link DocumentType}s to XML.
 54  
  *
 55  
  * @see DocumentType
 56  
  *
 57  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 58  
  */
 59  0
 public class DocumentTypeXmlExporter implements XmlExporter, XmlConstants {
 60  
 
 61  0
     protected final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(getClass());
 62  
 
 63  0
     private XmlRenderer renderer = new XmlRenderer(DOCUMENT_TYPE_NAMESPACE);
 64  
 
 65  
     public Element export(ExportDataSet dataSet) {
 66  0
         if (!dataSet.getDocumentTypes().isEmpty()) {
 67  0
             Collections.sort(dataSet.getDocumentTypes(), new DocumentTypeParentComparator());
 68  0
             Element rootElement = renderer.renderElement(null, DOCUMENT_TYPES);
 69  0
             rootElement.setAttribute(SCHEMA_LOCATION_ATTR, DOCUMENT_TYPE_SCHEMA_LOCATION, SCHEMA_NAMESPACE);
 70  0
             for (Iterator iterator = dataSet.getDocumentTypes().iterator(); iterator.hasNext();) {
 71  0
                 DocumentType documentType = (DocumentType) iterator.next();
 72  0
                 exportDocumentType(rootElement, documentType);
 73  0
             }
 74  0
             return rootElement;
 75  
         }
 76  0
         return null;
 77  
     }
 78  
 
 79  
     private void exportDocumentType(Element parent, DocumentType documentType) {
 80  0
         Element docTypeElement = renderer.renderElement(parent, DOCUMENT_TYPE);
 81  0
         List flattenedNodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodes(documentType, false);
 82  
         // derive a default exception workgroup by looking at how the nodes are configured
 83  0
         boolean hasDefaultExceptionWorkgroup = hasDefaultExceptionWorkgroup(flattenedNodes);
 84  0
         renderer.renderTextElement(docTypeElement, NAME, documentType.getName());
 85  0
         if (documentType.getParentDocType() != null) {
 86  0
             renderer.renderTextElement(docTypeElement, PARENT, documentType.getParentDocType().getName());
 87  
         }
 88  0
         renderer.renderTextElement(docTypeElement, DESCRIPTION, documentType.getDescription());
 89  0
         renderer.renderTextElement(docTypeElement, LABEL, documentType.getLabel());
 90  0
         if (!StringUtils.isBlank(documentType.getActualServiceNamespace())) {
 91  0
             renderer.renderTextElement(docTypeElement, SERVICE_NAMESPACE, documentType.getActualServiceNamespace());
 92  
         }
 93  0
         renderer.renderTextElement(docTypeElement, POST_PROCESSOR_NAME, documentType.getPostProcessorName());
 94  0
         Group superUserWorkgroup = documentType.getSuperUserWorkgroupNoInheritence();
 95  0
         if (superUserWorkgroup != null) {
 96  0
                 Element superUserGroupElement = renderer.renderTextElement(docTypeElement, SUPER_USER_GROUP_NAME, superUserWorkgroup.getGroupName().trim());
 97  0
                 superUserGroupElement.setAttribute(NAMESPACE, superUserWorkgroup.getNamespaceCode().trim());
 98  
         }
 99  0
         Group blanketWorkgroup = documentType.getBlanketApproveWorkgroup();
 100  0
         if (blanketWorkgroup != null){
 101  0
                 Element blanketGroupElement = renderer.renderTextElement(docTypeElement, BLANKET_APPROVE_GROUP_NAME, blanketWorkgroup.getGroupName().trim());
 102  0
                 blanketGroupElement.setAttribute(NAMESPACE, blanketWorkgroup.getNamespaceCode().trim());
 103  
         }
 104  0
         if (documentType.getBlanketApprovePolicy() != null){
 105  0
                 renderer.renderTextElement(docTypeElement, BLANKET_APPROVE_POLICY, documentType.getBlanketApprovePolicy());
 106  
         }
 107  0
         Group reportingWorkgroup = documentType.getReportingWorkgroup();
 108  0
         if (reportingWorkgroup != null) {
 109  0
                 Element reportingGroupElement = renderer.renderTextElement(docTypeElement, REPORTING_GROUP_NAME, reportingWorkgroup.getGroupName().trim());
 110  0
                 reportingGroupElement.setAttribute(NAMESPACE, reportingWorkgroup.getNamespaceCode().trim());
 111  
         }
 112  0
         if (!flattenedNodes.isEmpty() && hasDefaultExceptionWorkgroup) {
 113  0
                 Group exceptionWorkgroup = ((RouteNode)flattenedNodes.get(0)).getExceptionWorkgroup();
 114  0
                 if (exceptionWorkgroup != null) {
 115  0
                         Element exceptionGroupElement = renderer.renderTextElement(docTypeElement, DEFAULT_EXCEPTION_GROUP_NAME, exceptionWorkgroup.getGroupName().trim());
 116  0
                         exceptionGroupElement.setAttribute(NAMESPACE, exceptionWorkgroup.getNamespaceCode().trim());
 117  
                 }
 118  
         }
 119  0
         if (StringUtils.isNotBlank(documentType.getUnresolvedDocHandlerUrl())) {
 120  0
             renderer.renderTextElement(docTypeElement, DOC_HANDLER, documentType.getUnresolvedDocHandlerUrl());
 121  
         }
 122  0
         if (!StringUtils.isBlank(documentType.getUnresolvedHelpDefinitionUrl())) {
 123  0
             renderer.renderTextElement(docTypeElement, HELP_DEFINITION_URL, documentType.getUnresolvedHelpDefinitionUrl());
 124  
         }
 125  0
         if (!StringUtils.isBlank(documentType.getUnresolvedDocSearchHelpUrl())) {
 126  0
             renderer.renderTextElement(docTypeElement, DOC_SEARCH_HELP_URL, documentType.getUnresolvedDocSearchHelpUrl());
 127  
         }
 128  0
         if (!StringUtils.isBlank(documentType.getActualNotificationFromAddress())) {
 129  0
                 renderer.renderTextElement(docTypeElement, NOTIFICATION_FROM_ADDRESS, documentType.getActualNotificationFromAddress());
 130  
         }
 131  0
         renderer.renderBooleanElement(docTypeElement, ACTIVE, documentType.getActive(), true);
 132  0
         exportPolicies(docTypeElement, documentType.getPolicies());
 133  0
       exportAttributes(docTypeElement, documentType.getDocumentTypeAttributes());
 134  0
       exportSecurity(docTypeElement, documentType.getDocumentTypeSecurityXml());
 135  0
               if (!StringUtils.isBlank(documentType.getRoutingVersion())) {
 136  0
                       renderer.renderTextElement(docTypeElement, ROUTING_VERSION, documentType.getRoutingVersion());
 137  
               }
 138  0
               Process process = null;
 139  0
               if (documentType.getProcesses().size() > 0) {
 140  0
                   process = (Process)documentType.getProcesses().get(0);
 141  
               }
 142  0
               if (process != null && process.getInitialRouteNode() != null) {
 143  0
                   exportRouteData(docTypeElement, documentType, flattenedNodes, hasDefaultExceptionWorkgroup);
 144  
               } else {
 145  0
                   renderer.renderElement(docTypeElement, ROUTE_PATHS);
 146  
               }
 147  0
     }
 148  
 
 149  
     private void exportPolicies(Element parent, Collection policies) {
 150  0
         if (!policies.isEmpty()) {
 151  0
             Element policiesElement = renderer.renderElement(parent, POLICIES);
 152  0
             for (Iterator iterator = policies.iterator(); iterator.hasNext();) {
 153  0
                 DocumentTypePolicy policy = (DocumentTypePolicy) iterator.next();
 154  0
                 Element policyElement = renderer.renderElement(policiesElement, POLICY);
 155  0
                 renderer.renderTextElement(policyElement, NAME, policy.getPolicyName());
 156  0
                 renderer.renderBooleanElement(policyElement, VALUE, policy.getPolicyValue(), false);
 157  0
             }
 158  
         }
 159  0
     }
 160  
 
 161  
     private void exportAttributes(Element parent, List attributes) {
 162  0
         if (!attributes.isEmpty()) {
 163  0
             Element attributesElement = renderer.renderElement(parent, ATTRIBUTES);
 164  0
             for (Iterator iterator = attributes.iterator(); iterator.hasNext();) {
 165  0
                 DocumentTypeAttribute attribute = (DocumentTypeAttribute) iterator.next();
 166  0
                 Element attributeElement = renderer.renderElement(attributesElement, ATTRIBUTE);
 167  0
                 renderer.renderTextElement(attributeElement, NAME, attribute.getRuleAttribute().getName());
 168  0
             }
 169  
         }
 170  0
     }
 171  
 
 172  
     private void exportSecurity(Element parent, String securityXML) {
 173  0
       if (!Utilities.isEmpty(securityXML)) {
 174  
         try {
 175  0
           org.jdom.Document securityDoc = new SAXBuilder().build(new StringReader(securityXML));
 176  0
           XmlHelper.propogateNamespace(securityDoc.getRootElement(), DOCUMENT_TYPE_NAMESPACE);
 177  0
           parent.addContent(securityDoc.getRootElement().detach());
 178  0
         } catch (IOException e) {
 179  0
           throw new WorkflowRuntimeException("Error parsing doctype security XML.");
 180  0
         } catch (JDOMException e) {
 181  0
           throw new WorkflowRuntimeException("Error parsing doctype security XML.");
 182  0
         }
 183  
       }
 184  0
     }
 185  
 
 186  
     private void exportRouteData(Element parent, DocumentType documentType, List flattenedNodes, boolean hasDefaultExceptionWorkgroup) {
 187  0
         if (!flattenedNodes.isEmpty()) {
 188  0
             Element routePathsElement = renderer.renderElement(parent, ROUTE_PATHS);
 189  0
             for (Iterator iterator = documentType.getProcesses().iterator(); iterator.hasNext();) {
 190  0
                 Process process = (Process) iterator.next();
 191  0
                 Element routePathElement = renderer.renderElement(routePathsElement, ROUTE_PATH);
 192  0
                 if (!process.isInitial()) {
 193  0
                     renderer.renderAttribute(routePathElement, INITIAL_NODE, process.getInitialRouteNode().getRouteNodeName());
 194  0
                     renderer.renderAttribute(routePathElement, PROCESS_NAME, process.getName());
 195  
                 }
 196  0
                 exportProcess(routePathElement, process);
 197  0
             }
 198  
 
 199  0
             Element routeNodesElement = renderer.renderElement(parent, ROUTE_NODES);
 200  0
             for (Iterator iterator = flattenedNodes.iterator(); iterator.hasNext();) {
 201  0
                 RouteNode node = (RouteNode) iterator.next();
 202  0
                 exportRouteNode(routeNodesElement, node, hasDefaultExceptionWorkgroup);
 203  0
             }
 204  
         }
 205  0
     }
 206  
 
 207  
     /* default exception workgroup is not stored independently in db, so derive
 208  
      * one from the definition itself: if all nodes have the *same* exception workgroup name
 209  
      * defined, then this is tantamount to a *default* exception workgroup and can be
 210  
      * used as such.
 211  
      */
 212  
     private boolean hasDefaultExceptionWorkgroup(List flattenedNodes) {
 213  0
         boolean hasDefaultExceptionWorkgroup = true;
 214  0
         String exceptionWorkgroupName = null;
 215  0
         for (Iterator iterator = flattenedNodes.iterator(); iterator.hasNext();) {
 216  0
             RouteNode node = (RouteNode) iterator.next();
 217  0
             if (exceptionWorkgroupName == null) {
 218  0
                 exceptionWorkgroupName = node.getExceptionWorkgroupName();
 219  
             }
 220  0
             if (exceptionWorkgroupName == null || !exceptionWorkgroupName.equals(node.getExceptionWorkgroupName())) {
 221  0
                 hasDefaultExceptionWorkgroup = false;
 222  0
                 break;
 223  
             }
 224  0
         }
 225  0
         return hasDefaultExceptionWorkgroup;
 226  
     }
 227  
 
 228  
     private void exportProcess(Element parent, Process process) {
 229  0
             exportNodeGraph(parent, process.getInitialRouteNode(), null);
 230  0
     }
 231  
 
 232  
     private void exportNodeGraph(Element parent, RouteNode node, SplitJoinContext splitJoinContext) {
 233  0
         NodeType nodeType = null;
 234  
 
 235  0
         String contentFragment = node.getContentFragment();
 236  
         // some of the older versions of rice do not have content fragments
 237  0
         if(contentFragment == null || "".equals(contentFragment)){
 238  0
                 nodeType = getNodeTypeForNode(node);
 239  
         }else{
 240  
                 // I'm not sure if this should be the default implementation because
 241  
                 // it uses a string comparison instead of a classpath check.
 242  0
                 nodeType = this.getNodeTypeForNodeFromFragment(node);
 243  
         }
 244  
 
 245  0
         if (nodeType.isAssignableFrom(NodeType.SPLIT)) {
 246  0
             exportSplitNode(parent, node, nodeType, splitJoinContext);
 247  0
         } else if (nodeType.isAssignableFrom(NodeType.JOIN)) {
 248  0
             exportJoinNode(parent, node, nodeType, splitJoinContext);
 249  
         } else {
 250  0
             exportSimpleNode(parent, node, nodeType, splitJoinContext);
 251  
         }
 252  0
     }
 253  
 
 254  
     private void exportSimpleNode(Element parent, RouteNode node, NodeType nodeType, SplitJoinContext splitJoinContext) {
 255  0
         Element simpleElement = renderNodeElement(parent, node, nodeType);
 256  0
         if (node.getNextNodes().size() > 1) {
 257  0
             throw new WorkflowRuntimeException("Simple node cannot have more than one next node: " + node.getRouteNodeName());
 258  
         }
 259  0
         if (node.getNextNodes().size() == 1) {
 260  0
             RouteNode nextNode = (RouteNode)node.getNextNodes().get(0);
 261  0
             renderer.renderAttribute(simpleElement, NEXT_NODE, nextNode.getRouteNodeName());
 262  0
             exportNodeGraph(parent, nextNode, splitJoinContext);
 263  
         }
 264  0
     }
 265  
 
 266  
     private void exportSplitNode(Element parent, RouteNode node, NodeType nodeType, SplitJoinContext splitJoinContext) {
 267  0
         Element splitElement = renderNodeElement(parent, node, nodeType);
 268  0
         SplitJoinContext newSplitJoinContext = new SplitJoinContext(node);
 269  0
         for (Iterator iterator = node.getNextNodes().iterator(); iterator.hasNext();) {
 270  0
             RouteNode nextNode = (RouteNode) iterator.next();
 271  0
             BranchPrototype branch = nextNode.getBranch();
 272  0
             if (branch == null) {
 273  0
                 throw new WorkflowRuntimeException("Found a split next node with no associated branch prototype: " + nextNode.getRouteNodeName());
 274  
             }
 275  0
             exportBranch(splitElement, nextNode, branch, newSplitJoinContext);
 276  0
         }
 277  0
         RouteNode joinNode = newSplitJoinContext.joinNode;
 278  0
         if (joinNode == null) {
 279  0
             if (node.getNextNodes().size() > 0) {
 280  0
                 throw new WorkflowRuntimeException("Could not locate the join node for the given split node " + node.getRouteNodeName());
 281  
             }
 282  
         } else {
 283  0
             renderNodeElement(splitElement, joinNode, newSplitJoinContext.joinNodeType);
 284  0
             if (joinNode.getNextNodes().size() > 1) {
 285  0
                 throw new WorkflowRuntimeException("Join node cannot have more than one next node: " + joinNode.getRouteNodeName());
 286  
             }
 287  0
             if (joinNode.getNextNodes().size() == 1) {
 288  0
                 RouteNode nextNode = (RouteNode)joinNode.getNextNodes().get(0);
 289  0
                 renderer.renderAttribute(splitElement, NEXT_NODE, nextNode.getRouteNodeName());
 290  0
                 exportNodeGraph(parent, nextNode, splitJoinContext);
 291  
             }
 292  
         }
 293  0
     }
 294  
 
 295  
     private void exportBranch(Element parent, RouteNode node, BranchPrototype branch, SplitJoinContext splitJoinContext) {
 296  0
         Element branchElement = renderer.renderElement(parent, BRANCH);
 297  0
         renderer.renderAttribute(branchElement, NAME, branch.getName());
 298  0
         exportNodeGraph(branchElement, node, splitJoinContext);
 299  0
     }
 300  
 
 301  
     private void exportJoinNode(Element parent, RouteNode node, NodeType nodeType, SplitJoinContext splitJoinContext) {
 302  0
         if (splitJoinContext == null) {
 303  
             // this is the case where a join node is defined as part of a sub process to be used by a dynamic node, in this case it is
 304  
             // not associated with a proper split node.
 305  0
             if (!node.getNextNodes().isEmpty()) {
 306  0
                 throw new WorkflowRuntimeException("Could not export join node with next nodes that is not contained within a split.");
 307  
             }
 308  0
             renderNodeElement(parent, node, nodeType);
 309  0
         } else if (splitJoinContext.joinNode == null) {
 310  
             // this is the case where we are "inside" the split node in the XML, by setting up this context, the calling code knows that
 311  
             // when it renders all of the branches of the split node, it can then use this context info to render the join node before
 312  
             // closing the split
 313  0
             splitJoinContext.joinNode = node;
 314  0
             splitJoinContext.joinNodeType = nodeType;
 315  
         }
 316  0
     }
 317  
 
 318  
     private Element renderNodeElement(Element parent, RouteNode node, NodeType nodeType) {
 319  0
         String nodeName = nodeType.getName();
 320  
         // if it's a request activation node, be sure to export it as a simple node
 321  0
         if (nodeType.equals(NodeType.REQUEST_ACTIVATION)) {
 322  0
             nodeName = NodeType.SIMPLE.getName();
 323  
         }
 324  0
         Element nodeElement = renderer.renderElement(parent, nodeName);
 325  0
         renderer.renderAttribute(nodeElement, NAME, node.getRouteNodeName());
 326  0
         return nodeElement;
 327  
     }
 328  
 
 329  
     /**
 330  
      * Exists for backward compatibility for nodes which don't have a content fragment.
 331  
      */
 332  
     private void exportRouteNodeOld(Element parent, RouteNode node, boolean hasDefaultExceptionWorkgroup) {
 333  0
         NodeType nodeType = getNodeTypeForNode(node);
 334  0
         Element nodeElement = renderer.renderElement(parent, nodeType.getName());
 335  0
         renderer.renderAttribute(nodeElement, NAME, node.getRouteNodeName());
 336  0
         if (!hasDefaultExceptionWorkgroup) {
 337  0
                 if (!StringUtils.isBlank(node.getExceptionWorkgroupName())) {
 338  0
                         Element exceptionGroupElement = renderer.renderTextElement(nodeElement, EXCEPTION_GROUP_NAME, node.getExceptionWorkgroupName());
 339  0
                         exceptionGroupElement.setAttribute(NAMESPACE, node.getExceptionWorkgroup().getNamespaceCode());
 340  
                 }
 341  
         }
 342  0
         if (supportsActivationType(nodeType) && !StringUtils.isBlank(node.getActivationType())) {
 343  0
             renderer.renderTextElement(nodeElement, ACTIVATION_TYPE, node.getActivationType());
 344  
         }
 345  0
         if (supportsRouteMethod(nodeType)) {
 346  0
             exportRouteMethod(nodeElement, node);
 347  0
             renderer.renderBooleanElement(nodeElement, MANDATORY_ROUTE, node.getMandatoryRouteInd(), false);
 348  0
             renderer.renderBooleanElement(nodeElement, FINAL_APPROVAL, node.getFinalApprovalInd(), false);
 349  
         }
 350  0
         if (nodeType.isCustomNode(node.getNodeType())) {
 351  0
             renderer.renderTextElement(nodeElement, TYPE, node.getNodeType());
 352  
         }
 353  0
     }
 354  
 
 355  
     private void exportRouteNode(Element parent, RouteNode node, boolean hasDefaultExceptionWorkgroup) {
 356  0
         String contentFragment = node.getContentFragment();
 357  0
         if (StringUtils.isBlank(contentFragment)) {
 358  0
             exportRouteNodeOld(parent, node, hasDefaultExceptionWorkgroup);
 359  
         } else {
 360  
             try {
 361  0
                 Document document = XmlHelper.buildJDocument(new StringReader(contentFragment));
 362  0
                 Element rootElement = document.detachRootElement();
 363  0
                 XmlHelper.propogateNamespace(rootElement, parent.getNamespace());
 364  0
                 parent.addContent(rootElement);
 365  0
             } catch (InvalidXmlException e) {
 366  0
                 throw new WorkflowRuntimeException("Failed to load the content fragment.", e);
 367  0
             }
 368  
         }
 369  0
     }
 370  
 
 371  
 
 372  
     private NodeType getNodeTypeForNode(RouteNode node) {
 373  0
         NodeType nodeType = null;
 374  0
         String errorMessage = "Could not determine proper XML element for the given node type: " + node.getNodeType();
 375  
 
 376  
         try {
 377  0
             nodeType = NodeType.fromClassName(node.getNodeType());
 378  0
         } catch (ResourceUnavailableException e) {
 379  0
             throw new WorkflowRuntimeException(errorMessage, e);
 380  0
         }
 381  0
         if (nodeType == null) {
 382  0
             throw new WorkflowRuntimeException(errorMessage);
 383  
         }
 384  0
         return nodeType;
 385  
     }
 386  
 
 387  
     /**
 388  
      *
 389  
      * This method will find the base node type via the content fragment of the node.
 390  
      * Basically, it reads the node type, start, split, join, etc and then assigns
 391  
      * the base type to it.  This is necessary because there are cases where the
 392  
      * passed in nodeType will no be in the classpath. It should, in theory do
 393  
      * the same thing as getNodeTypeForNode.
 394  
      *
 395  
      * @param node
 396  
      * @return
 397  
      */
 398  
     private NodeType getNodeTypeForNodeFromFragment(RouteNode node) {
 399  0
         NodeType nodeType = null;
 400  0
         String contentFragment = node.getContentFragment();
 401  0
         String errorMessage = "Could not determine proper XML element for the given node type: " + node.getNodeType();
 402  
 
 403  0
         for (Iterator<NodeType> iterator = NodeType.getTypeList().iterator(); iterator.hasNext();) {
 404  0
                 NodeType nType = iterator.next();
 405  
                 // checks for something like <start
 406  
                 // or <split
 407  
                 // we may want to switch this out for something a little more robust.
 408  0
                 if(contentFragment.startsWith("<" + nType.getName())){
 409  0
                            nodeType = nType;
 410  
                    }
 411  0
         }
 412  
 
 413  0
         if (nodeType == null) {
 414  0
             throw new WorkflowRuntimeException(errorMessage);
 415  
         }
 416  0
         return nodeType;
 417  
     }
 418  
 
 419  
     /**
 420  
      * Any node can support activation type, this use to not be the case but now it is.
 421  
      */
 422  
     private boolean supportsActivationType(NodeType nodeType) {
 423  0
         return true;
 424  
     }
 425  
 
 426  
     /**
 427  
      * Any node can support route methods, this use to not be the case but now it is.
 428  
      */
 429  
     private boolean supportsRouteMethod(NodeType nodeType) {
 430  0
         return true;
 431  
     }
 432  
 
 433  
     private void exportRouteMethod(Element parent, RouteNode node) {
 434  0
         if (!StringUtils.isBlank(node.getRouteMethodName())) {
 435  0
             String routeMethodCode = node.getRouteMethodCode();
 436  0
             String elementName = null;
 437  0
             if (KEWConstants.ROUTE_LEVEL_FLEX_RM.equals(routeMethodCode)) {
 438  0
                 elementName = RULE_TEMPLATE;
 439  0
             } else if (KEWConstants.ROUTE_LEVEL_ROUTE_MODULE.equals(routeMethodCode)) {
 440  0
                 elementName = ROUTE_MODULE;
 441  
             } else {
 442  0
                 throw new WorkflowRuntimeException("Invalid route method code '"+routeMethodCode+"' for node " + node.getRouteNodeName());
 443  
             }
 444  0
             renderer.renderTextElement(parent, elementName, node.getRouteMethodName());
 445  
         }
 446  0
     }
 447  
 
 448  0
     private class DocumentTypeParentComparator implements Comparator {
 449  
 
 450  
         public int compare(Object object1, Object object2) {
 451  0
             DocumentType docType1 = (DocumentType)object1;
 452  0
             DocumentType docType2 = (DocumentType)object2;
 453  0
             Integer depth1 = getDepth(docType1);
 454  0
             Integer depth2 = getDepth(docType2);
 455  0
             return depth1.compareTo(depth2);
 456  
         }
 457  
 
 458  
         private Integer getDepth(DocumentType docType) {
 459  0
                 int depth = 0;
 460  0
                 while ((docType = docType.getParentDocType()) != null) {
 461  0
                         depth++;
 462  
                 }
 463  0
                 return new Integer(depth);
 464  
         }
 465  
 
 466  
     }
 467  
 
 468  0
     private class SplitJoinContext {
 469  
         public RouteNode splitNode;
 470  
         public RouteNode joinNode;
 471  
         public NodeType joinNodeType;
 472  0
         public SplitJoinContext(RouteNode splitNode) {
 473  0
             this.splitNode = splitNode;
 474  0
         }
 475  
     }
 476  
 
 477  
 
 478  
 }