KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jbpm > graph > exe > Token


1 package org.jbpm.graph.exe;
2
3 import java.io.*;
4 import java.util.*;
5 import org.jbpm.graph.def.*;
6 import org.jbpm.graph.log.*;
7 import org.jbpm.logging.exe.*;
8 import org.jbpm.logging.log.*;
9
10 /**
11  * represents one path of execution and maintains a pointer to a node
12  * in the {@link org.jbpm.graph.def.ProcessDefinition}. Most common
13  * way to get a hold of the token objects is with {@link ProcessInstance#getRootToken()}
14  * or {@link org.jbpm.graph.exe.ProcessInstance#findToken(String)}.
15  */

16 public class Token implements Serializable {
17
18   private static final long serialVersionUID = 1L;
19
20   long id = 0;
21   protected String JavaDoc name = null;
22   protected Date start = null;
23   protected Date end = null;
24   protected Node node = null;
25   protected Date nodeEnter = null;
26   protected ProcessInstance processInstance = null;
27   protected Token parent = null;
28   protected Map children = null;
29   protected List comments = null;
30   protected ProcessInstance subProcessInstance = null;
31   protected int nextLogIndex = 0;
32   boolean isAbleToReactivateParent = true;
33   boolean isTerminationImplicit = false;
34   
35   // logs should not be retrieved from the database to perform a workflow
36
// operation on a token. therefor, the logs here are transient. all
37
// workflow logs are just added. when this token is saved to the database,
38
// these logs should just be appended to the logs in the database.
39
transient List logs = null;
40   transient CompositeLog currentOperationLog = null;
41
42   // constructors
43
/////////////////////////////////////////////////////////////////////////////
44

45   public Token() {
46   }
47
48   /**
49    * creates a root token.
50    */

51   public Token(ProcessInstance processInstance) {
52     this.start = new Date();
53     this.processInstance = processInstance;
54     this.node = processInstance.getProcessDefinition().getStartState();
55     this.isTerminationImplicit = processInstance.getProcessDefinition().isTerminationImplicit();
56   }
57
58   /**
59    * creates a child token.
60    */

61   public Token(Token parent, String JavaDoc name) {
62     this.start = new Date();
63     this.processInstance = parent.getProcessInstance();
64     this.name = name;
65     this.node = parent.node;
66     this.parent = parent;
67     parent.addChild(this);
68     this.isTerminationImplicit = parent.isTerminationImplicit;
69     this.currentOperationLog = parent.currentOperationLog;
70     
71     parent.addLog(new TokenCreateLog(this));
72   }
73
74   // operations
75
/////////////////////////////////////////////////////////////////////////////
76

77   private void addChild(Token token) {
78     if (children==null) {
79       children = new HashMap();
80     }
81     children.put(token.getName(), token);
82   }
83
84   /**
85    * provides a signal to the token. this method activates this token and leaves
86    * the current state over the default transition.
87    */

88   public void signal() {
89     if ( (node == null) || (node.getDefaultLeavingTransition() == null)) {
90       throw new IllegalStateException JavaDoc("couldn't signal token '" + this + "' : couldn't leave node '" + node + "' over its default transition");
91     }
92     signal(node.getDefaultLeavingTransition());
93   }
94
95   /**
96    * provides a signal to the token. this leave the current state over the given
97    * transition name.
98    */

99   public void signal(String JavaDoc transitionName) {
100     if ((node == null) || (node.getLeavingTransition(transitionName) == null)) {
101       throw new IllegalStateException JavaDoc("couldn't signal token '" + this + "' : couldn't leave node '" + node + "' over the its transition '" + transitionName
102               + "'");
103     }
104     signal(node.getLeavingTransition(transitionName));
105   }
106   
107   /**
108    * provides a signal to the token. this leave the current state over the given
109    * transition name.
110    */

111   public void signal(Transition transition) {
112     if (transition == null) {
113       throw new IllegalArgumentException JavaDoc("couldn't signal without specifying a leaving transition : transition is null");
114     }
115
116     startCompositeLog(new SignalLog(transition));
117     try {
118       
119       // create the execution context
120
ExecutionContext executionContext = new ExecutionContext(this);
121       
122       // fire the event before-signal
123
Node signalNode = node;
124       signalNode.fireEvent(Event.EVENTTYPE_BEFORE_SIGNAL, executionContext);
125       
126       // start calculating the next state
127
node.leave(executionContext, transition);
128       
129       // if required, check if this token is implicitly terminated
130
checkImplicitTermination();
131       
132       // fire the event after-signal
133
signalNode.fireEvent(Event.EVENTTYPE_AFTER_SIGNAL, executionContext);
134       
135     } finally {
136       endCompositeLog();
137     }
138   }
139
140   /**
141    * ends this token and all of its children (if any). this is the last active (=not-ended) child of a parent token,
142    * the parent token will be ended as well and that verification will continue to
143    * propagate.
144    */

145   public void end() {
146     end(true);
147   }
148   
149   /**
150    * ends this token with optional parent ending verification.
151    * @param verifyParentTermination specifies if the parent token should be checked for termination.
152    * if verifyParentTermination is set to true and this is the last non-ended child of a parent token,
153    * the parent token will be ended as well and the verification will continue to propagate.
154    */

155   public void end(boolean verifyParentTermination) {
156     // if not already ended
157
if (end==null) {
158
159       // ended tokens cannot reactivate parents
160
isAbleToReactivateParent = false;
161       
162       // set the end date
163
// the end date is also the flag that indicates that this token has ended.
164
this.end = new Date();
165       
166       // end all this token's children
167
if (children != null) {
168         Iterator iter = children.values().iterator();
169         while (iter.hasNext()) {
170           Token child = (Token) iter.next();
171           if (!child.hasEnded()) {
172             child.end();
173           }
174         }
175       }
176       
177       // only log the end of child-tokens. the process instance logs replace the root token logs.
178
if (parent!=null) {
179         // add a log
180
parent.addLog(new TokenEndLog(this));
181       }
182       
183       if (verifyParentTermination) {
184         // if this is the last active token of the parent,
185
// the parent needs to be ended as well
186
notifyParentOfTokenEnd();
187       }
188     }
189   }
190   
191   // comments /////////////////////////////////////////////////////////////////
192

193   public void addComment(String JavaDoc message) {
194     addComment(new Comment(message));
195   }
196
197   public void addComment(Comment comment) {
198     if (comments==null) comments = new ArrayList();
199     comments.add(comment);
200     comment.setToken(this);
201   }
202   
203   public List getComments() {
204     return comments;
205   }
206  
207   // operations helper methods ////////////////////////////////////////////////
208

209   /**
210    * notifies a parent that one of its nodeMap has ended.
211    */

212   private void notifyParentOfTokenEnd() {
213     if (isRoot()) {
214       processInstance.end();
215     } else {
216       
217       if (!parent.hasActiveChildren()) {
218         parent.end();
219       }
220     }
221   }
222
223   /**
224    * tells if this token has child tokens that have not yet ended.
225    */

226   public boolean hasActiveChildren() {
227     boolean foundActiveChildToken = false;
228     // try and find at least one child token that is
229
// still active (= not ended)
230
Iterator iter = children.values().iterator();
231     while ((iter.hasNext()) && (!foundActiveChildToken)) {
232       Token child = (Token) iter.next();
233       if (!child.hasEnded()) {
234         foundActiveChildToken = true;
235       }
236     }
237     return foundActiveChildToken;
238   }
239
240   // log convenience methods //////////////////////////////////////////////////
241

242   /**
243    * convenience method for adding a process log.
244    */

245   public void addLog(ProcessLog processLog) {
246     LoggingInstance li = (LoggingInstance) processInstance.getInstance(LoggingInstance.class);
247     if (li != null) {
248       processLog.setToken(this);
249       li.addLog(processLog);
250     }
251   }
252   /**
253    * convenience method for starting a composite log. When you add composite logs,
254    * make sure you put the {@link #endCompositeLog()} in a finally block.
255    */

256   public void startCompositeLog(CompositeLog compositeLog) {
257     LoggingInstance li = (LoggingInstance) processInstance.getInstance(LoggingInstance.class);
258     if (li != null) {
259       compositeLog.setToken(this);
260       li.startCompositeLog(compositeLog);
261     }
262   }
263   /**
264    * convenience method for ending a composite log. Make sure you put this in a finally block.
265    */

266   public void endCompositeLog() {
267     LoggingInstance li = (LoggingInstance) processInstance.getInstance(LoggingInstance.class);
268     if (li != null) {
269       li.endCompositeLog();
270     }
271   }
272
273   // various information extraction methods ///////////////////////////////////
274

275   public String JavaDoc toString() {
276     return "Token("+getFullName()+")";
277   }
278
279   public boolean hasEnded() {
280     return (end != null);
281   }
282
283   public boolean isRoot() {
284     return (parent == null);
285   }
286
287   public boolean hasParent() {
288     return (parent != null);
289   }
290
291   public boolean hasChild(String JavaDoc name) {
292     return (children != null ? children.containsKey(name) : false);
293   }
294
295   public Token getChild(String JavaDoc name) {
296     Token child = null;
297     if (children != null) {
298       child = (Token) children.get(name);
299     }
300     return child;
301   }
302
303   public String JavaDoc getFullName() {
304     if (parent==null) return "/";
305     if (parent.getParent()==null) return "/"+name;
306     return parent.getFullName()+"/"+name;
307   }
308
309   public List getChildrenAtNode(Node aNode) {
310     List foundChildren = new ArrayList();
311     getChildrenAtNode(aNode, foundChildren);
312     return foundChildren;
313   }
314   
315   private void getChildrenAtNode(Node aNode, List foundTokens) {
316     if(aNode.equals(node)) {
317       foundTokens.add(this);
318     }
319     else if(children != null && !children.isEmpty()) {
320       for(Iterator it = children.values().iterator(); it.hasNext();) {
321         Token aChild = (Token)it.next();
322         aChild.getChildrenAtNode(aNode, foundTokens);
323       }
324     }
325   }
326   
327   public Token findToken(String JavaDoc relativeTokenPath) {
328     if (relativeTokenPath == null)
329       return null;
330     String JavaDoc path = relativeTokenPath.trim();
331     if (("".equals(path)) || (".".equals(path))) {
332       return this;
333     }
334     if ("..".equals(path)) {
335       return parent;
336     }
337     if (path.startsWith("/")) {
338       Token root = processInstance.getRootToken();
339       return root.findToken(path.substring(1));
340     }
341     if (path.startsWith("./")) {
342       return findToken(path.substring(2));
343     }
344     if (path.startsWith("../")) {
345       if (parent != null) {
346         return parent.findToken(path.substring(3));
347       }
348       return null;
349     }
350     int slashIndex = path.indexOf('/');
351     if (slashIndex == -1) {
352       return (Token) (children != null ? children.get(path) : null);
353     }
354     Token token = null;
355     String JavaDoc name = path.substring(0, slashIndex);
356     token = (Token) children.get(name);
357     if (token != null) {
358       return token.findToken(path.substring(slashIndex + 1));
359     }
360     return null;
361   }
362
363   public Map getActiveChildren() {
364     Map activeChildren = new HashMap();
365     if (children != null) {
366       Iterator iter = children.entrySet().iterator();
367       while (iter.hasNext()) {
368         Map.Entry entry = (Map.Entry) iter.next();
369         Token child = (Token) entry.getValue();
370         if (!child.hasEnded()) {
371           String JavaDoc childName = (String JavaDoc) entry.getKey();
372           activeChildren.put(childName, child);
373         }
374       }
375     }
376     return activeChildren;
377   }
378
379   public void checkImplicitTermination() {
380     if (isTerminationImplicit && node.hasNoLeavingTransitions()) {
381       end();
382       
383       if (processInstance.isTerminatedImplicitly()) {
384         processInstance.end();
385       }
386     }
387   }
388
389   public boolean isTerminatedImplicitly() {
390     if (end != null) return true;
391
392     Map leavingTransitions = node.getLeavingTransitionsMap();
393     if ((leavingTransitions != null) && (leavingTransitions.size() > 0)) {
394       // ok: found a non-terminated token
395
return false;
396     }
397
398     // loop over all active child tokens
399
Iterator iter = getActiveChildren().values().iterator();
400     while (iter.hasNext()) {
401       Token child = (Token) iter.next();
402       if (!child.isTerminatedImplicitly()) {
403         return false;
404       }
405     }
406     // if none of the above, this token is terminated implicitly
407
return true;
408   }
409
410   public int nextLogIndex() {
411     return nextLogIndex++;
412   }
413
414   // getters and setters
415
/////////////////////////////////////////////////////////////////////////////
416

417   public long getId() {
418     return id;
419   }
420   public Date getStart() {
421     return start;
422   }
423   public Date getEnd() {
424     return end;
425   }
426   public String JavaDoc getName() {
427     return name;
428   }
429   public ProcessInstance getProcessInstance() {
430     return processInstance;
431   }
432   public Map getChildren() {
433     return children;
434   }
435   public Node getNode() {
436     return node;
437   }
438   public void setNode(Node node) {
439     this.node = node;
440   }
441   public Token getParent() {
442     return parent;
443   }
444   public void setParent(Token parent) {
445     this.parent = parent;
446   }
447   public void setProcessInstance(ProcessInstance processInstance) {
448     this.processInstance = processInstance;
449   }
450   public ProcessInstance getSubProcessInstance() {
451     return subProcessInstance;
452   }
453   public void setSubProcessInstance(ProcessInstance subProcessInstance) {
454     this.subProcessInstance = subProcessInstance;
455   }
456   public Date getNodeEnter() {
457     return nodeEnter;
458   }
459   public void setNodeEnter(Date nodeEnter) {
460     this.nodeEnter = nodeEnter;
461   }
462   public boolean isAbleToReactivateParent() {
463     return isAbleToReactivateParent;
464   }
465   public void setAbleToReactivateParent(boolean isAbleToReactivateParent) {
466     this.isAbleToReactivateParent = isAbleToReactivateParent;
467   }
468   public boolean isTerminationImplicit() {
469     return isTerminationImplicit;
470   }
471   public void setTerminationImplicit(boolean isTerminationImplicit) {
472     this.isTerminationImplicit = isTerminationImplicit;
473   }
474   // private static final Log log = LogFactory.getLog(Token.class);
475
}
476
Popular Tags