1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.engine;
17
18 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
19 import org.kuali.rice.kew.api.KewApiConstants;
20 import org.kuali.rice.kew.api.WorkflowRuntimeException;
21 import org.kuali.rice.kew.doctype.bo.DocumentType;
22 import org.kuali.rice.kew.engine.node.ProcessDefinitionBo;
23 import org.kuali.rice.kew.engine.node.RouteNode;
24 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
25 import org.kuali.rice.kew.api.KewApiConstants;
26
27 import java.util.ArrayList;
28 import java.util.List;
29
30
31
32
33
34
35
36
37
38
39 public final class CompatUtils {
40
41 private static RouteHelper helper = new RouteHelper();
42
43 private CompatUtils() {
44 throw new UnsupportedOperationException("do not call");
45 }
46
47 public static Integer getLevelForNode(DocumentType documentType, String nodeName) {
48 if (isRouteLevelCompatible(documentType)) {
49 return getLevelForNode(documentType.getPrimaryProcess().getInitialRouteNode(), nodeName, 0);
50 }
51 return new Integer(KewApiConstants.INVALID_ROUTE_LEVEL);
52 }
53
54 private static Integer getLevelForNode(RouteNode node, String nodeName, Integer currentLevel) {
55 if (node == null) {
56 throw new WorkflowRuntimeException("Could not locate node with name '"+nodeName+"'");
57 }
58
59
60 if (node.getRouteNodeName().equals(nodeName)) {
61 return currentLevel;
62 }
63 List<RouteNode> nextNodes = node.getNextNodes();
64 if (nextNodes.isEmpty()) {
65 throw new WorkflowRuntimeException("Could not locate node with name '"+nodeName+"'");
66 }
67 if (nextNodes.size() > 1) {
68 throw new WorkflowRuntimeException("Can only determine route level for document types with no splitting");
69 }
70 RouteNode nextNode = (RouteNode)nextNodes.get(0);
71 return getLevelForNode(nextNode, nodeName, new Integer(currentLevel.intValue()+1));
72 }
73
74
75
76
77
78
79 public static RouteNode getNodeForLevel(DocumentType documentType, Integer routeLevel) {
80 RouteNode result = null;
81
82 RouteNode initialRouteNode = documentType.getPrimaryProcess().getInitialRouteNode();
83 if (initialRouteNode != null) {
84 Object[] node = getNodeForLevel(initialRouteNode, routeLevel, new Integer(0));
85 result = (RouteNode)node[0];
86 }
87 return result;
88 }
89
90 private static Object[] getNodeForLevel(RouteNode node, Integer routeLevel, Integer currentLevel) {
91 if (helper.isSubProcessNode(node)) {
92 Object[] result = getNodeForLevel(node.getDocumentType().getNamedProcess(node.getRouteNodeName()).getInitialRouteNode(), routeLevel, currentLevel);
93 if (result[0] != null) {
94 node = (RouteNode)result[0];
95 }
96 currentLevel = (Integer)result[1];
97 }
98 if (currentLevel.equals(routeLevel)) {
99 return new Object[] { node, currentLevel };
100 }
101 List<RouteNode> nextNodes = node.getNextNodes();
102 if (nextNodes.isEmpty()) {
103 return new Object[] { null, currentLevel };
104 }
105 if (nextNodes.size() > 1) {
106 throw new WorkflowRuntimeException("Cannot determine a route level number for documents with splitting.");
107 }
108 currentLevel = new Integer(currentLevel.intValue()+1);
109 return getNodeForLevel((RouteNode)nextNodes.get(0), routeLevel, currentLevel);
110 }
111
112 public static boolean isRouteLevelCompatible(DocumentType documentType) {
113 return KewApiConstants.ROUTING_VERSION_ROUTE_LEVEL.equals(documentType.getRoutingVersion());
114 }
115
116 public static boolean isRouteLevelCompatible(DocumentRouteHeaderValue document) {
117 return isRouteLevelCompatible(document.getDocumentType());
118 }
119
120 public static boolean isNodalDocument(DocumentRouteHeaderValue document) {
121 return KewApiConstants.DocumentContentVersions.NODAL == document.getDocVersion().intValue();
122 }
123
124 public static boolean isNodalRequest(ActionRequestValue request) {
125 return KewApiConstants.DocumentContentVersions.NODAL == request.getDocVersion().intValue();
126 }
127
128 public static boolean isRouteLevelDocument(DocumentRouteHeaderValue document) {
129 return KewApiConstants.DocumentContentVersions.ROUTE_LEVEL == document.getDocVersion().intValue();
130 }
131
132 public static boolean isRouteLevelRequest(ActionRequestValue request) {
133 return KewApiConstants.DocumentContentVersions.ROUTE_LEVEL == request.getDocVersion().intValue();
134 }
135
136
137
138
139
140 public static List<RouteNode> getRouteLevelCompatibleNodeList(DocumentType documentType) {
141 if (!isRouteLevelCompatible(documentType)) {
142 throw new WorkflowRuntimeException("Attempting to invoke a 'route level' operation on a document which is not route level compatible.");
143 }
144 ProcessDefinitionBo primaryProcess = documentType.getPrimaryProcess();
145 RouteNode routeNode = primaryProcess.getInitialRouteNode();
146 List<RouteNode> nodes = new ArrayList<RouteNode>();
147 int count = 0;
148 int maxCount = 100;
149 if (routeNode != null) {
150 while (true) {
151 nodes.add(routeNode);
152 List<RouteNode> nextNodes = routeNode.getNextNodes();
153 if (nextNodes.size() == 0) {
154 break;
155 }
156 if (nextNodes.size() > 1) {
157 throw new RuntimeException("Node has more than one next node! It is not route level compatible!" + routeNode.getRouteNodeName());
158 }
159 if (count >= maxCount) {
160 throw new RuntimeException("A runaway loop was detected when attempting to create route level compatible node graph. documentType=" + documentType.getDocumentTypeId()+","+documentType.getName());
161 }
162 routeNode = nextNodes.iterator().next();
163 }
164 }
165 return nodes;
166 }
167
168 public static int getMaxRouteLevel(DocumentType documentType) {
169 return getRouteLevelCompatibleNodeList(documentType).size();
170 }
171 }