1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
package org.kuali.rice.kew.actions; |
18 | |
|
19 | |
import org.apache.log4j.MDC; |
20 | |
import org.kuali.rice.kew.actionrequest.ActionRequestFactory; |
21 | |
import org.kuali.rice.kew.actionrequest.ActionRequestValue; |
22 | |
import org.kuali.rice.kew.actionrequest.Recipient; |
23 | |
import org.kuali.rice.kew.actiontaken.ActionTakenValue; |
24 | |
import org.kuali.rice.kew.api.WorkflowRuntimeException; |
25 | |
import org.kuali.rice.kew.engine.CompatUtils; |
26 | |
import org.kuali.rice.kew.engine.RouteHelper; |
27 | |
import org.kuali.rice.kew.engine.node.NodeGraphSearchCriteria; |
28 | |
import org.kuali.rice.kew.engine.node.NodeGraphSearchResult; |
29 | |
import org.kuali.rice.kew.engine.node.RouteNode; |
30 | |
import org.kuali.rice.kew.engine.node.RouteNodeInstance; |
31 | |
import org.kuali.rice.kew.engine.node.service.RouteNodeService; |
32 | |
import org.kuali.rice.kew.exception.InvalidActionTakenException; |
33 | |
import org.kuali.rice.kew.postprocessor.DocumentRouteLevelChange; |
34 | |
import org.kuali.rice.kew.postprocessor.PostProcessor; |
35 | |
import org.kuali.rice.kew.postprocessor.ProcessDocReport; |
36 | |
import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; |
37 | |
import org.kuali.rice.kew.service.KEWServiceLocator; |
38 | |
import org.kuali.rice.kew.util.KEWConstants; |
39 | |
import org.kuali.rice.kim.api.identity.principal.PrincipalContract; |
40 | |
|
41 | |
|
42 | |
import java.util.ArrayList; |
43 | |
import java.util.Collection; |
44 | |
import java.util.Iterator; |
45 | |
import java.util.List; |
46 | |
|
47 | |
|
48 | |
|
49 | |
|
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
public class ReturnToPreviousNodeAction extends ActionTakenEvent { |
57 | |
|
58 | 0 | protected final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(getClass()); |
59 | |
|
60 | 0 | private RouteHelper helper = new RouteHelper(); |
61 | |
private String nodeName; |
62 | |
private boolean superUserUsage; |
63 | 0 | private boolean sendNotifications = true; |
64 | |
|
65 | |
public ReturnToPreviousNodeAction(DocumentRouteHeaderValue routeHeader, PrincipalContract principal) { |
66 | 0 | super(KEWConstants.ACTION_TAKEN_RETURNED_TO_PREVIOUS_CD, routeHeader, principal); |
67 | 0 | } |
68 | |
|
69 | |
public ReturnToPreviousNodeAction(DocumentRouteHeaderValue routeHeader, PrincipalContract principal, String annotation, String nodeName, boolean sendNotifications) { |
70 | 0 | super(KEWConstants.ACTION_TAKEN_RETURNED_TO_PREVIOUS_CD, routeHeader, principal, annotation); |
71 | 0 | this.nodeName = nodeName; |
72 | 0 | this.sendNotifications = sendNotifications; |
73 | 0 | } |
74 | |
|
75 | |
public ReturnToPreviousNodeAction(DocumentRouteHeaderValue routeHeader, PrincipalContract principal, String annotation, String nodeName, boolean sendNotifications, boolean runPostProcessorLogic) { |
76 | 0 | super(KEWConstants.ACTION_TAKEN_RETURNED_TO_PREVIOUS_CD, routeHeader, principal, annotation, runPostProcessorLogic); |
77 | 0 | this.nodeName = nodeName; |
78 | 0 | this.sendNotifications = sendNotifications; |
79 | 0 | } |
80 | |
|
81 | |
|
82 | |
|
83 | |
|
84 | |
protected ReturnToPreviousNodeAction(String overrideActionTakenCode, DocumentRouteHeaderValue routeHeader, PrincipalContract principal, String annotation, String nodeName, boolean sendNotifications) { |
85 | 0 | super(overrideActionTakenCode, routeHeader, principal, annotation); |
86 | 0 | this.nodeName = nodeName; |
87 | 0 | this.sendNotifications = sendNotifications; |
88 | 0 | } |
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
public ReturnToPreviousNodeAction(String overrideActionTakenCode, DocumentRouteHeaderValue routeHeader, PrincipalContract principal, String annotation, String nodeName, boolean sendNotifications, boolean runPostProcessorLogic) { |
94 | 0 | super(overrideActionTakenCode, routeHeader, principal, annotation, runPostProcessorLogic); |
95 | 0 | this.nodeName = nodeName; |
96 | 0 | this.sendNotifications = sendNotifications; |
97 | 0 | } |
98 | |
|
99 | |
|
100 | |
|
101 | |
|
102 | |
private void revokePendingRequests(List<ActionRequestValue> pendingRequests, ActionTakenValue actionTaken, Recipient delegator) { |
103 | 0 | revokeRequests(pendingRequests); |
104 | 0 | getActionRequestService().deactivateRequests(actionTaken, pendingRequests); |
105 | 0 | if (sendNotifications) { |
106 | 0 | ActionRequestFactory arFactory = new ActionRequestFactory(getRouteHeader()); |
107 | 0 | List<ActionRequestValue> notificationRequests = arFactory.generateNotifications(pendingRequests, getPrincipal(), delegator, KEWConstants.ACTION_REQUEST_FYI_REQ, getActionTakenCode()); |
108 | 0 | getActionRequestService().activateRequests(notificationRequests); |
109 | |
} |
110 | 0 | } |
111 | |
|
112 | |
|
113 | |
|
114 | |
|
115 | |
private void revokeRequests(List<ActionRequestValue> actionRequests) { |
116 | 0 | for (Iterator<ActionRequestValue> iterator = actionRequests.iterator(); iterator.hasNext();) { |
117 | 0 | ActionRequestValue actionRequest = iterator.next(); |
118 | 0 | actionRequest.setCurrentIndicator(Boolean.FALSE); |
119 | 0 | if (actionRequest.getActionTaken() != null) { |
120 | 0 | actionRequest.getActionTaken().setCurrentIndicator(Boolean.FALSE); |
121 | 0 | KEWServiceLocator.getActionTakenService().saveActionTaken(actionRequest.getActionTaken()); |
122 | |
} |
123 | 0 | revokeRequests(actionRequest.getChildrenRequests()); |
124 | 0 | KEWServiceLocator.getActionRequestService().saveActionRequest(actionRequest); |
125 | 0 | } |
126 | 0 | } |
127 | |
|
128 | |
private void processReturnToInitiator(RouteNodeInstance newNodeInstance) { |
129 | |
|
130 | 0 | RouteNode initialNode = newNodeInstance.getRouteNode().getDocumentType().getPrimaryProcess().getInitialRouteNode(); |
131 | 0 | if (newNodeInstance.getRouteNode().getRouteNodeId().equals(initialNode.getRouteNodeId())) { |
132 | 0 | LOG.debug("Document was returned to initiator"); |
133 | 0 | ActionRequestFactory arFactory = new ActionRequestFactory(getRouteHeader(), newNodeInstance); |
134 | 0 | ActionRequestValue notificationRequest = arFactory.createNotificationRequest(KEWConstants.ACTION_REQUEST_APPROVE_REQ, getRouteHeader().getInitiatorPrincipal(), getActionTakenCode(), getPrincipal(), "Document initiator"); |
135 | 0 | getActionRequestService().activateRequest(notificationRequest); |
136 | |
} |
137 | 0 | } |
138 | |
|
139 | |
|
140 | |
|
141 | |
|
142 | |
@Override |
143 | |
public String validateActionRules() { |
144 | 0 | return validateActionRules(getActionRequestService().findAllPendingRequests(routeHeader.getDocumentId())); |
145 | |
} |
146 | |
|
147 | |
public String validateActionRules(List<ActionRequestValue> actionRequests) { |
148 | 0 | if (!getRouteHeader().isValidActionToTake(getActionPerformedCode())) { |
149 | 0 | String docStatus = getRouteHeader().getDocRouteStatus(); |
150 | 0 | return "Document of status '" + docStatus + "' cannot taken action '" + KEWConstants.ACTION_TAKEN_RETURNED_TO_PREVIOUS + "' to node name "+nodeName; |
151 | |
} |
152 | 0 | List<ActionRequestValue> filteredActionRequests = filterActionRequestsByCode(actionRequests, KEWConstants.ACTION_REQUEST_COMPLETE_REQ); |
153 | 0 | if (! isActionCompatibleRequest(filteredActionRequests) && ! isSuperUserUsage()) { |
154 | 0 | return "No request for the user is compatible with the RETURN TO PREVIOUS NODE action"; |
155 | |
} |
156 | 0 | return ""; |
157 | |
} |
158 | |
|
159 | |
|
160 | |
|
161 | |
|
162 | |
@Override |
163 | |
public boolean isActionCompatibleRequest(List<ActionRequestValue> requests) { |
164 | 0 | String actionTakenCode = getActionPerformedCode(); |
165 | |
|
166 | |
|
167 | 0 | if (KEWConstants.ACTION_TAKEN_MOVE_CD.equals(actionTakenCode)) { |
168 | 0 | return true; |
169 | |
} |
170 | |
|
171 | |
|
172 | 0 | if (routeHeader.isStateInitiated() || routeHeader.isStateSaved()) { |
173 | 0 | return true; |
174 | |
} |
175 | |
|
176 | 0 | boolean actionCompatible = false; |
177 | 0 | Iterator<ActionRequestValue> ars = requests.iterator(); |
178 | 0 | ActionRequestValue actionRequest = null; |
179 | |
|
180 | 0 | while (ars.hasNext()) { |
181 | 0 | actionRequest = ars.next(); |
182 | |
|
183 | |
|
184 | |
|
185 | |
|
186 | |
|
187 | |
|
188 | |
|
189 | 0 | String request = actionRequest.getActionRequested(); |
190 | |
|
191 | 0 | if ( (KEWConstants.ACTION_REQUEST_FYI_REQ.equals(request)) || |
192 | |
(KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ.equals(request)) || |
193 | |
(KEWConstants.ACTION_REQUEST_APPROVE_REQ.equals(request)) || |
194 | |
(KEWConstants.ACTION_REQUEST_COMPLETE_REQ.equals(request)) ) { |
195 | 0 | actionCompatible = true; |
196 | 0 | break; |
197 | |
} |
198 | |
|
199 | |
|
200 | 0 | if (KEWConstants.ACTION_TAKEN_RETURNED_TO_PREVIOUS_CD.equals(actionTakenCode) && |
201 | |
(KEWConstants.ACTION_REQUEST_COMPLETE_REQ.equals(request) || KEWConstants.ACTION_REQUEST_APPROVE_REQ.equals(request))) { |
202 | 0 | actionCompatible = true; |
203 | |
} |
204 | 0 | } |
205 | |
|
206 | 0 | return actionCompatible; |
207 | |
} |
208 | |
|
209 | |
public void recordAction() throws InvalidActionTakenException { |
210 | 0 | MDC.put("docId", getRouteHeader().getDocumentId()); |
211 | 0 | updateSearchableAttributesIfPossible(); |
212 | 0 | LOG.debug("Returning document " + getRouteHeader().getDocumentId() + " to previous node: " + nodeName + ", annotation: " + annotation); |
213 | |
|
214 | 0 | List actionRequests = getActionRequestService().findAllValidRequests(getPrincipal().getPrincipalId(), getDocumentId(), KEWConstants.ACTION_REQUEST_COMPLETE_REQ); |
215 | 0 | String errorMessage = validateActionRules(actionRequests); |
216 | 0 | if (!org.apache.commons.lang.StringUtils.isEmpty(errorMessage)) { |
217 | 0 | throw new InvalidActionTakenException(errorMessage); |
218 | |
} |
219 | |
|
220 | 0 | Collection activeNodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(getRouteHeader().getDocumentId()); |
221 | 0 | NodeGraphSearchCriteria criteria = new NodeGraphSearchCriteria(NodeGraphSearchCriteria.SEARCH_DIRECTION_BACKWARD, activeNodeInstances, nodeName); |
222 | 0 | NodeGraphSearchResult result = KEWServiceLocator.getRouteNodeService().searchNodeGraph(criteria); |
223 | 0 | validateReturnPoint(nodeName, activeNodeInstances, result); |
224 | |
|
225 | 0 | LOG.debug("Record the returnToPreviousNode action"); |
226 | 0 | Recipient delegator = findDelegatorForActionRequests(actionRequests); |
227 | 0 | ActionTakenValue actionTaken = saveActionTaken(Boolean.FALSE, delegator); |
228 | |
|
229 | 0 | LOG.debug("Finding requests in return path and setting current indicator to FALSE"); |
230 | 0 | List<ActionRequestValue> doneRequests = new ArrayList<ActionRequestValue>(); |
231 | 0 | List<ActionRequestValue> pendingRequests = new ArrayList<ActionRequestValue>(); |
232 | 0 | for (Iterator iterator = result.getPath().iterator(); iterator.hasNext();) { |
233 | 0 | RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator.next(); |
234 | |
|
235 | 0 | KEWServiceLocator.getRouteNodeService().revokeNodeInstance(getRouteHeader(), nodeInstance); |
236 | 0 | List nodeRequests = getActionRequestService().findRootRequestsByDocIdAtRouteNode(getRouteHeader().getDocumentId(), nodeInstance.getRouteNodeInstanceId()); |
237 | 0 | for (Iterator requestIt = nodeRequests.iterator(); requestIt.hasNext();) { |
238 | 0 | ActionRequestValue request = (ActionRequestValue) requestIt.next(); |
239 | 0 | if (request.isDone()) { |
240 | 0 | doneRequests.add(request); |
241 | |
} else { |
242 | 0 | pendingRequests.add(request); |
243 | |
} |
244 | 0 | } |
245 | 0 | } |
246 | 0 | revokeRequests(doneRequests); |
247 | 0 | LOG.debug("Change pending requests to FYI and activate for docId " + getRouteHeader().getDocumentId()); |
248 | 0 | revokePendingRequests(pendingRequests, actionTaken, delegator); |
249 | 0 | notifyActionTaken(actionTaken); |
250 | 0 | executeNodeChange(activeNodeInstances, result); |
251 | 0 | } |
252 | |
|
253 | |
|
254 | |
|
255 | |
|
256 | |
|
257 | |
private void validateReturnPoint(String nodeName, Collection activeNodeInstances, NodeGraphSearchResult result) throws InvalidActionTakenException { |
258 | 0 | RouteNodeInstance resultNodeInstance = result.getResultNodeInstance(); |
259 | 0 | if (result.getResultNodeInstance() == null) { |
260 | 0 | throw new InvalidActionTakenException("Could not locate return point for node name '"+nodeName+"'."); |
261 | |
} |
262 | 0 | assertValidNodeType(resultNodeInstance); |
263 | 0 | assertValidBranch(resultNodeInstance, activeNodeInstances); |
264 | 0 | assertValidProcess(resultNodeInstance, activeNodeInstances); |
265 | 0 | assertFinalApprovalNodeNotInPath(result.getPath()); |
266 | 0 | } |
267 | |
|
268 | |
private void assertValidNodeType(RouteNodeInstance resultNodeInstance) throws InvalidActionTakenException { |
269 | |
|
270 | 0 | if (!helper.isSimpleNode(resultNodeInstance.getRouteNode()) && !helper.isSplitNode(resultNodeInstance.getRouteNode())) { |
271 | 0 | throw new InvalidActionTakenException("Can only return to a simple or a split node, attempting to return to " + resultNodeInstance.getRouteNode().getNodeType()); |
272 | |
} |
273 | 0 | } |
274 | |
|
275 | |
private void assertValidBranch(RouteNodeInstance resultNodeInstance, Collection activeNodeInstances) throws InvalidActionTakenException { |
276 | |
|
277 | 0 | boolean inValidBranch = false; |
278 | 0 | if (resultNodeInstance.getBranch().getParentBranch() == null) { |
279 | 0 | inValidBranch = true; |
280 | |
} else { |
281 | 0 | for (Iterator iterator = activeNodeInstances.iterator(); iterator.hasNext(); ) { |
282 | 0 | RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator.next(); |
283 | 0 | if (nodeInstance.getBranch().getBranchId().equals(resultNodeInstance.getBranch().getBranchId())) { |
284 | 0 | inValidBranch = true; |
285 | 0 | break; |
286 | |
} |
287 | 0 | } |
288 | |
} |
289 | 0 | if (!inValidBranch) { |
290 | 0 | throw new InvalidActionTakenException("Returning to an illegal branch, can only return to node within the same branch as an active node or to the primary branch."); |
291 | |
} |
292 | 0 | } |
293 | |
|
294 | |
private void assertValidProcess(RouteNodeInstance resultNodeInstance, Collection activeNodeInstances) throws InvalidActionTakenException { |
295 | |
|
296 | 0 | if (resultNodeInstance.isInProcess()) { |
297 | 0 | boolean inValidProcess = false; |
298 | 0 | for (Iterator iterator = activeNodeInstances.iterator(); iterator.hasNext(); ) { |
299 | 0 | RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator.next(); |
300 | 0 | if (nodeInstance.isInProcess() && nodeInstance.getProcess().getRouteNodeInstanceId().equals(nodeInstance.getProcess().getRouteNodeInstanceId())) { |
301 | 0 | inValidProcess = true; |
302 | 0 | break; |
303 | |
} |
304 | 0 | } |
305 | 0 | if (!inValidProcess) { |
306 | 0 | throw new InvalidActionTakenException("Returning into an illegal process, cannot return to node within a previously executing process."); |
307 | |
} |
308 | |
} |
309 | 0 | } |
310 | |
|
311 | |
|
312 | |
|
313 | |
|
314 | |
|
315 | |
|
316 | |
private void assertFinalApprovalNodeNotInPath(List path) throws InvalidActionTakenException { |
317 | 0 | for (Iterator iterator = path.iterator(); iterator.hasNext(); ) { |
318 | 0 | RouteNodeInstance nodeInstance = (RouteNodeInstance ) iterator.next(); |
319 | |
|
320 | 0 | if (nodeInstance.isComplete() && Boolean.TRUE.equals(nodeInstance.getRouteNode().getFinalApprovalInd())) { |
321 | 0 | throw new InvalidActionTakenException("Cannot return past or through the final approval node '"+nodeInstance.getName()+"'."); |
322 | |
} |
323 | 0 | } |
324 | 0 | } |
325 | |
|
326 | |
private void executeNodeChange(Collection activeNodes, NodeGraphSearchResult result) throws InvalidActionTakenException { |
327 | 0 | Integer oldRouteLevel = null; |
328 | 0 | Integer newRouteLevel = null; |
329 | 0 | if (CompatUtils.isRouteLevelCompatible(getRouteHeader())) { |
330 | 0 | int returnPathLength = result.getPath().size()-1; |
331 | 0 | oldRouteLevel = getRouteHeader().getDocRouteLevel(); |
332 | 0 | newRouteLevel = oldRouteLevel - returnPathLength; |
333 | 0 | LOG.debug("Changing route header "+ getRouteHeader().getDocumentId()+" route level for backward compatibility to "+newRouteLevel); |
334 | 0 | getRouteHeader().setDocRouteLevel(newRouteLevel); |
335 | 0 | KEWServiceLocator.getRouteHeaderService().saveRouteHeader(routeHeader); |
336 | |
} |
337 | 0 | List<RouteNodeInstance> startingNodes = determineStartingNodes(result.getPath(), activeNodes); |
338 | 0 | RouteNodeInstance newNodeInstance = materializeReturnPoint(startingNodes, result); |
339 | 0 | for (RouteNodeInstance activeNode : startingNodes) |
340 | |
{ |
341 | 0 | notifyNodeChange(oldRouteLevel, newRouteLevel, activeNode, newNodeInstance); |
342 | |
} |
343 | 0 | processReturnToInitiator(newNodeInstance); |
344 | 0 | } |
345 | |
|
346 | |
private void notifyNodeChange(Integer oldRouteLevel, Integer newRouteLevel, RouteNodeInstance oldNodeInstance, RouteNodeInstance newNodeInstance) throws InvalidActionTakenException { |
347 | |
try { |
348 | 0 | LOG.debug("Notifying post processor of route node change '"+oldNodeInstance.getName()+"'->'"+newNodeInstance.getName()); |
349 | 0 | PostProcessor postProcessor = routeHeader.getDocumentType().getPostProcessor(); |
350 | 0 | KEWServiceLocator.getRouteHeaderService().saveRouteHeader(getRouteHeader()); |
351 | 0 | DocumentRouteLevelChange routeNodeChange = new DocumentRouteLevelChange(routeHeader.getDocumentId(), |
352 | |
routeHeader.getAppDocId(), |
353 | |
oldRouteLevel, newRouteLevel, |
354 | |
oldNodeInstance.getName(), newNodeInstance.getName(), |
355 | |
oldNodeInstance.getRouteNodeInstanceId(), newNodeInstance.getRouteNodeInstanceId()); |
356 | 0 | ProcessDocReport report = postProcessor.doRouteLevelChange(routeNodeChange); |
357 | 0 | setRouteHeader(KEWServiceLocator.getRouteHeaderService().getRouteHeader(getDocumentId())); |
358 | 0 | if (!report.isSuccess()) { |
359 | 0 | LOG.warn(report.getMessage(), report.getProcessException()); |
360 | 0 | throw new InvalidActionTakenException(report.getMessage()); |
361 | |
} |
362 | 0 | } catch (Exception ex) { |
363 | 0 | throw new WorkflowRuntimeException(ex.getMessage()); |
364 | 0 | } |
365 | 0 | } |
366 | |
|
367 | |
private List<RouteNodeInstance> determineStartingNodes(List path, Collection<RouteNodeInstance> activeNodes) { |
368 | 0 | List<RouteNodeInstance> startingNodes = new ArrayList<RouteNodeInstance>(); |
369 | 0 | for (RouteNodeInstance activeNodeInstance : activeNodes) |
370 | |
{ |
371 | 0 | if (isInPath(activeNodeInstance, path)) |
372 | |
{ |
373 | 0 | startingNodes.add(activeNodeInstance); |
374 | |
} |
375 | |
} |
376 | 0 | return startingNodes; |
377 | |
} |
378 | |
|
379 | |
private boolean isInPath(RouteNodeInstance nodeInstance, List<RouteNodeInstance> path) { |
380 | 0 | for (RouteNodeInstance pathNodeInstance : path) |
381 | |
{ |
382 | 0 | if (pathNodeInstance.getRouteNodeInstanceId().equals(nodeInstance.getRouteNodeInstanceId())) |
383 | |
{ |
384 | 0 | return true; |
385 | |
} |
386 | |
} |
387 | 0 | return false; |
388 | |
} |
389 | |
|
390 | |
private RouteNodeInstance materializeReturnPoint(Collection<RouteNodeInstance> startingNodes, NodeGraphSearchResult result) { |
391 | 0 | RouteNodeService nodeService = KEWServiceLocator.getRouteNodeService(); |
392 | 0 | RouteNodeInstance returnInstance = result.getResultNodeInstance(); |
393 | 0 | RouteNodeInstance newNodeInstance = helper.getNodeFactory().createRouteNodeInstance(getDocumentId(), returnInstance.getRouteNode()); |
394 | 0 | newNodeInstance.setBranch(returnInstance.getBranch()); |
395 | 0 | newNodeInstance.setProcess(returnInstance.getProcess()); |
396 | 0 | newNodeInstance.setComplete(false); |
397 | 0 | newNodeInstance.setActive(true); |
398 | 0 | nodeService.save(newNodeInstance); |
399 | 0 | for (RouteNodeInstance activeNodeInstance : startingNodes) { |
400 | |
|
401 | 0 | activeNodeInstance.setComplete(true); |
402 | 0 | activeNodeInstance.setActive(false); |
403 | 0 | activeNodeInstance.setInitial(false); |
404 | 0 | activeNodeInstance.addNextNodeInstance(newNodeInstance); |
405 | |
} |
406 | 0 | for (RouteNodeInstance activeNodeInstance : startingNodes) |
407 | |
{ |
408 | 0 | nodeService.save(activeNodeInstance); |
409 | |
} |
410 | |
|
411 | |
|
412 | |
|
413 | 0 | return newNodeInstance; |
414 | |
} |
415 | |
|
416 | |
public boolean isSuperUserUsage() { |
417 | 0 | return superUserUsage; |
418 | |
} |
419 | |
public void setSuperUserUsage(boolean superUserUsage) { |
420 | 0 | this.superUserUsage = superUserUsage; |
421 | 0 | } |
422 | |
|
423 | |
} |