
org.ow2.bonita.pvm.internal.model.NodeImpl Maven / Gradle / Ivy
/*
* 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.ow2.bonita.pvm.internal.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.ow2.bonita.pvm.PvmException;
import org.ow2.bonita.pvm.activity.Activity;
import org.ow2.bonita.pvm.internal.wire.Descriptor;
import org.ow2.bonita.pvm.model.Node;
import org.ow2.bonita.pvm.model.Transition;
/**
* @author Tom Baeyens
*/
public class NodeImpl extends CompositeElementImpl implements Node {
private static final long serialVersionUID = 1L;
protected ObjectReference behaviourReference;
protected List outgoingTransitions;
protected List incomingTransitions;
protected TransitionImpl defaultTransition;
protected NodeImpl parentNode;
protected boolean isLocalScope;
protected boolean isExecutionAsync;
protected boolean isSignalAsync;
protected boolean isLeaveAsync;
protected boolean isPreviousNeeded;
transient protected Map outgoingTransitionsMap;
/**
* Use {@link ProcessDefinitionImpl#createNode()} or
* {@link NodeImpl#createNode()} instead.
*/
public NodeImpl() {
super();
}
// specialized node containment methods /////////////////////////////////////
public NodeImpl addNode(NodeImpl node) {
node.setParentNode(this);
super.addNode(node);
return node;
}
public Node findNode(String nodeName) {
if (nodeName == null) {
if (name == null) {
return this;
}
} else if (nodeName.equals(name)) {
return this;
}
return super.findNode(nodeName);
}
// leaving transitions //////////////////////////////////////////////////////
/**
* creates a transition from this node to the given destination node. Also the
* transition pointers to source and destination node will be set
* appropriatly.
*
* @throws NullPointerException
* if destination is null.
*/
public Transition createOutgoingTransition(NodeImpl destination) {
return createOutgoingTransition(destination, null);
}
/**
* creates a transition with the given name from this node to the given
* destination node. Also the transition pointers to source and destination
* node will be set appropriatly.
*
* @param transitionName
* may be null.
* @throws NullPointerException
* if destination is null.
*/
public TransitionImpl createOutgoingTransition(NodeImpl destination,
String transitionName) {
TransitionImpl transition = createOutgoingTransition(transitionName);
if (destination != null) {
destination.addIncomingTransition(transition);
}
return transition;
}
public TransitionImpl createOutgoingTransition(String transitionName) {
// create a new transition
TransitionImpl transition = new TransitionImpl();
transition.setName(transitionName);
// wire it between the source and destination
addOutgoingTransition(transition);
// if there is no default transition yet
if (defaultTransition == null) {
// make this the default outgoing transition
defaultTransition = transition;
}
return transition;
}
/**
* adds the given transition as a leaving transition to this node. Also the
* source of the transition is set to this node. Adding a transition that is
* already contained in the leaving transitions has no effect.
*
* @return the added transition.
* @throws NullPointerException
* if transition is null.
*/
public Transition addOutgoingTransition(TransitionImpl transition) {
transition.setSource(this);
if (outgoingTransitions == null) {
outgoingTransitions = new ArrayList();
}
if (!outgoingTransitions.contains(transition)) {
outgoingTransitions.add(transition);
}
outgoingTransitionsMap = null;
return transition;
}
/**
* removes the given transition from the leaving transitions. Also the
* transition's source will be nulled. This method will do nothing if the
* transition is null or if the given transition is not in the list of this
* node's leaving transitions. In case this is the transition that was in the
* outgoingTransitionsMap and another transition exists with the same name,
* that transition (the first) will be put in the outgoingTransitionsMap as a
* replacement for the removed transition. If the transition is actually
* removed from the list of leaving transitions, the transition's source will
* be nulled.
*/
public boolean removeOutgoingTransition(TransitionImpl transition) {
if ((transition != null) && (outgoingTransitions != null)) {
boolean isRemoved = outgoingTransitions.remove(transition);
if (isRemoved) {
transition.setSource(null);
if (outgoingTransitions.isEmpty()) {
outgoingTransitions = null;
}
outgoingTransitionsMap = null;
}
return isRemoved;
}
return false;
}
/**
* the first leaving transition with the given name or null of no such leaving
* transition exists.
*/
public TransitionImpl getOutgoingTransition(String transitionName) {
return (getOutgoingTransitionsMap() != null ? outgoingTransitionsMap
.get(transitionName) : null);
}
/**
* searches for the given transitionName in this node and then up the parent
* chain. Returns null if no such transition is found.
*/
public TransitionImpl findOutgoingTransition(String transitionName) {
TransitionImpl transition = getOutgoingTransition(transitionName);
if (transition != null) {
return transition;
}
if (parentNode != null) {
return parentNode.findOutgoingTransition(transitionName);
}
return null;
}
/**
* searches for the default transition in this node and then up the parent
* chain. Returns null if no such transition is found.
*/
public TransitionImpl findDefaultTransition() {
if (defaultTransition != null) {
return defaultTransition;
}
if (parentNode != null) {
return parentNode.findDefaultTransition();
}
return null;
}
/**
* the list of leaving transitions. Beware: the actual member is returned. No
* copy is made.
*/
public List getOutgoingTransitions() {
return (List) outgoingTransitions;
}
/** indicates if a leaving transition with the given transitionName exists. */
public boolean hasOutgoingTransition(String transitionName) {
return (getOutgoingTransition(transitionName) != null);
}
/** indicates if this node has leaving transitions */
public boolean hasOutgoingTransitions() {
return ((outgoingTransitions != null) && (!outgoingTransitions.isEmpty()));
}
/**
* sets the outgoingTransitions to the given list of outgoingTransitions. A
* copy of the collection is made. Also the outgoingTransitionsMap will be
* updated and the source of all the transitions in the given list will be set
* to this node. In case there was a leaving transitions list present, these
* transition's source will be nulled.
*/
public void setOutgoingTransitions(List outgoingTransitions) {
if (this.outgoingTransitions != null) {
for (TransitionImpl removedTransition : this.outgoingTransitions) {
removedTransition.setSource(null);
}
}
if (outgoingTransitions != null) {
this.outgoingTransitions = new ArrayList(
outgoingTransitions);
for (TransitionImpl addedTransition : outgoingTransitions) {
addedTransition.setSource(this);
}
} else {
this.outgoingTransitions = null;
}
this.outgoingTransitionsMap = null;
}
/**
* the leaving transitions, keyed by transition name. If a transition with the
* same name occurs mutltiple times, the first one is returned. Leaving
* transitions with a null value for their name are not included in the map.
* Beware: the actual member is returned. No copy is made.
*/
public Map getOutgoingTransitionsMap() {
if (outgoingTransitionsMap == null) {
this.outgoingTransitionsMap = getTransitionsMap(outgoingTransitions);
}
return (Map) outgoingTransitionsMap;
}
// arriving transitions /////////////////////////////////////////////////////
/**
* adds the given transition as an arriving transition to this node. Also the
* source of the transition is set to this node.
*
* @return the added transition.
* @throws NullPointerException
* if transition is null.
*/
public Transition addIncomingTransition(TransitionImpl transition) {
transition.setDestination(this);
if (incomingTransitions == null) {
incomingTransitions = new ArrayList();
}
incomingTransitions.add(transition);
return transition;
}
/**
* removes the given transition if it is contained in the arriving transitions
* of this node. If this transition was actually removed, its destination
* pointer is nulled.
*
* @return true if a transition was removed.
*/
public boolean removeIncomingTransition(TransitionImpl transition) {
if ((transition != null) && (incomingTransitions != null)
&& (incomingTransitions.remove(transition))) {
transition.setDestination(null);
if (incomingTransitions.isEmpty()) {
incomingTransitions = null;
}
return true;
}
return false;
}
/**
* the list of arriving transitions. Beware: the actual member is returned. No
* copy is made.
*/
public List getIncomingTransitions() {
return (List) incomingTransitions;
}
/** indicates if this node has arriving transitions */
public boolean hasIncomingTransitions() {
return ((incomingTransitions != null) && (!incomingTransitions.isEmpty()));
}
/**
* sets the incomingTransitions to the given list of incomingTransitions. A
* copy of the collection is made. Also the destination of all the transitions
* in the given list will be set to this node. In case there was an arriving
* transitions list present, these transition's destination will be nulled.
*/
public void setIncomingTransitions(List incomingTransitions) {
if (this.incomingTransitions != null) {
for (TransitionImpl removedTransition : this.incomingTransitions) {
removedTransition.setDestination(null);
}
}
if (incomingTransitions != null) {
this.incomingTransitions = new ArrayList(
incomingTransitions);
for (TransitionImpl addedTransition : incomingTransitions) {
addedTransition.setDestination(this);
}
} else {
this.incomingTransitions = null;
}
}
// behaviour ////////////////////////////////////////////////////////////////
/**
* sets the given activity as the behaviour for this node. An object reference
* for the given activity is created.
*/
public void setBehaviour(Activity activity) {
behaviourReference = new ObjectReference(activity);
}
/**
* sets the activity that can be created from the given descriptor as the
* behaviour for this node. It is assumed that the descriptor will create an
* {@link Activity} An object reference for the given descriptor is created.
*/
public void setBehaviour(Descriptor descriptor) {
behaviourReference = new ObjectReference(descriptor);
}
/**
* sets the expression behaviour for this node. The evaluation of the
* expression will replace the
* {@link Activity#execute(org.ow2.bonita.pvm.Execution) Activity's execute
* method}. An object reference for the given descriptor is created.
*/
public void setBehaviour(String expression) {
behaviourReference = new ObjectReference(expression);
}
public ObjectReference getBehaviourReference() {
return behaviourReference;
}
public void setBehaviourReference(ObjectReference behaviourReference) {
this.behaviourReference = behaviourReference;
}
public Activity getBehaviour() {
Activity behaviour = (behaviourReference != null ? behaviourReference.get()
: null);
if (behaviour == null) {
throw new PvmException("no behaviour on " + this);
}
return behaviour;
}
// various helper methods ///////////////////////////////////////////////////
private static Map getTransitionsMap(
List transitions) {
Map map = null;
if (transitions != null) {
map = new HashMap();
for (TransitionImpl transition : transitions) {
if (!map.containsKey(transition.getName())) {
map.put(transition.getName(), transition);
}
}
}
return map;
}
static Map getNodesMap(List nodes) {
Map map = null;
if (nodes != null) {
map = new HashMap();
for (NodeImpl node : nodes) {
if (node.getName() != null) {
if (!map.containsKey(node.getName())) {
map.put(node.getName(), node);
}
}
}
}
return map;
}
public String toString() {
if (name != null)
return "node(" + name + ")";
if (dbid != 0)
return "node(" + dbid + ")";
return "node(" + System.identityHashCode(this) + ")";
}
/**
* collects the full stack of parent in a list. This node is the first element
* in the chain. The process definition will be the last element. the chain
* will never be null.
*/
public List getParentChain() {
List chain = new ArrayList();
ObservableElementImpl processElement = this;
while (processElement != null) {
chain.add(processElement);
processElement = processElement.getParent();
}
return chain;
}
// getters and setters //////////////////////////////////////////////////////
public ObservableElementImpl getParent() {
return (parentNode != null ? parentNode : processDefinition);
}
public String getName() {
return name;
}
public void setName(String name) {
// if there is no processDefinition associated with this node
if (processDefinition == null) {
// it s just a setter
this.name = name;
} else { // otherwise
// make sure the processDefinition's activitiesMap remains up to date
if (this.name != null) {
processDefinition.removeNode(this);
}
this.name = name;
if (name != null) {
processDefinition.addNode(this);
}
}
}
public TransitionImpl getDefaultTransition() {
return defaultTransition;
}
public void setDefaultTransition(TransitionImpl defaultTransition) {
this.defaultTransition = defaultTransition;
}
public NodeImpl getParentNode() {
return parentNode;
}
public void setParentNode(NodeImpl parentNode) {
this.parentNode = parentNode;
}
public boolean isExecutionAsync() {
return isExecutionAsync;
}
public boolean isSignalAsync() {
return isSignalAsync;
}
public void setSignalAsync(boolean isSignalAsync) {
this.isSignalAsync = isSignalAsync;
}
public void setExecutionAsync(boolean isExecutionAsync) {
this.isExecutionAsync = isExecutionAsync;
}
public boolean isLeaveAsync() {
return isLeaveAsync;
}
public void setLeaveAsync(boolean isLeaveAsync) {
this.isLeaveAsync = isLeaveAsync;
}
public boolean isPreviousNeeded() {
return isPreviousNeeded;
}
public void setPreviousNeeded(boolean isPreviousNeeded) {
this.isPreviousNeeded = isPreviousNeeded;
}
public boolean isLocalScope() {
return isLocalScope;
}
public void setLocalScope(boolean isLocalScope) {
this.isLocalScope = isLocalScope;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy