Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Copyright 2005-2013 The Kuali Foundation Licensed under the Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.opensource.org/licenses/ecl2.php Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
 
 package org.kuali.rice.kew.engine.node.hierarchyrouting;
 
 
 import java.util.List;
 import java.util.Map;


Generic hierarchy routing node

Author(s):
Kuali Rice Team (rice.collab@kuali.org)
 
 public class HierarchyRoutingNode implements DynamicNode {
     protected final Logger LOG = Logger.getLogger(getClass());

    
The RouteNode configuration parameter that specifies the hierarchy provider implementation
 
     public static final String HIERARCHY_PROVIDER = "hierarchyProvider";
    
RouteNodeInstance NodeState key for id of stop
 
     public static final String STOP_ID = "stop_id";
 
     protected static final String SPLIT_PROCESS_NAME = "Hierarchy Split";
     protected static final String JOIN_PROCESS_NAME = "Hierarchy Join";
     protected static final String REQUEST_PROCESS_NAME = "Hierarchy Request";
     protected static final String NO_STOP_NAME = "No stop";
 
     // constants for the process state in tracking stops we've traveled
     private static final String VISITED_STOPS = "visited_stops";
     private static final String V_STOPS_DEL = ",";
     
     private static final String INITIAL_SPLIT_NODE_MARKER = "InitialSplitNode";

    
Loads hierarchy provider class via the GlobalResourceLoader

Parameters:
nodeInstance the current RouteNodeInstance
context the current RouteContext
Returns:
the HierarchyProvider implementation, as specified by the HIERARCHY_PROVIDER config parameter
 
     protected HierarchyProvider getHierarchyProvider(RouteNodeInstance nodeInstanceRouteContext context) {
         Map<StringStringcfgMap = Utilities.getKeyValueCollectionAsMap(nodeInstance.getRouteNode().getConfigParams());
         String hierarchyProviderClass = cfgMap.get(); 
         if (StringUtils.isEmpty(hierarchyProviderClass)) {
             throw new WorkflowRuntimeException("hierarchyProvider configuration parameter not set for HierarchyRoutingNode: " + nodeInstance.getName());
         }
         QName qn = QName.valueOf(hierarchyProviderClass);
         ObjectDefinition od;
         if (..equals(qn.getNamespaceURI())) {
             od = new ObjectDefinition(qn.getLocalPart());
         } else {
             od = new ObjectDefinition(qn.getLocalPart(), qn.getNamespaceURI());
         }
         HierarchyProvider hp = (HierarchyProvider) GlobalResourceLoader.getObject(od);
         hp.init(nodeInstancecontext);
        return hp;
    }
    public DynamicResult transitioningInto(RouteContext contextRouteNodeInstance dynamicNodeInstanceRouteHelper helperthrows Exception {
        HierarchyProvider provider = getHierarchyProvider(dynamicNodeInstancecontext);
        DocumentType documentType = setUpDocumentType(providercontext.getDocument().getDocumentType(), dynamicNodeInstance);
        RouteNode splitNode = documentType.getNamedProcess().getInitialRouteNode();
        //set up initial SplitNodeInstance
        RouteNodeInstance splitNodeInstance = helper.getNodeFactory().createRouteNodeInstance(context.getDocument().getDocumentId(), splitNode);
        splitNodeInstance.setBranch(dynamicNodeInstance.getBranch());
        markAsInitialSplitNode(splitNodeInstance);
        
        int i = 0;
        List<Stopstops = provider.getLeafStops(context);
        if (stops.isEmpty()) {
            // if we have no stops, then just return a no-op node with IU-UNIV attached, this will terminate the process
            RouteNode noStopNode = documentType.getNamedProcess().getInitialRouteNode();
            RouteNodeInstance noChartOrgInstance = helper.getNodeFactory().createRouteNodeInstance(context.getDocument().getDocumentId(), noStopNode);
            noChartOrgInstance.setBranch(dynamicNodeInstance.getBranch());
            provider.setStop(noChartOrgInstancenull);
            return new DynamicResult(truenoChartOrgInstance);
        }
        for (Stop stopstops) {
            RouteNode requestNode = getStopRequestNode(stopdocumentType);
            createInitialRequestNodeInstance(providerstopsplitNodeInstancedynamicNodeInstancerequestNode);
        }
        return new DynamicResult(falsesplitNodeInstance);
    }
    public DynamicResult transitioningOutOf(RouteContext contextRouteHelper helperthrows Exception {
        // process initial nodes govern transitioning within the process
        // the process node will be the hierarchy node, so that's what we need to grab
        HierarchyProvider provider = getHierarchyProvider(context.getNodeInstance().getProcess(), context);
        
        RouteNodeInstance processInstance = context.getNodeInstance().getProcess();
        RouteNodeInstance curStopNode = context.getNodeInstance();
        Map<StringRouteNodeInstancestopRequestNodeMap = new HashMap<StringRouteNodeInstance>();
        findStopRequestNodes(providercontextstopRequestNodeMap);//SpringServiceLocator.getRouteNodeService().findProcessNodeInstances(processInstance);
        
        Stop stop = provider.getStop(curStopNode);
        if (provider.isRoot(stop)) {
            return new DynamicResult(truenull);
        }        
        
        //create a join node for the next node and attach any sibling orgs to the join
        //if no join node is necessary i.e. no siblings create a requests node
        InnerTransitionResult transition = canTransitionFrom(providerstopstopRequestNodeMap.values(), helper);
        DynamicResult result = null;
        if (transition.isCanTransition()) {
            DocumentType documentType = context.getDocument().getDocumentType();
            // make a simple requests node
            RouteNodeInstance requestNode = createNextStopRequestNodeInstance(providercontextstopprocessInstancehelper);
            if (transition.getSiblings().isEmpty()) {
                result = new DynamicResult(falserequestNode);
            } else {
                /* join stuff not working
                //create a join to transition us to the next org
                RouteNode joinPrototype = documentType.getNamedProcess(JOIN_PROCESS_NAME).getInitialRouteNode();
                RouteNodeInstance joinNode = helper.getNodeFactory().createRouteNodeInstance(context.getDocument().getDocumentId(), joinPrototype);
                LOG.debug("Created join node: " + joinNode);
                String branchName = "Branch for join " + provider.getStopIdentifier(stop);
                Branch joinBranch = helper.getNodeFactory().createBranch(branchName, null, joinNode);
                LOG.debug("Created branch for join node: " + joinBranch);
                joinNode.setBranch(joinBranch);
                for (RouteNodeInstance sibling: transition.getSiblings()) {
                    LOG.debug("Adding expected joiner: " + sibling.getRouteNodeInstanceId() + " " + provider.getStop(sibling));
                    helper.getJoinEngine().addExpectedJoiner(joinNode, sibling.getBranch());
                }
                ///XXX: can't get stop from node that hasn't been saved yet maybe...need to follow up on this...comes back as 'root'
                LOG.debug("Adding as stop after join: " + requestNode.getRouteNodeInstanceId() + " " + provider.getStop(requestNode));
                //set the next org after the join
                joinNode.addNextNodeInstance(requestNode);
                result = new DynamicResult(false, joinNode);
                
                */
            }
        } else {
            result = new DynamicResult(falsenull);
        }
        result.getNextNodeInstances().addAll(getNewlyAddedOrgRouteInstances(providercontexthelper));
        return result;
    }
    
    private void findStopRequestNodes(HierarchyProvider providerRouteContext contextMap<StringRouteNodeInstancestopRequestNodes) {
        List<RouteNodeInstancenodeInstances = KEWServiceLocator.getRouteNodeService().getFlattenedNodeInstances(context.getDocument(), true);
        for (RouteNodeInstance nodeInstancenodeInstances) {
            if (provider.hasStop(nodeInstance)) {
                .debug("Stop node instance: " + nodeInstance);
                stopRequestNodes.put(nodeInstance.getRouteNodeInstanceId(), nodeInstance);
            }
        }
        
    }
    private RouteNodeInstance createNextStopRequestNodeInstance(HierarchyProvider providerRouteContext contextStop stopRouteNodeInstance processInstanceRouteHelper helper) {
        Stop futureStop = provider.getParent(stop);
        .debug("Creating next stop request node instance " + provider.getStopIdentifier(futureStop) + " as parent of " + provider.getStopIdentifier(stop));
        RouteNode requestsPrototype = getStopRequestNode(futureStopcontext.getDocument().getDocumentType());
        RouteNodeInstance requestNode = helper.getNodeFactory().createRouteNodeInstance(context.getDocument().getDocumentId(), requestsPrototype);
        requestNode.setBranch(processInstance.getBranch());
        NodeState ns = new NodeState();
        ns.setKey();
        ns.setValue(provider.getStopIdentifier(futureStop));
        requestNode.addNodeState(ns);
        provider.setStop(requestNodefutureStop);
        .debug("Stop set on request node: " + provider.getStop(requestNode));
        addStopToProcessState(providerprocessInstancefutureStop);
        return requestNode;
    }

    
i can only transition from this if all the nodes left are completed immediate siblings

Parameters:
org
requestNodes
Returns:
List of Nodes that are siblings to the org passed in
    private InnerTransitionResult canTransitionFrom(HierarchyProvider providerStop currentStopCollection<RouteNodeInstancerequestNodesRouteHelper helper) {
        .debug("Testing whether we can transition from stop: " + currentStop);
        Stop parent = provider.getParent(currentStop);
        InnerTransitionResult result = new InnerTransitionResult();
        result.setCanTransition(false);
        for (RouteNodeInstance requestNoderequestNodes) {
            if (!provider.hasStop(requestNode)) {
                .debug("request node " + requestNode.getName() + " does not have a stop associated with it");
                continue;
            }
            Stop requestNodeStop = provider.getStop(requestNode);
            if (requestNodeStop != null) {
                .debug("Request node: " + requestNode.getRouteNodeInstanceId() + " has stop " + requestNodeStop.toString());
            }
            if (requestNodeStop != null && provider.equals(currentStoprequestNodeStop)) {
                .debug("Skipping node " + requestNode.getName() + " because it is associated with the current stop");
                continue;
            }
            Stop stop = provider.getStop(requestNode);
            .debug("Found an outstanding stop: " + stop);
            boolean isChildOfMyParent = isDescendent(providerparentstop);
            if (isChildOfMyParent) {
                .debug("Found stop node whose parent is my parent:");
                .debug("Stop: " + stop);
                .debug("Node: " + requestNode);
                // if any sibling request node is active, then I can't transition
                if (requestNode.isActive()) {
                    // can't transition
                    result.getSiblings().clear();
                    return result;
                }
                /* join stuff not working
                // if it's a direct sibling
                if (provider.equals(parent, provider.getParent(stop))) {
                    LOG.debug("Adding stop " + provider.getStopIdentifier(stop) + " as sibling to " + provider.getStopIdentifier(currentStop));
                    result.getSiblings().add(requestNode);
                }
                */
            }
        }
        result.setCanTransition(true);
        return result;
    }
    protected boolean isDescendent(HierarchyProvider providerStop parentStop otherStop) {
        return provider.isRoot(parent) || hasAsParent(providerparentotherStop);
    }
    private static class InnerTransitionResult {
        private boolean canTransition;
        private List<RouteNodeInstancesiblings = new ArrayList<RouteNodeInstance>();
        public boolean isCanTransition() {
            return ;
        }
        public void setCanTransition(boolean canTransition) {
            this. = canTransition;
        }
        public List<RouteNodeInstancegetSiblings() {
            return ;
        }
        public void setSiblings(List<RouteNodeInstancesiblings) {
            this. = siblings;
        }
    }
    private static void markAsInitialSplitNode(RouteNodeInstance splitNode) {
        NodeState ns = new NodeState();
    	
    	splitNode.addNodeState(ns);
    }

    

Parameters:
routeNodeInstance
Returns:
    private static boolean isInitialSplitNode(RouteNodeInstance routeNodeInstance) {
        return routeNodeInstance.getNodeState() != null;
    }

    
Adds the org to the process state

Parameters:
processInstance
org
    private void addStopToProcessState(HierarchyProvider providerRouteNodeInstance processInstanceStop stop) {
        String stopStateName = provider.getStopIdentifier(stop);
        NodeState visitedStopsState = processInstance.getNodeState();
        if (visitedStopsState == null) {
            NodeState ns = new NodeState();
            ns.setKey();
            ns.setValue(stopStateName + );
        	
        	processInstance.addNodeState(ns);
        } else if (! getVisitedStopsList(processInstance).contains(stopStateName)) {
            visitedStopsState.setValue(visitedStopsState.getValue() + stopStateName + );
        }
    }
    
    

Parameters:
process
Returns:
List of stop strings on the process state
    private static List<StringgetVisitedStopsList(RouteNodeInstance process) {
        return Arrays.asList(process.getNodeState().getValue().split());
    }
    
    
Determines if the org has been routed to or will be.

Parameters:
stop
process
Returns:
boolean if this is an org we would not hit in routing
    private boolean isNewStop(HierarchyProvider providerStop stopRouteNodeInstance process) {
        
        String orgStateName = provider.getStopIdentifier(stop);
        List<StringvisitedOrgs = getVisitedStopsList(process);
        boolean isInVisitedList = visitedOrgs.contains(orgStateName);
        if (isInVisitedList) {
            return false;
        }
        boolean willEventualRouteThere = false;
        //determine if we will eventually route to this chart anyway
        for (Iterator<Stringiter = visitedOrgs.iterator(); iter.hasNext() && willEventualRouteThere == false; ) {
            String visitedStopStateName = iter.next();
            Stop visitedStop = provider.getStopByIdentifier(visitedStopStateName);
            willEventualRouteThere = hasAsParent(providerstopvisitedStop) || willEventualRouteThere;
        }
        return ! willEventualRouteThere;
    }

    
Creates a Org Request RouteNodeInstance that is a child of the passed in split. This is used to create the initial request RouteNodeInstances off the begining split.

Parameters:
org
splitNodeInstance
processInstance
requestsNode
Returns:
Request RouteNodeInstance bound to the passed in split as a 'nextNodeInstance'
    private RouteNodeInstance createInitialRequestNodeInstance(HierarchyProvider providerStop stopRouteNodeInstance splitNodeInstanceRouteNodeInstance processInstanceRouteNode requestsNode) {
        String branchName = "Branch " + provider.getStopIdentifier(stop);
        RouteNodeInstance orgRequestInstance = SplitTransitionEngine.createSplitChild(branchNamerequestsNodesplitNodeInstance);
        splitNodeInstance.addNextNodeInstance(orgRequestInstance);
        NodeState ns = new NodeState();
        ns.setKey();
        ns.setValue(provider.getStopIdentifier(stop));
        
        orgRequestInstance.addNodeState(ns);
        provider.setStop(orgRequestInstancestop);
        addStopToProcessState(providerprocessInstancestop);
        return orgRequestInstance;
    }
    
    
Check the xml and determine there are any orgs declared that we will not travel through on our current trajectory.

Parameters:
context
helper
Returns:
RouteNodeInstances for any orgs we would not have traveled through that are now in the xml.
Throws:
java.lang.Exception
    private List<RouteNodeInstancegetNewlyAddedOrgRouteInstances(HierarchyProvider providerRouteContext contextRouteHelper helperthrows Exception {
        RouteNodeInstance processInstance = context.getNodeInstance().getProcess();
        RouteNodeInstance chartOrgNode = context.getNodeInstance();
        //check for new stops in the xml
        List<Stopstops = provider.getLeafStops(context);
        List<RouteNodeInstancenewStopsRoutingTo = new ArrayList<RouteNodeInstance>();
        for (Stop stopstops) {
            if (isNewStop(providerstopprocessInstance)) {
                //the idea here is to always use the object referenced by the engine so simulation can occur
                List<RouteNodeInstanceprocessNodes = chartOrgNode.getPreviousNodeInstances();
                for (RouteNodeInstance splitNodeInstanceprocessNodes) {
                    if (isInitialSplitNode(splitNodeInstance)) {                        
                        RouteNode requestsNode = getStopRequestNode(stopcontext.getDocument().getDocumentType());
                        RouteNodeInstance newOrgRequestNode = createInitialRequestNodeInstance(providerstopsplitNodeInstanceprocessInstancerequestsNode);
                        newStopsRoutingTo.add(newOrgRequestNode);
                    }
                }
            }
        }
        return newStopsRoutingTo;
    }    
    
    

Parameters:
parent
child
Returns:
true - if child or one of it's eventual parents reports to parent false - if child or one of it's eventual parents does not report to parent
    private boolean hasAsParent(HierarchyProvider providerStop parentStop child) {
        if (child == null || provider.isRoot(child)) {
            return false;
        } else if (provider.equals(parentchild)) {
            return true;
        } else {
            child = provider.getParent(child);
            return hasAsParent(providerparentchild);
        }
    }


    
Make the 'floating' split, join and request RouteNodes that will be independent processes. These are the prototypes from which our RouteNodeInstance will belong

Parameters:
documentType
dynamicNodeInstance
    private DocumentType setUpDocumentType(HierarchyProvider providerDocumentType documentTypeRouteNodeInstance dynamicNodeInstance) {
        boolean altered = false;
        if (documentType.getNamedProcess() == null) {
            RouteNode splitNode = getSplitNode(dynamicNodeInstance);
            documentType.addProcess(getPrototypeProcess(splitNodedocumentType));
            altered = true;
        }
        if (documentType.getNamedProcess() == null) {
            RouteNode joinNode = getJoinNode(dynamicNodeInstance);
            documentType.addProcess(getPrototypeProcess(joinNodedocumentType));
            altered = true;
        }
        if (documentType.getNamedProcess() == null) {
            RouteNode requestsNode = getRequestNode(providerdynamicNodeInstance);
            documentType.addProcess(getPrototypeProcess(requestsNodedocumentType));
            altered = true;
        }
        if (documentType.getNamedProcess() == null) {
            RouteNode noChartOrgNode = getNoChartOrgNode(dynamicNodeInstance);
            documentType.addProcess(getPrototypeProcess(noChartOrgNodedocumentType));
            altered = true;
        }
        if (altered) {
                //side step normal version etc. because it's a pain.
            KEWServiceLocator.getDocumentTypeService().save(documentType);
        }
        return KEWServiceLocator.getDocumentTypeService().findByName(documentType.getName());
    }

    
Places a ProcessDefinition on the documentType wrapping the node and setting the node as the process's initalRouteNode

Parameters:
node
documentType
Returns:
Process wrapping the node passed in
    protected ProcessDefinitionBo getPrototypeProcess(RouteNode nodeDocumentType documentType) {
        ProcessDefinitionBo process = new ProcessDefinitionBo();
        process.setDocumentType(documentType);
        process.setInitial(false);
        process.setInitialRouteNode(node);
        process.setName(node.getRouteNodeName());
        return process;
    }

    

Parameters:
process
Returns:
Route Node of the JoinNode that will be prototype for the split RouteNodeInstances generated by this component
    private static RouteNode getSplitNode(RouteNodeInstance process) {
        RouteNode dynamicNode = process.getRouteNode();
        RouteNode splitNode = new RouteNode();
        splitNode.setActivationType(dynamicNode.getActivationType());
        splitNode.setDocumentType(dynamicNode.getDocumentType());
        splitNode.setFinalApprovalInd(dynamicNode.getFinalApprovalInd());
        splitNode.setExceptionWorkgroupId(dynamicNode.getExceptionWorkgroupId());
        splitNode.setMandatoryRouteInd(dynamicNode.getMandatoryRouteInd());
        splitNode.setNodeType(SimpleSplitNode.class.getName());
        splitNode.setRouteMethodCode("FR");
        splitNode.setRouteMethodName(null);
        splitNode.setRouteNodeName();
        return splitNode;
        //SubRequests
    }

    

Parameters:
process
Returns:
Route Node of the JoinNode that will be prototype for the join RouteNodeInstances generated by this component
    private static RouteNode getJoinNode(RouteNodeInstance process) {
        RouteNode dynamicNode = process.getRouteNode();
        RouteNode joinNode = new RouteNode();
        joinNode.setActivationType(dynamicNode.getActivationType());
        joinNode.setDocumentType(dynamicNode.getDocumentType());
        joinNode.setFinalApprovalInd(dynamicNode.getFinalApprovalInd());
        joinNode.setExceptionWorkgroupId(dynamicNode.getExceptionWorkgroupId());
        joinNode.setMandatoryRouteInd(dynamicNode.getMandatoryRouteInd());
        joinNode.setNodeType(SimpleJoinNode.class.getName());
        joinNode.setRouteMethodCode("FR");
        joinNode.setRouteMethodName(null);
        joinNode.setRouteNodeName();
        return joinNode;
    }

    

Parameters:
process
Returns:
RouteNode of RequestsNode that will be prototype for RouteNodeInstances having requets that are generated by this component
    private RouteNode getRequestNode(HierarchyProvider providerRouteNodeInstance process) {
        RouteNode dynamicNode = process.getRouteNode();
        RouteNode requestsNode = new RouteNode();
        requestsNode.setActivationType(dynamicNode.getActivationType());
        requestsNode.setDocumentType(dynamicNode.getDocumentType());
        requestsNode.setFinalApprovalInd(dynamicNode.getFinalApprovalInd());
        requestsNode.setExceptionWorkgroupId(dynamicNode.getExceptionWorkgroupId());
        requestsNode.setMandatoryRouteInd(dynamicNode.getMandatoryRouteInd());
        requestsNode.setNodeType(RequestsNode.class.getName());
        requestsNode.setRouteMethodCode("FR");
        requestsNode.setRouteMethodName(process.getRouteNode().getRouteMethodName());
        requestsNode.setRouteNodeName();
        provider.configureRequestNode(processrequestsNode);
        return requestsNode;
    }

    

Parameters:
process
Returns:
RouteNode of a no-op node which will be used if the user sends no Chart+Org XML to this routing component.
    private static RouteNode getNoChartOrgNode(RouteNodeInstance process) {
        RouteNode dynamicNode = process.getRouteNode();
        RouteNode noChartOrgNOde = new RouteNode();
        noChartOrgNOde.setActivationType(dynamicNode.getActivationType());
        noChartOrgNOde.setDocumentType(dynamicNode.getDocumentType());
        noChartOrgNOde.setFinalApprovalInd(dynamicNode.getFinalApprovalInd());
        noChartOrgNOde.setExceptionWorkgroupId(dynamicNode.getExceptionWorkgroupId());
        noChartOrgNOde.setMandatoryRouteInd(dynamicNode.getMandatoryRouteInd());
        noChartOrgNOde.setNodeType(NoOpNode.class.getName());
        noChartOrgNOde.setRouteMethodCode("FR");
        noChartOrgNOde.setRouteMethodName(null);
        noChartOrgNOde.setRouteNodeName();
        return noChartOrgNOde;
    }
 
    
    // methods which can be overridden to change the chart org routing node behavior
    
    protected RouteNode getStopRequestNode(Stop stopDocumentType documentType) {
        return documentType.getNamedProcess().getInitialRouteNode();
    }
    
New to GrepCode? Check out our FAQ X