001: /*
002: * Copyright 2005-2006 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.engine.transition;
018:
019: import java.util.HashSet;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Set;
023:
024: import edu.iu.uis.eden.engine.RouteContext;
025: import edu.iu.uis.eden.engine.node.DynamicNode;
026: import edu.iu.uis.eden.engine.node.DynamicResult;
027: import edu.iu.uis.eden.engine.node.ProcessResult;
028: import edu.iu.uis.eden.engine.node.RouteNode;
029: import edu.iu.uis.eden.engine.node.RouteNodeInstance;
030: import edu.iu.uis.eden.exception.RouteManagerException;
031:
032: /**
033: * The DynamicTransitionEngine operates on a {@link DynamicNode} and takes the next node instances returned
034: * by the node and runs returns them in a TransitionResult after doing some processing and validation on them.
035: *
036: * @see DynamicNode
037: *
038: * @author rkirkend
039: * @author ewestfal
040: */
041: public class DynamicTransitionEngine extends TransitionEngine {
042:
043: // TODO interate the all the nodes and attach the dynamic node as the 'process'
044: // don't include the dynamic node instance in the routing structure - require a correctly built graph
045: // change dynamic node signiture to next node because of above
046: // reconcile branching if necessary
047: public RouteNodeInstance transitionTo(
048: RouteNodeInstance dynamicNodeInstance, RouteContext context)
049: throws Exception {
050: dynamicNodeInstance.setInitial(false);
051: dynamicNodeInstance.setActive(false);
052: DynamicNode dynamicNode = (DynamicNode) getNode(
053: dynamicNodeInstance.getRouteNode(), DynamicNode.class);
054: DynamicResult result = dynamicNode.transitioningInto(context,
055: dynamicNodeInstance, getRouteHelper());
056: RouteNodeInstance nextNodeInstance = result
057: .getNextNodeInstance();
058: RouteNodeInstance finalNodeInstance = null;
059: if (result.isComplete()) {
060: dynamicNodeInstance.setComplete(true);
061: finalNodeInstance = getFinalNodeInstance(
062: dynamicNodeInstance, context);
063: if (nextNodeInstance == null) {
064: nextNodeInstance = finalNodeInstance;
065: }
066: }
067:
068: if (nextNodeInstance != null) {
069: initializeNodeGraph(context, dynamicNodeInstance,
070: nextNodeInstance, new HashSet(), finalNodeInstance);
071: }
072: return nextNodeInstance;
073: }
074:
075: public ProcessResult isComplete(RouteContext context)
076: throws Exception {
077: throw new UnsupportedOperationException(
078: "isComplete() should not be invoked on a Dynamic node!");
079: }
080:
081: public Transition transitionFrom(RouteContext context,
082: ProcessResult processResult) throws Exception {
083:
084: Transition transition = new Transition();
085: RouteNodeInstance dynamicNodeInstance = context
086: .getNodeInstance().getProcess();
087: DynamicNode dynamicNode = (DynamicNode) getNode(
088: dynamicNodeInstance.getRouteNode(), DynamicNode.class);
089: DynamicResult result = dynamicNode.transitioningOutOf(context,
090: getRouteHelper());
091: if (result.getNextNodeInstance() == null
092: && result.getNextNodeInstances().isEmpty()
093: && result.isComplete()) {
094: dynamicNodeInstance.setComplete(true);
095: RouteNodeInstance finalNodeInstance = getFinalNodeInstance(
096: dynamicNodeInstance, context);
097: if (finalNodeInstance != null) {
098: transition.getNextNodeInstances()
099: .add(finalNodeInstance);
100: }
101: } else {
102: if (result.getNextNodeInstance() != null) {
103: result.getNextNodeInstance().setProcess(
104: dynamicNodeInstance);
105: transition.getNextNodeInstances().add(
106: result.getNextNodeInstance());
107: }
108: for (Iterator iter = result.getNextNodeInstances()
109: .iterator(); iter.hasNext();) {
110: RouteNodeInstance nextNodeInstance = (RouteNodeInstance) iter
111: .next();
112: nextNodeInstance.setProcess(dynamicNodeInstance);
113: }
114: transition.getNextNodeInstances().addAll(
115: result.getNextNodeInstances());
116: }
117: return transition;
118: }
119:
120: /**
121: * This method checks the next node returned by the user and walks the resulting node graph, filling in required data where possible.
122: * Will throw errors if there is a problem with what the implementor has returned to us. This allows them to do things like return next
123: * nodes with no attached branches, and we will go ahead and generate the branches for them, etc.
124: */
125: private void initializeNodeGraph(RouteContext context,
126: RouteNodeInstance dynamicNodeInstance,
127: RouteNodeInstance nodeInstance, Set nodeInstances,
128: RouteNodeInstance finalNodeInstance) throws Exception {
129: if (nodeInstances.contains(nodeInstance)) {
130: throw new RouteManagerException(
131: "A cycle was detected in the node graph returned from the dynamic node.",
132: context);
133: }
134: nodeInstances.add(nodeInstance);
135: nodeInstance.setProcess(dynamicNodeInstance);
136: List nextNodeInstances = nodeInstance.getNextNodeInstances();
137:
138: if (nextNodeInstances.size() > 1) {
139: // TODO implement this feature
140: // throw new UnsupportedOperationException("Need to implement support for branch generation!");
141: }
142: for (Iterator iterator = nextNodeInstances.iterator(); iterator
143: .hasNext();) {
144: RouteNodeInstance nextNodeInstance = (RouteNodeInstance) iterator
145: .next();
146: initializeNodeGraph(context, dynamicNodeInstance,
147: nextNodeInstance, nodeInstances, finalNodeInstance);
148: }
149: if (nextNodeInstances.isEmpty() && finalNodeInstance != null) {
150: nodeInstance.addNextNodeInstance(finalNodeInstance);
151: }
152: }
153:
154: private RouteNodeInstance getFinalNodeInstance(
155: RouteNodeInstance dynamicNodeInstance, RouteContext context)
156: throws Exception {
157: List nextNodes = dynamicNodeInstance.getRouteNode()
158: .getNextNodes();
159: if (nextNodes.size() > 1) {
160: throw new RouteManagerException(
161: "There should only be 1 next node following a dynamic node, there were "
162: + nextNodes.size(), context);
163: }
164: RouteNodeInstance finalNodeInstance = null;
165: if (!nextNodes.isEmpty()) {
166: finalNodeInstance = getRouteHelper().getNodeFactory()
167: .createRouteNodeInstance(
168: context.getDocument().getRouteHeaderId(),
169: (RouteNode) nextNodes.get(0));
170: finalNodeInstance
171: .setBranch(dynamicNodeInstance.getBranch());
172: finalNodeInstance.setProcess(dynamicNodeInstance
173: .getProcess());
174: }
175: return finalNodeInstance;
176: }
177: }
|