001/** 002 * Copyright 2005-2017 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kew.engine.node.service.impl; 017 018import org.apache.commons.collections.ComparatorUtils; 019import org.kuali.rice.kew.doctype.bo.DocumentType; 020import org.kuali.rice.kew.engine.RouteHelper; 021import org.kuali.rice.kew.engine.node.Branch; 022import org.kuali.rice.kew.engine.node.BranchState; 023import org.kuali.rice.kew.engine.node.NodeGraphContext; 024import org.kuali.rice.kew.engine.node.NodeGraphSearchCriteria; 025import org.kuali.rice.kew.engine.node.NodeGraphSearchResult; 026import org.kuali.rice.kew.engine.node.NodeMatcher; 027import org.kuali.rice.kew.engine.node.NodeState; 028import org.kuali.rice.kew.engine.node.ProcessDefinitionBo; 029import org.kuali.rice.kew.engine.node.RouteNode; 030import org.kuali.rice.kew.engine.node.RouteNodeInstance; 031import org.kuali.rice.kew.engine.node.RouteNodeUtils; 032import org.kuali.rice.kew.engine.node.dao.RouteNodeDAO; 033import org.kuali.rice.kew.engine.node.service.RouteNodeService; 034import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 035import org.kuali.rice.kew.service.KEWServiceLocator; 036import org.kuali.rice.krad.data.DataObjectService; 037import org.kuali.rice.krad.data.PersistenceOption; 038import org.springframework.beans.factory.annotation.Required; 039 040import java.util.ArrayList; 041import java.util.Arrays; 042import java.util.Collection; 043import java.util.Collections; 044import java.util.Comparator; 045import java.util.HashMap; 046import java.util.HashSet; 047import java.util.Iterator; 048import java.util.List; 049import java.util.Map; 050import java.util.Set; 051 052 053 054public class RouteNodeServiceImpl implements RouteNodeService { 055 056 protected final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(getClass()); 057 058 public static final String REVOKED_NODE_INSTANCES_STATE_KEY = "NodeInstances.Revoked"; 059 060 private static final Comparator NODE_INSTANCE_FORWARD_SORT = new NodeInstanceIdSorter(); 061 private static final Comparator NODE_INSTANCE_BACKWARD_SORT = 062 ComparatorUtils.reversedComparator(NODE_INSTANCE_FORWARD_SORT); 063 private RouteHelper helper = new RouteHelper(); 064 private RouteNodeDAO routeNodeDAO; 065 066 private DataObjectService dataObjectService; 067 068 public RouteNode save(RouteNode node) { 069 return dataObjectService.save(node); 070 } 071 072 public RouteNodeInstance save(RouteNodeInstance nodeInstance) { 073 return dataObjectService.save(nodeInstance); 074 } 075 076 public void save(NodeState nodeState) { 077 dataObjectService.save(nodeState); 078 } 079 080 public Branch save(Branch branch) { 081 return dataObjectService.save(branch); 082 } 083 084 public RouteNode findRouteNodeById(String nodeId) { 085 return dataObjectService.find(RouteNode.class,nodeId); 086 } 087 088 public RouteNodeInstance findRouteNodeInstanceById(String nodeInstanceId) { 089 return routeNodeDAO.findRouteNodeInstanceById(nodeInstanceId); 090 } 091 092 public RouteNodeInstance findRouteNodeInstanceById(String nodeInstanceId, DocumentRouteHeaderValue document) { 093 return RouteNodeUtils.findRouteNodeInstanceById(nodeInstanceId, document); 094 } 095 096 public List<RouteNodeInstance> getCurrentNodeInstances(String documentId) { 097 List<RouteNodeInstance> currentNodeInstances = getActiveNodeInstances(documentId); 098 if (currentNodeInstances.isEmpty()) { 099 currentNodeInstances = getTerminalNodeInstances(documentId); 100 } 101 return currentNodeInstances; 102 } 103 104 public List<RouteNodeInstance> getActiveNodeInstances(String documentId) { 105 return routeNodeDAO.getActiveNodeInstances(documentId); 106 } 107 108 public List<RouteNodeInstance> getActiveNodeInstances(DocumentRouteHeaderValue document) { 109 List<RouteNodeInstance> flattenedNodeInstances = getFlattenedNodeInstances(document, true); 110 List<RouteNodeInstance> activeNodeInstances = new ArrayList<RouteNodeInstance>(); 111 for (RouteNodeInstance nodeInstance : flattenedNodeInstances) { 112 if (nodeInstance.isActive()) { 113 activeNodeInstances.add(nodeInstance); 114 } 115 } 116 return activeNodeInstances; 117 } 118 119 @Override 120 public List<String> getCurrentRouteNodeNames(String documentId) { 121 return routeNodeDAO.getCurrentRouteNodeNames(documentId); 122 } 123 124 @Override 125 public List<String> getCurrentSimpleRouteNodeNames(String documentId) { 126 return routeNodeDAO.getCurrentSimpleRouteNodeNames(documentId); 127 } 128 129 130 @Override 131 public List<String> getActiveRouteNodeNames(String documentId) { 132 return routeNodeDAO.getActiveRouteNodeNames(documentId); 133 } 134 135 @Override 136 public List<String> getActiveSimpleRouteNodeNames(String documentId) { 137 return routeNodeDAO.getActiveSimpleRouteNodeNames(documentId); 138 } 139 140 public List<RouteNodeInstance> getTerminalNodeInstances(String documentId) { 141 return routeNodeDAO.getTerminalNodeInstances(documentId); 142 } 143 144 @Override 145 public List<String> getTerminalRouteNodeNames(String documentId) { 146 return routeNodeDAO.getTerminalRouteNodeNames(documentId); 147 } 148 149 public List getInitialNodeInstances(String documentId) { 150 return routeNodeDAO.getInitialNodeInstances(documentId); 151 } 152 153 public NodeState findNodeState(Long nodeInstanceId, String key) { 154 return routeNodeDAO.findNodeState(nodeInstanceId, key); 155 } 156 157 public RouteNode findRouteNodeByName(String documentTypeId, String name) { 158 return routeNodeDAO.findRouteNodeByName(documentTypeId, name); 159 } 160 161 public List<RouteNode> findFinalApprovalRouteNodes(String documentTypeId) { 162 DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findById(documentTypeId); 163 documentType = documentType.getRouteDefiningDocumentType(); 164 return routeNodeDAO.findFinalApprovalRouteNodes(documentType.getDocumentTypeId()); 165 } 166 167 public List findNextRouteNodesInPath(RouteNodeInstance nodeInstance, String nodeName) { 168 List<RouteNode> nodesInPath = new ArrayList<RouteNode>(); 169 for (Iterator<RouteNode> iterator = nodeInstance.getRouteNode().getNextNodes().iterator(); iterator.hasNext();) { 170 RouteNode nextNode = iterator.next(); 171 nodesInPath.addAll(findNextRouteNodesInPath(nodeName, nextNode, new HashSet<String>())); 172 } 173 return nodesInPath; 174 } 175 176 private List<RouteNode> findNextRouteNodesInPath(String nodeName, RouteNode node, Set<String> inspected) { 177 List<RouteNode> nextNodesInPath = new ArrayList<RouteNode>(); 178 if (inspected.contains(node.getRouteNodeId())) { 179 return nextNodesInPath; 180 } 181 inspected.add(node.getRouteNodeId()); 182 if (node.getRouteNodeName().equals(nodeName)) { 183 nextNodesInPath.add(node); 184 } else { 185 if (helper.isSubProcessNode(node)) { 186 ProcessDefinitionBo subProcess = node.getDocumentType().getNamedProcess(node.getRouteNodeName()); 187 RouteNode subNode = subProcess.getInitialRouteNode(); 188 if (subNode != null) { 189 nextNodesInPath.addAll(findNextRouteNodesInPath(nodeName, subNode, inspected)); 190 } 191 } 192 for (Iterator<RouteNode> iterator = node.getNextNodes().iterator(); iterator.hasNext();) { 193 RouteNode nextNode = iterator.next(); 194 nextNodesInPath.addAll(findNextRouteNodesInPath(nodeName, nextNode, inspected)); 195 } 196 } 197 return nextNodesInPath; 198 } 199 200 public boolean isNodeInPath(DocumentRouteHeaderValue document, String nodeName) { 201 boolean isInPath = false; 202 Collection<RouteNodeInstance> activeNodes = getActiveNodeInstances(document.getDocumentId()); 203 for (Iterator<RouteNodeInstance> iterator = activeNodes.iterator(); iterator.hasNext();) { 204 RouteNodeInstance nodeInstance = iterator.next(); 205 List nextNodesInPath = findNextRouteNodesInPath(nodeInstance, nodeName); 206 isInPath = isInPath || !nextNodesInPath.isEmpty(); 207 } 208 return isInPath; 209 } 210 211 public List findRouteNodeInstances(String documentId) { 212 return this.routeNodeDAO.findRouteNodeInstances(documentId); 213 } 214 215 public void setRouteNodeDAO(RouteNodeDAO dao) { 216 this.routeNodeDAO = dao; 217 } 218 219 public List findProcessNodeInstances(RouteNodeInstance process) { 220 return this.routeNodeDAO.findProcessNodeInstances(process); 221 } 222 223 public List<String> findPreviousNodeNames(String documentId) { 224 DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId); 225 List<String> revokedIds = Collections.emptyList(); 226 227 List<String> nodeNames = new ArrayList<String>(); 228 if(document.getRootBranch() != null) { 229 String revoked = document.getRootBranch().getBranchState(REVOKED_NODE_INSTANCES_STATE_KEY) == null ? null : document.getRootBranch().getBranchState(REVOKED_NODE_INSTANCES_STATE_KEY).getValue(); 230 if (revoked != null) { 231 revokedIds = Arrays.asList(revoked.split(",")); 232 } 233 List <RouteNodeInstance> currentNodeInstances = KEWServiceLocator.getRouteNodeService().getCurrentNodeInstances(documentId); 234 List<RouteNodeInstance> nodeInstances = new ArrayList<RouteNodeInstance>(); 235 for (RouteNodeInstance nodeInstance : currentNodeInstances) { 236 nodeInstances.addAll(nodeInstance.getPreviousNodeInstances()); 237 } 238 239 while (!nodeInstances.isEmpty()) { 240 RouteNodeInstance nodeInstance = nodeInstances.remove(0); 241 if (!revokedIds.contains(nodeInstance.getRouteNodeInstanceId())) { 242 nodeNames.add(nodeInstance.getName()); 243 } 244 nodeInstances.addAll(nodeInstance.getPreviousNodeInstances()); 245 } 246 247 //reverse the order, because it was built last to first 248 Collections.reverse(nodeNames); 249 } 250 251 return nodeNames; 252 } 253 254 public List<String> findFutureNodeNames(String documentId) { 255 List currentNodeInstances = KEWServiceLocator.getRouteNodeService().getCurrentNodeInstances(documentId); 256 List<RouteNode> nodes = new ArrayList<RouteNode>(); 257 for (Iterator iterator = currentNodeInstances.iterator(); iterator.hasNext();) { 258 RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator.next(); 259 nodes.addAll(nodeInstance.getRouteNode().getNextNodes()); 260 } 261 List<String> nodeNames = new ArrayList<String>(); 262 while (!nodes.isEmpty()) { 263 RouteNode node = nodes.remove(0); 264 if (!nodeNames.contains(node.getRouteNodeName())) { 265 nodeNames.add(node.getRouteNodeName()); 266 } 267 nodes.addAll(node.getNextNodes()); 268 } 269 return nodeNames; 270 } 271 272 public List<RouteNode> getFlattenedNodes(DocumentType documentType, boolean climbHierarchy) { 273 List<RouteNode> nodes = new ArrayList<RouteNode>(); 274 if (!documentType.isRouteInherited() || climbHierarchy) { 275 for (Iterator iterator = documentType.getProcesses().iterator(); iterator.hasNext();) { 276 ProcessDefinitionBo process = (ProcessDefinitionBo) iterator.next(); 277 nodes.addAll(getFlattenedNodes(process)); 278 } 279 } 280 Collections.sort(nodes, new RouteNodeSorter()); 281 return nodes; 282 } 283 284 public List<RouteNode> getFlattenedNodes(ProcessDefinitionBo process) { 285 Map<String, RouteNode> nodesMap = new HashMap<String, RouteNode>(); 286 if (process.getInitialRouteNode() != null) { 287 flattenNodeGraph(nodesMap, process.getInitialRouteNode()); 288 List<RouteNode> nodes = new ArrayList<RouteNode>(nodesMap.values()); 289 Collections.sort(nodes, new RouteNodeSorter()); 290 return nodes; 291 } else { 292 List<RouteNode> nodes = new ArrayList<RouteNode>(); 293 nodes.add(new RouteNode()); 294 return nodes; 295 } 296 297 } 298 299 /** 300 * Recursively walks the node graph and builds up the map. Uses a map because we will 301 * end up walking through duplicates, as is the case with Join nodes. 302 */ 303 private void flattenNodeGraph(Map<String, RouteNode> nodes, RouteNode node) { 304 if (node != null) { 305 if (nodes.containsKey(node.getRouteNodeName())) { 306 return; 307 } 308 nodes.put(node.getRouteNodeName(), node); 309 for (Iterator<RouteNode> iterator = node.getNextNodes().iterator(); iterator.hasNext();) { 310 RouteNode nextNode = iterator.next(); 311 flattenNodeGraph(nodes, nextNode); 312 } 313 } else { 314 return; 315 } 316 } 317 318 public List<RouteNodeInstance> getFlattenedNodeInstances(DocumentRouteHeaderValue document, boolean includeProcesses) { 319 List<RouteNodeInstance> nodeInstances = new ArrayList<RouteNodeInstance>(); 320 Set<String> visitedNodeInstanceIds = new HashSet<String>(); 321 for (Iterator<RouteNodeInstance> iterator = document.getInitialRouteNodeInstances().iterator(); iterator.hasNext();) { 322 RouteNodeInstance initialNodeInstance = iterator.next(); 323 flattenNodeInstanceGraph(nodeInstances, visitedNodeInstanceIds, initialNodeInstance, includeProcesses); 324 } 325 return nodeInstances; 326 } 327 328 private void flattenNodeInstanceGraph(List<RouteNodeInstance> nodeInstances, Set<String> visitedNodeInstanceIds, RouteNodeInstance nodeInstance, boolean includeProcesses) { 329 330 if (nodeInstance != null) { 331 if (visitedNodeInstanceIds.contains(nodeInstance.getRouteNodeInstanceId())) { 332 return; 333 } 334 if (includeProcesses && nodeInstance.getProcess() != null) { 335 flattenNodeInstanceGraph(nodeInstances, visitedNodeInstanceIds, nodeInstance.getProcess(), includeProcesses); 336 } 337 visitedNodeInstanceIds.add(nodeInstance.getRouteNodeInstanceId()); 338 nodeInstances.add(nodeInstance); 339 for (Iterator<RouteNodeInstance> iterator = nodeInstance.getNextNodeInstances().iterator(); iterator.hasNext();) { 340 RouteNodeInstance nextNodeInstance = iterator.next(); 341 flattenNodeInstanceGraph(nodeInstances, visitedNodeInstanceIds, nextNodeInstance, includeProcesses); 342 } 343 344 } 345 346 } 347 348 public NodeGraphSearchResult searchNodeGraph(NodeGraphSearchCriteria criteria) { 349 NodeGraphContext context = new NodeGraphContext(); 350 if (criteria.getSearchDirection() == NodeGraphSearchCriteria.SEARCH_DIRECTION_BACKWARD) { 351 searchNodeGraphBackward(context, criteria.getMatcher(), null, criteria.getStartingNodeInstances()); 352 } else { 353 throw new UnsupportedOperationException("Search feature can only search backward currently."); 354 } 355 List exactPath = determineExactPath(context, criteria.getSearchDirection(), criteria.getStartingNodeInstances()); 356 return new NodeGraphSearchResult(context.getCurrentNodeInstance(), exactPath); 357 } 358 359 private void searchNodeGraphBackward(NodeGraphContext context, NodeMatcher matcher, RouteNodeInstance previousNodeInstance, Collection nodeInstances) { 360 if (nodeInstances == null) { 361 return; 362 } 363 for (Iterator iterator = nodeInstances.iterator(); iterator.hasNext();) { 364 RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator.next(); 365 context.setPreviousNodeInstance(previousNodeInstance); 366 context.setCurrentNodeInstance(nodeInstance); 367 searchNodeGraphBackward(context, matcher); 368 if (context.getResultNodeInstance() != null) { 369 // we've located the node instance we're searching for, we're done 370 break; 371 } 372 } 373 } 374 375 private void searchNodeGraphBackward(NodeGraphContext context, NodeMatcher matcher) { 376 RouteNodeInstance current = context.getCurrentNodeInstance(); 377 int numBranches = current.getNextNodeInstances().size(); 378 // if this is a split node, we want to wait here, until all branches join back to us 379 if (numBranches > 1) { 380 // determine the number of branches that have joined back to the split thus far 381 Integer joinCount = (Integer)context.getSplitState().get(current.getRouteNodeInstanceId()); 382 if (joinCount == null) { 383 joinCount = new Integer(0); 384 } 385 // if this split is not a leaf node we increment the count 386 if (context.getPreviousNodeInstance() != null) { 387 joinCount = new Integer(joinCount.intValue()+1); 388 } 389 context.getSplitState().put(current.getRouteNodeInstanceId(), joinCount); 390 // if not all branches have joined, stop and wait for other branches to join 391 if (joinCount.intValue() != numBranches) { 392 return; 393 } 394 } 395 if (matcher.isMatch(context)) { 396 context.setResultNodeInstance(current); 397 } else { 398 context.getVisited().put(current.getRouteNodeInstanceId(), current); 399 searchNodeGraphBackward(context, matcher, current, current.getPreviousNodeInstances()); 400 } 401 } 402 403 public List<RouteNodeInstance> getActiveNodeInstances(DocumentRouteHeaderValue document, String nodeName) { 404 Collection<RouteNodeInstance> activeNodes = getActiveNodeInstances(document.getDocumentId()); 405 List<RouteNodeInstance> foundNodes = new ArrayList<RouteNodeInstance>(); 406 for (Iterator<RouteNodeInstance> iterator = activeNodes.iterator(); iterator.hasNext();) { 407 RouteNodeInstance nodeInstance = iterator.next(); 408 if (nodeInstance.getName().equals(nodeName)) { 409 foundNodes.add(nodeInstance); 410 } 411 } 412 return foundNodes; 413 } 414 415 private List determineExactPath(NodeGraphContext context, int searchDirection, Collection<RouteNodeInstance> startingNodeInstances) { 416 List<RouteNodeInstance> exactPath = new ArrayList<RouteNodeInstance>(); 417 if (context.getResultNodeInstance() == null) { 418 exactPath.addAll(context.getVisited().values()); 419 } else { 420 determineExactPath(exactPath, new HashMap<String, RouteNodeInstance>(), startingNodeInstances, context.getResultNodeInstance()); 421 } 422 if (NodeGraphSearchCriteria.SEARCH_DIRECTION_FORWARD == searchDirection) { 423 Collections.sort(exactPath, NODE_INSTANCE_BACKWARD_SORT); 424 } else { 425 Collections.sort(exactPath, NODE_INSTANCE_FORWARD_SORT); 426 } 427 return exactPath; 428 } 429 430 private void determineExactPath(List<RouteNodeInstance> exactPath, Map<String, RouteNodeInstance> visited, Collection<RouteNodeInstance> startingNodeInstances, RouteNodeInstance nodeInstance) { 431 if (nodeInstance == null) { 432 return; 433 } 434 if (visited.containsKey(nodeInstance.getRouteNodeInstanceId())) { 435 return; 436 } 437 visited.put(nodeInstance.getRouteNodeInstanceId(), nodeInstance); 438 exactPath.add(nodeInstance); 439 for (RouteNodeInstance startingNode : startingNodeInstances) { 440 if (startingNode.getRouteNodeInstanceId().equals(nodeInstance.getRouteNodeInstanceId())) { 441 return; 442 } 443 } 444 for (Iterator<RouteNodeInstance> iterator = nodeInstance.getNextNodeInstances().iterator(); iterator.hasNext(); ) { 445 RouteNodeInstance nextNodeInstance = iterator.next(); 446 determineExactPath(exactPath, visited, startingNodeInstances, nextNodeInstance); 447 } 448 } 449 450 451 /** 452 * Sorts by RouteNodeId or the order the nodes will be evaluated in *roughly*. This is 453 * for display purposes when rendering a flattened list of nodes. 454 * 455 * @author Kuali Rice Team (rice.collab@kuali.org) 456 */ 457 private static class RouteNodeSorter implements Comparator { 458 public int compare(Object arg0, Object arg1) { 459 RouteNode rn1 = (RouteNode)arg0; 460 RouteNode rn2 = (RouteNode)arg1; 461 return rn1.getRouteNodeId().compareTo(rn2.getRouteNodeId()); 462 } 463 } 464 465 private static class NodeInstanceIdSorter implements Comparator { 466 public int compare(Object arg0, Object arg1) { 467 RouteNodeInstance nodeInstance1 = (RouteNodeInstance)arg0; 468 RouteNodeInstance nodeInstance2 = (RouteNodeInstance)arg1; 469 return nodeInstance1.getRouteNodeInstanceId().compareTo(nodeInstance2.getRouteNodeInstanceId()); 470 } 471 } 472 473 474 public void deleteByRouteNodeInstance(RouteNodeInstance routeNodeInstance){ 475 //update the route node instance link table to cancel the relationship between the to-be-deleted instance and the previous node instances 476 routeNodeDAO.deleteLinksToPreNodeInstances(routeNodeInstance); 477 //delete the routeNodeInstance and its next node instances 478 routeNodeDAO.deleteRouteNodeInstancesHereAfter(routeNodeInstance); 479 } 480 481 public void deleteNodeStateById(Long nodeStateId){ 482 routeNodeDAO.deleteNodeStateById(nodeStateId); 483 } 484 485 public void deleteNodeStates(List statesToBeDeleted){ 486 routeNodeDAO.deleteNodeStates(statesToBeDeleted); 487 } 488 489 /** 490 * Records the revocation in the root BranchState of the document. 491 */ 492 public void revokeNodeInstance(DocumentRouteHeaderValue document, RouteNodeInstance nodeInstance) { 493 if (document == null) { 494 throw new IllegalArgumentException("Document must not be null."); 495 } 496 if (nodeInstance == null || nodeInstance.getRouteNodeInstanceId() == null) { 497 throw new IllegalArgumentException("In order to revoke a final approval node the node instance must be persisent and have an id."); 498 } 499 // get the initial node instance, the root branch is where we will store the state 500 Branch rootBranch = document.getRootBranch(); 501 BranchState state = null; 502 if (rootBranch != null) { 503 state = rootBranch.getBranchState(REVOKED_NODE_INSTANCES_STATE_KEY); 504 } 505 if (state == null) { 506 state = new BranchState(); 507 state.setKey(REVOKED_NODE_INSTANCES_STATE_KEY); 508 state.setValue(""); 509 rootBranch.addBranchState(state); 510 } 511 if (state.getValue() == null) { 512 state.setValue(""); 513 } 514 state.setValue(state.getValue() + nodeInstance.getRouteNodeInstanceId() + ","); 515 save(rootBranch); 516 } 517 518 /** 519 * Queries the list of revoked node instances from the root BranchState of the Document 520 * and returns a List of revoked RouteNodeInstances. 521 */ 522 public List getRevokedNodeInstances(DocumentRouteHeaderValue document) { 523 if (document == null) { 524 throw new IllegalArgumentException("Document must not be null."); 525 } 526 List<RouteNodeInstance> revokedNodeInstances = new ArrayList<RouteNodeInstance>(); 527 528 Branch rootBranch = document.getRootBranch(); 529 BranchState state = null; 530 if (rootBranch != null) { 531 state = rootBranch.getBranchState(REVOKED_NODE_INSTANCES_STATE_KEY); 532 } 533 if (state == null || org.apache.commons.lang.StringUtils.isEmpty(state.getValue())) { 534 return revokedNodeInstances; 535 } 536 String[] revokedNodes = state.getValue().split(","); 537 for (int index = 0; index < revokedNodes.length; index++) { 538 String revokedNodeInstanceId = revokedNodes[index]; 539 RouteNodeInstance revokedNodeInstance = findRouteNodeInstanceById(revokedNodeInstanceId); 540 if (revokedNodeInstance == null) { 541 LOG.warn("Could not locate revoked RouteNodeInstance with the given id: " + revokedNodeInstanceId); 542 } else { 543 revokedNodeInstances.add(revokedNodeInstance); 544 } 545 } 546 return revokedNodeInstances; 547 } 548 549 550 public DataObjectService getDataObjectService() { 551 return dataObjectService; 552 } 553 554 @Required 555 public void setDataObjectService(DataObjectService dataObjectService) { 556 this.dataObjectService = dataObjectService; 557 } 558 559 560}