KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jbpm > graph > def > Node


1 package org.jbpm.graph.def;
2
3 import java.util.ArrayList JavaDoc;
4 import java.util.Date JavaDoc;
5 import java.util.HashMap JavaDoc;
6 import java.util.HashSet JavaDoc;
7 import java.util.Iterator JavaDoc;
8 import java.util.List JavaDoc;
9 import java.util.Map JavaDoc;
10 import java.util.Set JavaDoc;
11
12 import org.dom4j.Element;
13 import org.jbpm.graph.action.ActionTypes;
14 import org.jbpm.graph.exe.ExecutionContext;
15 import org.jbpm.graph.exe.Token;
16 import org.jbpm.graph.log.NodeLog;
17 import org.jbpm.jpdl.xml.JpdlXmlReader;
18 import org.jbpm.jpdl.xml.Parsable;
19
20 public class Node extends GraphElement implements Parsable {
21   
22   private static final long serialVersionUID = 1L;
23   
24   protected List JavaDoc leavingTransitions = null;
25   private transient Map JavaDoc leavingTransitionMap = null;
26   protected Set JavaDoc arrivingTransitions = null;
27   protected Action action = null;
28   protected SuperState superState = null;
29
30
31   // event types //////////////////////////////////////////////////////////////
32

33   public static final String JavaDoc[] supportedEventTypes = new String JavaDoc[]{Event.EVENTTYPE_NODE_ENTER,Event.EVENTTYPE_NODE_LEAVE,Event.EVENTTYPE_BEFORE_SIGNAL,Event.EVENTTYPE_AFTER_SIGNAL};
34   public String JavaDoc[] getSupportedEventTypes() {
35     return supportedEventTypes;
36   }
37
38   // constructors /////////////////////////////////////////////////////////////
39

40   /**
41    * creates an unnamed node.
42    */

43   public Node() {
44   }
45
46   /**
47    * creates a node with the given name.
48    */

49   public Node(String JavaDoc name) {
50     super(name);
51   }
52
53   public void read(Element nodeElement, JpdlXmlReader jpdlXmlReader) {
54     action = jpdlXmlReader.readSingleAction(nodeElement);
55   }
56
57   public void write(Element nodeElement) {
58     if (action!=null) {
59       String JavaDoc actionName = ActionTypes.getActionName(action.getClass());
60       Element actionElement = nodeElement.addElement(actionName);
61       action.write(actionElement);
62     }
63   }
64
65   // leaving transitions //////////////////////////////////////////////////////
66

67   public List JavaDoc getLeavingTransitions() {
68     return leavingTransitions;
69   }
70
71   /**
72    * are the leaving {@link Transition}s, mapped by their name (java.lang.String).
73    */

74   public Map JavaDoc getLeavingTransitionsMap() {
75     if ( (leavingTransitionMap==null)
76          && (leavingTransitions!=null) ){
77       // initialize the cached leaving transition map
78
leavingTransitionMap = new HashMap JavaDoc();
79       Iterator JavaDoc iter = leavingTransitions.iterator();
80       while (iter.hasNext()) {
81         Transition leavingTransition = (Transition) iter.next();
82         leavingTransitionMap.put(leavingTransition.getName(), leavingTransition);
83       }
84     }
85     return leavingTransitionMap;
86   }
87
88   /**
89    * creates a bidirection relation between this node and the given leaving transition.
90    * @throws IllegalArgumentException if leavingTransition is null.
91    */

92   public Transition addLeavingTransition(Transition leavingTransition) {
93     if (leavingTransition == null) throw new IllegalArgumentException JavaDoc("can't add a null leaving transition to an node");
94     if (leavingTransitions == null) leavingTransitions = new ArrayList JavaDoc();
95     leavingTransitions.add(leavingTransition);
96     leavingTransition.from = this;
97     leavingTransitionMap = null;
98     return leavingTransition;
99   }
100
101   /**
102    * removes the bidirection relation between this node and the given leaving transition.
103    * @throws IllegalArgumentException if leavingTransition is null.
104    */

105   public void removeLeavingTransition(Transition leavingTransition) {
106     if (leavingTransition == null) throw new IllegalArgumentException JavaDoc("can't remove a null leavingTransition from an node");
107     if (leavingTransitions != null) {
108       if (leavingTransitions.remove(leavingTransition)) {
109         leavingTransition.from = null;
110         leavingTransitionMap = null;
111       }
112     }
113   }
114
115   /**
116    * checks for the presence of a leaving transition with the given name.
117    * @return true if this node has a leaving transition with the given name,
118    * false otherwise.
119    */

120   public boolean hasLeavingTransition(String JavaDoc transitionName) {
121     if (leavingTransitions==null) return false;
122     return getLeavingTransitionsMap().containsKey(transitionName);
123   }
124
125   /**
126    * retrieves a leaving transition by name. note that also the leaving
127    * transitions of the supernode are taken into account.
128    */

129   public Transition getLeavingTransition(String JavaDoc transitionName) {
130     Transition transition = null;
131     if (leavingTransitions!=null) {
132       transition = (Transition) getLeavingTransitionsMap().get(transitionName);
133     }
134     if ( (transition==null)
135          && (superState!=null)
136        ) {
137       transition = superState.getLeavingTransition(transitionName);
138     }
139     return transition;
140   }
141
142   /**
143    * true if this transition has leaving transitions.
144    */

145   public boolean hasNoLeavingTransitions() {
146     return ( ( (leavingTransitions == null)
147                || (leavingTransitions.size() == 0) )
148              && ( (superState==null)
149                   || (superState.hasNoLeavingTransitions() ) ) );
150   }
151
152   /**
153    * generates a new name for a transition that will be added as a leaving transition.
154    */

155   public String JavaDoc generateNextLeavingTransitionName() {
156     String JavaDoc name = null;
157     if (leavingTransitions!=null) {
158       if (!containsName(leavingTransitions, null)) {
159         name = null;
160       } else {
161         int n = 1;
162         while (containsName(leavingTransitions, Integer.toString(n))) n++;
163         name = Integer.toString(n);
164       }
165     }
166     return name;
167   }
168
169   private boolean containsName(List JavaDoc leavingTransitions, String JavaDoc name) {
170     Iterator JavaDoc iter = leavingTransitions.iterator();
171     while (iter.hasNext()) {
172       Transition transition = (Transition) iter.next();
173       if ( (name==null) && (transition.getName()==null) ) {
174         return true;
175       } else if ( (name!=null) && (name.equals(transition.getName())) ) {
176         return true;
177       }
178     }
179     return false;
180   }
181
182   // default leaving transition and leaving transition ordering ///////////////
183

184   /**
185    * is the default leaving transition.
186    */

187   public Transition getDefaultLeavingTransition() {
188     Transition defaultTransition = null;
189     if ( (leavingTransitions!=null)
190          && (leavingTransitions.size()>0) ) {
191       defaultTransition = (Transition) leavingTransitions.get(0);
192     } else if ( superState!=null ){
193       defaultTransition = superState.getDefaultLeavingTransition();
194     }
195     return defaultTransition;
196   }
197
198   /**
199    * moves one leaving transition from the oldIndex and inserts it at the newIndex.
200    */

201   public void reorderLeavingTransition( int oldIndex, int newIndex ) {
202     if ( (leavingTransitions!=null)
203          && (Math.min(oldIndex, newIndex)>=0)
204          && (Math.max(oldIndex, newIndex)<leavingTransitions.size()) ) {
205       Object JavaDoc o = leavingTransitions.remove(oldIndex);
206       leavingTransitions.add(newIndex, o);
207     }
208   }
209
210   public List JavaDoc getLeavingTransitionsList() {
211     return leavingTransitions;
212   }
213
214   // arriving transitions /////////////////////////////////////////////////////
215

216   /**
217    * are the arriving transitions.
218    */

219   public Set JavaDoc getArrivingTransitions() {
220     return arrivingTransitions;
221   }
222
223   /**
224    * add a bidirection relation between this node and the given arriving
225    * transition.
226    * @throws IllegalArgumentException if t is null.
227    */

228   public Transition addArrivingTransition(Transition arrivingTransition) {
229     if (arrivingTransition == null) throw new IllegalArgumentException JavaDoc("can't add a null arrivingTransition to a node");
230     if (arrivingTransitions == null) arrivingTransitions = new HashSet JavaDoc();
231     arrivingTransitions.add(arrivingTransition);
232     arrivingTransition.to = this;
233     return arrivingTransition;
234   }
235
236   /**
237    * removes the bidirection relation between this node and the given arriving
238    * transition.
239    * @throws IllegalArgumentException if t is null.
240    */

241   public void removeArrivingTransition(Transition arrivingTransition) {
242     if (arrivingTransition == null) throw new IllegalArgumentException JavaDoc("can't remove a null arrivingTransition from a node");
243     if (arrivingTransitions != null) {
244       if (arrivingTransitions.remove(arrivingTransition)) {
245         arrivingTransition.to = null;
246       }
247     }
248   }
249   
250   // various //////////////////////////////////////////////////////////////////
251

252   /**
253    * is the {@link SuperState} or the {@link ProcessDefinition} in which this
254    * node is contained.
255    */

256   public GraphElement getParent() {
257     GraphElement parent = processDefinition;
258     if (superState!=null) parent = superState;
259     return parent;
260   }
261
262   // behaviour methods ////////////////////////////////////////////////////////
263

264   /**
265    * called by a transition to pass execution to this node.
266    */

267   public void enter(ExecutionContext executionContext) {
268     Token token = executionContext.getToken();
269
270     // update the runtime context information
271
token.setNode(this);
272
273     // fire the leave-node event for this node
274
fireEvent(Event.EVENTTYPE_NODE_ENTER, executionContext);
275     
276     // keep track of node entrance in the token, so that a node-log can be generated at node leave time.
277
token.setNodeEnter(new Date JavaDoc());
278
279     // remove the transition references from the runtime context
280
executionContext.setTransition(null);
281     executionContext.setTransitionSource(null);
282
283     // execute the node
284
execute(executionContext);
285   }
286   
287   /**
288    * override this method to customize the node behaviour.
289    */

290   public void execute(ExecutionContext executionContext) {
291     // if there is a custom action associated with this node
292
if (action!=null) {
293       try {
294         // execute the action
295
action.execute(executionContext);
296
297       } catch (Throwable JavaDoc exception) {
298         // search for an exception handler or throw to the client
299
raiseException(exception, executionContext);
300       }
301
302     } else {
303       // let this node handle the token
304
// the default behaviour is to leave the node over the default transition.
305
leave(executionContext);
306     }
307   }
308
309   /**
310    * called by the implementation of this node to continue execution over the default transition.
311    */

312   public void leave(ExecutionContext executionContext) {
313     leave(executionContext, getDefaultLeavingTransition());
314   }
315
316   /**
317    * called by the implementation of this node to continue execution over the specified transition.
318    */

319   public void leave(ExecutionContext executionContext, String JavaDoc transitionName) {
320     Transition transition = getLeavingTransition(transitionName);
321     if (transition==null) {
322       throw new RuntimeException JavaDoc("transition '"+transitionName+"' is not a leaving transition of node '"+this+"'");
323     }
324     leave(executionContext, transition);
325   }
326
327   /**
328    * called by the implementation of this node to continue execution over the given transition.
329    */

330   public void leave(ExecutionContext executionContext, Transition transition) {
331     if (transition==null) throw new RuntimeException JavaDoc("can't leave node '"+this+"' without leaving transition");
332     Token token = executionContext.getToken();
333     token.setNode(this);
334     executionContext.setTransition(transition);
335     
336     // fire the leave-node event for this node
337
fireEvent(Event.EVENTTYPE_NODE_LEAVE, executionContext);
338     
339     // log this node
340
if (token.getNodeEnter()!=null) {
341       token.addLog(new NodeLog(this, token.getNodeEnter(), new Date JavaDoc()));
342     }
343
344     // update the runtime information for taking the transition
345
// the transitionSource is used to calculate events on superstates
346
executionContext.setTransitionSource(this);
347
348     // take the transition
349
transition.take(executionContext);
350   }
351
352   /////////////////////////////////////////////////////////////////////////////
353

354   public ProcessDefinition getProcessDefinition() {
355     ProcessDefinition pd = this.processDefinition;
356     if (superState!=null) {
357       pd = superState.getProcessDefinition();
358     }
359     return pd;
360   }
361
362   // change the name of a node ////////////////////////////////////////////////
363
/**
364    * updates the name of this node
365    */

366   public void setName(String JavaDoc name) {
367     if (isDifferent(this.name, name)) {
368       String JavaDoc oldName = this.name;
369       if (superState!=null) {
370         if ( superState.hasNode(name) ) {
371           throw new IllegalArgumentException JavaDoc("couldn't set name '"+name+"' on node '"+this+"'cause the superState of this node has already another child node with the same name");
372         }
373         Map JavaDoc nodes = superState.getNodesMap();
374         nodes.remove(oldName);
375         nodes.put(name,this);
376       } else if (processDefinition!=null) {
377         if ( processDefinition.hasNode(name) ) {
378           throw new IllegalArgumentException JavaDoc("couldn't set name '"+name+"' on node '"+this+"'cause the process definition of this node has already another node with the same name");
379         }
380         Map JavaDoc nodeMap = processDefinition.getNodesMap();
381         nodeMap.remove(oldName);
382         nodeMap.put(name,this);
383       }
384       this.name = name;
385     }
386   }
387   
388   private boolean isDifferent(String JavaDoc name1, String JavaDoc name2) {
389     if ((name1!=null)
390         && (name1.equals(name2))) {
391       return false;
392     } else if ( (name1==null)
393                 && (name2==null) ) {
394       return false;
395     }
396     return true;
397   }
398
399   /**
400    * the slash separated name that includes all the superstate names.
401    */

402   public String JavaDoc getFullyQualifiedName() {
403     String JavaDoc fullyQualifiedName = name;
404     if (superState!=null) {
405       fullyQualifiedName = superState.getFullyQualifiedName()+"/"+name;
406     }
407     return fullyQualifiedName;
408   }
409
410   // getters and setters //////////////////////////////////////////////////////
411

412   public SuperState getSuperState() {
413     return superState;
414   }
415   public Action getAction() {
416     return action;
417   }
418   public void setAction(Action action) {
419     this.action = action;
420   }
421
422   // logger ///////////////////////////////////////////////////////////////////
423
// private static final Log log = LogFactory.getLog(Node.class);
424
}
425
Popular Tags