001/** 002 * Copyright 2005-2014 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; 017 018import org.kuali.rice.kew.api.WorkflowRuntimeException; 019import org.kuali.rice.kew.engine.RouteContext; 020import org.kuali.rice.kew.service.KEWServiceLocator; 021import org.kuali.rice.krad.util.LegacyUtils; 022 023import java.util.HashSet; 024import java.util.Iterator; 025import java.util.Set; 026import java.util.StringTokenizer; 027 028 029/** 030 * A basic implementation of the JoinEngine which handles join setup and makes determinations 031 * as to when a join condition has been satisfied. 032 * 033 * @author Kuali Rice Team (rice.collab@kuali.org) 034 */ 035public class BasicJoinEngine implements JoinEngine { 036 037 public static final String EXPECTED_JOINERS = "ExpectedJoiners"; 038 public static final String ACTUAL_JOINERS = "ActualJoiners"; 039 040 public RouteNodeInstance createExpectedJoinState(RouteContext context, RouteNodeInstance joinInstance, RouteNodeInstance previousNodeInstance) { 041 RouteNodeInstance splitNode = previousNodeInstance.getBranch().getSplitNode(); 042 if (splitNode == null) { 043 throw new WorkflowRuntimeException("The split node retrieved from node with name '" + previousNodeInstance.getName() + "' and branch with name '" + previousNodeInstance.getBranch().getName() + "' was null"); 044 } 045 for (Iterator iter = splitNode.getNextNodeInstances().iterator(); iter.hasNext();) { 046 RouteNodeInstance splitNodeNextNode = (RouteNodeInstance) iter.next(); 047 joinInstance = saveNode(context, joinInstance); 048 splitNodeNextNode.getBranch().setJoinNode(joinInstance); 049 addExpectedJoiner(joinInstance, splitNodeNextNode.getBranch()); 050 } 051 joinInstance.setBranch(splitNode.getBranch()); 052 joinInstance.setProcess(splitNode.getProcess()); 053 return joinInstance; 054 } 055 056 public void addExpectedJoiner(RouteNodeInstance nodeInstance, Branch branch) { 057 addJoinState(nodeInstance, branch, EXPECTED_JOINERS); 058 } 059 060 public void addActualJoiner(RouteNodeInstance nodeInstance, Branch branch) { 061 addJoinState(nodeInstance, branch, ACTUAL_JOINERS); 062 } 063 064 private void addJoinState(RouteNodeInstance nodeInstance, Branch branch, String key) { 065 NodeState state = nodeInstance.getNodeState(key); 066 if (state == null) { 067 state = new NodeState(); 068 state.setKey(key); 069 state.setValue(""); 070 state.setNodeInstance(nodeInstance); 071 nodeInstance.addNodeState(state); 072 } 073 state.setValue(state.getValue()+branch.getBranchId()+","); 074 } 075 076 public boolean isJoined(RouteNodeInstance nodeInstance) { 077 NodeState expectedState = nodeInstance.getNodeState(EXPECTED_JOINERS); 078 if (expectedState == null || org.apache.commons.lang.StringUtils.isEmpty(expectedState.getValue())) { 079 return true; 080 } 081 NodeState actualState = nodeInstance.getNodeState(ACTUAL_JOINERS); 082 Set expectedSet = loadIntoSet(expectedState); 083 Set actualSet = loadIntoSet(actualState); 084 for (Iterator iterator = expectedSet.iterator(); iterator.hasNext();) { 085 String value = (String) iterator.next(); 086 if (actualSet.contains(value)) { 087 iterator.remove(); 088 } 089 } 090 return expectedSet.size() == 0; 091 } 092 093 private Set loadIntoSet(NodeState state) { 094 Set set = new HashSet(); 095 StringTokenizer tokenizer = new StringTokenizer(state.getValue(), ","); 096 while (tokenizer.hasMoreTokens()) { 097 set.add(tokenizer.nextToken()); 098 } 099 return set; 100 } 101 102 private RouteNodeInstance saveNode(RouteContext context, RouteNodeInstance nodeInstance) { 103 if (!context.isSimulation()) { 104 return KEWServiceLocator.getRouteNodeService().save(nodeInstance); 105 } else { 106 // if we are in simulation mode, lets go ahead and assign some id 107 // values to our beans 108 for (RouteNodeInstance routeNodeInstance : nodeInstance.getNextNodeInstances()) { 109 if (routeNodeInstance.getRouteNodeInstanceId() == null) { 110 routeNodeInstance.setRouteNodeInstanceId(context.getEngineState().getNextSimulationId()); 111 } 112 } 113 if (nodeInstance.getProcess() != null && nodeInstance.getProcess().getRouteNodeInstanceId() == null) { 114 nodeInstance.getProcess().setRouteNodeInstanceId(context.getEngineState().getNextSimulationId()); 115 } 116 if (nodeInstance.getBranch() != null && nodeInstance.getBranch().getBranchId() == null) { 117 nodeInstance.getBranch().setBranchId(context.getEngineState().getNextSimulationId()); 118 } 119 return nodeInstance; 120 } 121 } 122 123}