?? token.java
字號:
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jbpm.graph.exe;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmContext;
import org.jbpm.JbpmException;
import org.jbpm.db.JobSession;
import org.jbpm.graph.def.Event;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.def.Transition;
import org.jbpm.graph.log.SignalLog;
import org.jbpm.graph.log.TokenCreateLog;
import org.jbpm.graph.log.TokenEndLog;
import org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator;
import org.jbpm.logging.exe.LoggingInstance;
import org.jbpm.logging.log.CompositeLog;
import org.jbpm.logging.log.ProcessLog;
import org.jbpm.svc.Services;
import org.jbpm.taskmgmt.exe.TaskMgmtInstance;
import org.jbpm.util.Clock;
import org.jbpm.util.EqualsUtil;
/**
* represents one path of execution and maintains a pointer to a node
* in the {@link org.jbpm.graph.def.ProcessDefinition}. Most common
* way to get a hold of the token objects is with {@link ProcessInstance#getRootToken()}
* or {@link org.jbpm.graph.exe.ProcessInstance#findToken(String)}.
*/
public class Token implements Serializable {
private static final long serialVersionUID = 1L;
long id = 0;
int version = 0;
protected String name = null;
protected Date start = null;
protected Date end = null;
protected Node node = null;
protected Date nodeEnter = null;
protected ProcessInstance processInstance = null;
protected Token parent = null;
protected Map children = null;
protected List comments = null;
protected ProcessInstance subProcessInstance = null;
protected int nextLogIndex = 0;
boolean isAbleToReactivateParent = true;
boolean isTerminationImplicit = false;
boolean isSuspended = false;
String lock = null;
// constructors
/////////////////////////////////////////////////////////////////////////////
public Token() {
}
/**
* creates a root token.
*/
public Token(ProcessInstance processInstance) {
this.start = Clock.getCurrentTime();
this.processInstance = processInstance;
this.node = processInstance.getProcessDefinition().getStartState();
this.isTerminationImplicit = processInstance.getProcessDefinition().isTerminationImplicit();
// optimization: assigning an id is not necessary since the process instance will be saved shortly.
// Services.assignId(this);
}
/**
* creates a child token.
*/
public Token(Token parent, String name) {
this.start = Clock.getCurrentTime();
this.processInstance = parent.getProcessInstance();
this.name = name;
this.node = parent.getNode();
this.parent = parent;
parent.addChild(this);
this.isTerminationImplicit = parent.isTerminationImplicit();
parent.addLog(new TokenCreateLog(this));
// assign an id to this token before events get fired
Services.assignId(this);
}
// operations
/////////////////////////////////////////////////////////////////////////////
void addChild(Token token) {
if (children==null) {
children = new HashMap();
}
children.put(token.getName(), token);
}
/**
* provides a signal to the token. this method activates this token and leaves
* the current state over the default transition.
*/
public void signal() {
if (node==null) {
throw new JbpmException("token '" + this + "' can't be signalled cause it is currently not positioned in a node");
}
if (node.getDefaultLeavingTransition() == null) {
throw new JbpmException("couldn't signal token '" + this + "' : node '" + node + "' doesn't have a default transition");
}
signal(node.getDefaultLeavingTransition(), new ExecutionContext(this));
}
/**
* provides a signal to the token. this leave the current state over the given
* transition name.
*/
public void signal(String transitionName) {
if (node==null) {
throw new JbpmException("token '" + this + "' can't be signalled cause it is currently not positioned in a node");
}
if (node.getDefaultLeavingTransition() == null) {
throw new JbpmException("couldn't signal token '" + this + "' : node '" + node + "' doesn't have a default transition");
}
Transition leavingTransition = node.getLeavingTransition(transitionName);
if (leavingTransition==null) {
throw new JbpmException("transition '"+transitionName+"' does not exist on "+node);
}
signal(leavingTransition, new ExecutionContext(this));
}
/**
* provides a signal to the token. this leave the current state over the given
* transition name.
*/
public void signal(Transition transition) {
signal(transition, new ExecutionContext(this));
}
void signal(ExecutionContext executionContext) {
signal(node.getDefaultLeavingTransition(), executionContext);
}
void signal(Transition transition, ExecutionContext executionContext) {
if (transition == null) {
throw new JbpmException("couldn't signal without specifying a leaving transition : transition is null");
}
if (executionContext == null) {
throw new JbpmException("couldn't signal without an execution context: executionContext is null");
}
if (isSuspended) {
throw new JbpmException("can't signal token '"+name+"' ("+id+"): it is suspended");
}
if (isLocked()) {
throw new JbpmException("this token is locked by "+lock);
}
startCompositeLog(new SignalLog(transition));
try {
// fire the event before-signal
Node signalNode = node;
signalNode.fireEvent(Event.EVENTTYPE_BEFORE_SIGNAL, executionContext);
// start calculating the next state
node.leave(executionContext, transition);
// if required, check if this token is implicitly terminated
checkImplicitTermination();
// fire the event after-signal
signalNode.fireEvent(Event.EVENTTYPE_AFTER_SIGNAL, executionContext);
} finally {
endCompositeLog();
}
}
/**
* a set of all the leaving transitions on the current node for which the condition expression resolves to true.
*/
public Set getAvailableTransitions() {
Set availableTransitions = new HashSet();
if (node!=null) {
addAvailableTransitionsOfNode(node, availableTransitions);
}
return availableTransitions;
}
/**
* adds available transitions of that node to the Set
* and after that calls itself recursivly for the SuperSate of the Node
* if it has a super state
*/
private void addAvailableTransitionsOfNode(Node currentNode, Set availableTransitions) {
List leavingTransitions = currentNode.getLeavingTransitions();
if (leavingTransitions!=null) {
Iterator iter = leavingTransitions.iterator();
while (iter.hasNext()) {
Transition transition = (Transition) iter.next();
String conditionExpression = transition.getCondition();
if (conditionExpression!=null) {
Object result = JbpmExpressionEvaluator.evaluate(conditionExpression, new ExecutionContext(this));
if ( (result instanceof Boolean)
&& (((Boolean)result).booleanValue())
) {
availableTransitions.add(transition);
}
} else {
availableTransitions.add(transition);
}
}
}
if (currentNode.getSuperState() != null) {
addAvailableTransitionsOfNode(currentNode.getSuperState(), availableTransitions);
}
}
/**
* ends this token and all of its children (if any). this is the last active (=not-ended) child of a parent token,
* the parent token will be ended as well and that verification will continue to
* propagate.
*/
public void end() {
end(true);
}
/**
* ends this token with optional parent ending verification.
* @param verifyParentTermination specifies if the parent token should be checked for termination.
* if verifyParentTermination is set to true and this is the last non-ended child of a parent token,
* the parent token will be ended as well and the verification will continue to propagate.
*/
public void end(boolean verifyParentTermination) {
// if not already ended
if (end==null) {
// ended tokens cannot reactivate parents
isAbleToReactivateParent = false;
// set the end date
// the end date is also the flag that indicates that this token has ended.
this.end = Clock.getCurrentTime();
// end all this token's children
if (children != null) {
Iterator iter = children.values().iterator();
while (iter.hasNext()) {
Token child = (Token) iter.next();
if (!child.hasEnded()) {
child.end();
}
}
}
if (subProcessInstance!=null) {
subProcessInstance.end();
}
// only log the end of child-tokens. the process instance logs replace the root token logs.
if (parent!=null) {
// add a log
parent.addLog(new TokenEndLog(this));
}
// if there are tasks associated to this token, remove signalling capabilities
TaskMgmtInstance taskMgmtInstance = (processInstance!=null ? processInstance.getTaskMgmtInstance() : null);
if (taskMgmtInstance!=null) {
taskMgmtInstance.removeSignalling(this);
}
if (verifyParentTermination) {
// if this is the last active token of the parent,
// the parent needs to be ended as well
notifyParentOfTokenEnd();
}
}
}
// comments /////////////////////////////////////////////////////////////////
public void addComment(String message) {
addComment(new Comment(message));
}
public void addComment(Comment comment) {
if (comments==null) comments = new ArrayList();
comments.add(comment);
comment.setToken(this);
}
public List getComments() {
return comments;
}
// operations helper methods ////////////////////////////////////////////////
/**
* notifies a parent that one of its nodeMap has ended.
*/
void notifyParentOfTokenEnd() {
if (isRoot()) {
processInstance.end();
} else {
if (!parent.hasActiveChildren()) {
parent.end();
}
}
}
/**
* tells if this token has child tokens that have not yet ended.
*/
public boolean hasActiveChildren() {
boolean foundActiveChildToken = false;
// try and find at least one child token that is
// still active (= not ended)
if (children!=null) {
Iterator iter = children.values().iterator();
while ((iter.hasNext()) && (!foundActiveChildToken)) {
Token child = (Token) iter.next();
if (!child.hasEnded()) {
foundActiveChildToken = true;
}
}
}
return foundActiveChildToken;
}
// log convenience methods //////////////////////////////////////////////////
/**
* convenience method for adding a process log.
*/
public void addLog(ProcessLog processLog) {
LoggingInstance li = (LoggingInstance) processInstance.getInstance(LoggingInstance.class);
if (li != null) {
processLog.setToken(this);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -