001: /*
002: * JBoss, Home of Professional Open Source
003: * Copyright 2005, JBoss Inc., and individual contributors as indicated
004: * by the @authors tag. See the copyright.txt in the distribution for a
005: * full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jbpm.graph.node;
023:
024: import java.util.ArrayList;
025: import java.util.Collection;
026:
027: import org.dom4j.Element;
028: import org.jbpm.JbpmException;
029: import org.jbpm.context.def.ContextDefinition;
030: import org.jbpm.context.exe.ContextInstance;
031: import org.jbpm.graph.def.Node;
032: import org.jbpm.graph.def.ProcessDefinition;
033: import org.jbpm.graph.exe.ExecutionContext;
034: import org.jbpm.graph.exe.Token;
035: import org.jbpm.jpdl.xml.JpdlXmlReader;
036: import org.jbpm.jpdl.xml.Parsable;
037:
038: /**
039: * is an unordered set of child nodeMap. the path of execution will
040: * be given to each node exactly once. the sequence of the child
041: * nodeMap will be determined at runtime. this implements the
042: * workflow pattern interleved parallel routing.
043: *
044: * If no script is supplied, the transition names will be sequenced
045: * in arbitrary order.
046: * If a script is provided, the variable transitionNames contains the
047: * available transition names. The returned value has to be one of
048: * those transitionNames.
049: * Instead of supplying a script, its also possible to subclass this
050: * class and override the selectTransition method.
051: */
052: public class InterleaveStart extends Node implements Parsable {
053:
054: private static final long serialVersionUID = 1L;
055:
056: String variableName = "interleave-transition-names";
057: Interleaver interleaver = new DefaultInterleaver();
058:
059: public interface Interleaver {
060: String selectNextTransition(Collection transitionNames);
061: }
062:
063: public class DefaultInterleaver implements Interleaver {
064: public String selectNextTransition(Collection transitionNames) {
065: return (String) transitionNames.iterator().next();
066: }
067: }
068:
069: public InterleaveStart() {
070: }
071:
072: public InterleaveStart(String name) {
073: super (name);
074: }
075:
076: public void read(Element element, JpdlXmlReader jpdlReader) {
077: // TODO
078:
079: // just making sure that the context definition is present
080: // because the interleave node needs the context instance at runtime
081: ProcessDefinition processDefinition = jpdlReader
082: .getProcessDefinition();
083: if (processDefinition.getDefinition(ContextDefinition.class) == null) {
084: processDefinition.addDefinition(new ContextDefinition());
085: }
086: }
087:
088: public void write(Element element) {
089: // TODO
090: }
091:
092: public void execute(ExecutionContext executionContext) {
093: Token token = executionContext.getToken();
094: Collection transitionNames = retrieveTransitionNames(token);
095: // if this is the first time we enter
096: if (transitionNames == null) {
097: // collect all leaving transition names
098: transitionNames = new ArrayList(getTransitionNames(token));
099: }
100:
101: // select one of the remaining transition names
102: String nextTransition = interleaver
103: .selectNextTransition(transitionNames);
104: // remove it from the remaining transitions
105: transitionNames.remove(nextTransition);
106:
107: // store the transition names
108: storeTransitionNames(transitionNames, token);
109:
110: // pass the token over the selected transition
111: token.getNode().leave(executionContext, nextTransition);
112: }
113:
114: protected Collection getTransitionNames(Token token) {
115: Node node = token.getNode();
116: return node.getLeavingTransitionsMap().keySet();
117: }
118:
119: protected void storeTransitionNames(Collection transitionNames,
120: Token token) {
121: ContextInstance ci = (ContextInstance) token
122: .getProcessInstance()
123: .getInstance(ContextInstance.class);
124: if (ci == null)
125: throw new JbpmException(
126: "an interleave start node requires the availability of a context");
127: ci.setVariable(variableName, transitionNames, token);
128: }
129:
130: public Collection retrieveTransitionNames(Token token) {
131: ContextInstance ci = (ContextInstance) token
132: .getProcessInstance()
133: .getInstance(ContextInstance.class);
134: return (Collection) ci.getVariable(variableName, token);
135: }
136:
137: public void removeTransitionNames(Token token) {
138: ContextInstance ci = (ContextInstance) token
139: .getProcessInstance()
140: .getInstance(ContextInstance.class);
141: ci.setVariable(variableName, null, token);
142: }
143:
144: public Interleaver getInterleaver() {
145: return interleaver;
146: }
147:
148: public void setInterleaver(Interleaver interleaver) {
149: this.interleaver = interleaver;
150: }
151: }
|