/*
|
* 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.pvm.internal.model;
|
|
import java.util.ArrayList;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
import org.jbpm.api.activity.ActivityBehaviour;
|
import org.jbpm.pvm.internal.util.ReflectUtil;
|
import org.jbpm.pvm.internal.wire.Descriptor;
|
|
/**
|
* @author Tom Baeyens
|
*/
|
public class ActivityImpl extends CompositeElementImpl implements Activity {
|
|
private static final long serialVersionUID = 1L;
|
|
protected ActivityBehaviour activityBehaviour;
|
protected boolean isActivityBehaviourStateful = false;
|
protected Descriptor activityBehaviourDescriptor;
|
|
protected List<TransitionImpl> outgoingTransitions = new ArrayList<TransitionImpl>();
|
protected List<TransitionImpl> incomingTransitions = new ArrayList<TransitionImpl>();
|
protected TransitionImpl defaultOutgoingTransition;
|
protected ActivityImpl parentActivity;
|
|
protected String type;
|
protected Continuation continuation = Continuation.SYNCHRONOUS;
|
|
protected ActivityCoordinatesImpl coordinates;
|
|
// Do not initialize. Caching is based on the nullity of this map
|
transient protected Map<String, TransitionImpl> outgoingTransitionsMap = null;
|
|
/**
|
* Use {@link ProcessDefinitionImpl#createActivity()} or {@link ActivityImpl#createActivity()} instead.
|
*/
|
public ActivityImpl() {
|
super();
|
}
|
|
// specialized activity containment methods /////////////////////////////////////
|
|
public ActivityImpl addActivity(ActivityImpl activity) {
|
activity.setParentActivity(this);
|
super.addActivity(activity);
|
return activity;
|
}
|
|
public ActivityImpl findActivity(String activityName) {
|
if (activityName==null) {
|
if (name==null) {
|
return this;
|
}
|
} else if (activityName.equals(name)) {
|
return this;
|
}
|
return super.findActivity(activityName);
|
}
|
|
// outgoing transitions //////////////////////////////////////////////////////
|
|
/** creates an outgoing transition from this activity. */
|
public TransitionImpl createOutgoingTransition() {
|
// create a new transition
|
TransitionImpl transition = new TransitionImpl();
|
transition.setProcessDefinition(processDefinition);
|
|
// wire it between the source and destination
|
addOutgoingTransition(transition);
|
|
// if there is no default transition yet
|
if (defaultOutgoingTransition==null) {
|
// make this the default outgoing transition
|
defaultOutgoingTransition = transition;
|
}
|
|
return transition;
|
}
|
|
/**
|
* adds the given transition as a leaving transition to this activity.
|
* Also the source of the transition is set to this activity.
|
* 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) {
|
if (! outgoingTransitions.contains(transition)) {
|
transition.setSource(this);
|
transition.setSourceIndex(outgoingTransitions.size());
|
outgoingTransitions.add(transition);
|
clearOutgoingTransitionsMap();
|
}
|
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 activity'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) {
|
boolean isRemoved = outgoingTransitions.remove(transition);
|
if (isRemoved) {
|
transition.setSource(null);
|
clearOutgoingTransitionsMap();
|
}
|
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 activity 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 (parentActivity!=null) {
|
return parentActivity.findOutgoingTransition(transitionName);
|
}
|
return null;
|
}
|
|
/** searches for the default transition in this activity and then up the
|
* parent chain. Returns null if no such transition is found. */
|
public TransitionImpl findDefaultTransition() {
|
if (defaultOutgoingTransition!=null) {
|
return defaultOutgoingTransition;
|
}
|
if (parentActivity!=null) {
|
return parentActivity.findDefaultTransition();
|
}
|
return null;
|
}
|
|
|
/** the list of leaving transitions.
|
* Beware: the actual member is returned. No copy is made.
|
*/
|
public List<Transition> 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 activity has leaving transitions */
|
public boolean hasOutgoingTransitions() {
|
return !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 activity.
|
* In case there was a leaving transitions list present, these transition's
|
* source will be nulled.
|
*/
|
public void setOutgoingTransitions(List<TransitionImpl> outgoingTransitions) {
|
if (!this.outgoingTransitions.isEmpty()) {
|
List<TransitionImpl> removedTransitions = new ArrayList<TransitionImpl>(outgoingTransitions);
|
for (TransitionImpl removedTransition: removedTransitions) {
|
removeOutgoingTransition(removedTransition);
|
}
|
}
|
if (outgoingTransitions!=null) {
|
this.outgoingTransitions = new ArrayList<TransitionImpl>();
|
for (TransitionImpl addedTransition: outgoingTransitions) {
|
addOutgoingTransition(addedTransition);
|
}
|
} else {
|
this.outgoingTransitions = new ArrayList<TransitionImpl>();
|
}
|
clearOutgoingTransitionsMap();
|
}
|
|
// arriving transitions /////////////////////////////////////////////////////
|
|
/**
|
* adds the given transition as an arriving transition to this activity.
|
* Also the source of the transition is set to this activity.
|
* @return the added transition.
|
* @throws NullPointerException if transition is null.
|
*/
|
public Transition addIncomingTransition(TransitionImpl transition) {
|
transition.setDestination(this);
|
incomingTransitions.add(transition);
|
return transition;
|
}
|
|
/** removes the given transition if it is contained in the arriving
|
* transitions of this activity. 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.remove(transition))) {
|
transition.setDestination(null);
|
return true;
|
}
|
return false;
|
}
|
|
/** the list of arriving transitions.
|
* Beware: the actual member is returned. No copy is made.
|
*/
|
public List<Transition> getIncomingTransitions() {
|
return (List) incomingTransitions;
|
}
|
|
/** indicates if this activity has arriving transitions */
|
public boolean hasIncomingTransitions() {
|
return !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 activity.
|
* In case there was an arriving transitions list present, these transition's
|
* destination will be nulled.
|
*/
|
public void setIncomingTransitions(List<TransitionImpl> incomingTransitions) {
|
if (!this.incomingTransitions.isEmpty()) {
|
for (TransitionImpl removedTransition: this.incomingTransitions) {
|
removedTransition.setDestination(null);
|
}
|
}
|
if (incomingTransitions!=null) {
|
this.incomingTransitions = new ArrayList<TransitionImpl>(incomingTransitions);
|
for (TransitionImpl addedTransition: incomingTransitions) {
|
addedTransition.setDestination(this);
|
}
|
} else {
|
this.incomingTransitions = 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<String, Transition> getOutgoingTransitionsMap() {
|
if(outgoingTransitionsMap == null){
|
this.outgoingTransitionsMap = new HashMap<String, TransitionImpl>();
|
for (TransitionImpl transition: outgoingTransitions) {
|
if (! this.outgoingTransitionsMap.containsKey(transition.getName())) {
|
this.outgoingTransitionsMap.put(transition.getName(), transition);
|
}
|
}
|
}
|
return (Map) outgoingTransitionsMap;
|
}
|
|
void clearOutgoingTransitionsMap() {
|
outgoingTransitionsMap = null;
|
}
|
|
// various helper methods ///////////////////////////////////////////////////
|
|
|
static Map<String, ActivityImpl> getActivitiesMap(List<ActivityImpl> activities) {
|
Map<String, ActivityImpl> map = null;
|
if (activities!=null) {
|
map = new HashMap<String, ActivityImpl>();
|
for (ActivityImpl activity: activities) {
|
if (! map.containsKey(activity.getName())) {
|
map.put(activity.getName(), activity);
|
}
|
}
|
}
|
return map;
|
}
|
|
public String toString() {
|
if (name!=null) return "activity("+name+")";
|
if (dbid!=0) return "activity("+dbid+")";
|
return "activity("+System.identityHashCode(this)+")";
|
}
|
|
/** collects the full stack of parent in a list. This activity is the
|
* first element in the chain. The process definition will be the last element.
|
* the chain will never be null. */
|
public List<ObservableElementImpl> getParentChain() {
|
List<ObservableElementImpl> chain = new ArrayList<ObservableElementImpl>();
|
ObservableElementImpl processElement = this;
|
while (processElement!=null) {
|
chain.add(processElement);
|
processElement = processElement.getParent();
|
}
|
return chain;
|
}
|
|
public boolean isAsync() {
|
return ! (continuation==Continuation.SYNCHRONOUS);
|
}
|
|
public boolean contains(ActivityImpl activity) {
|
while (activity!=null) {
|
if (activity.getParent()==this) {
|
return true;
|
}
|
activity = activity.getParentActivity();
|
}
|
return false;
|
}
|
|
// customized getters and setters ///////////////////////////////////////////
|
|
public ActivityBehaviour getActivityBehaviour() {
|
if (activityBehaviour!=null) {
|
return activityBehaviour;
|
}
|
if (activityBehaviourDescriptor!=null) {
|
ActivityBehaviour createdBehaviour = (ActivityBehaviour) ReflectUtil.instantiateUserCode(activityBehaviourDescriptor, processDefinition);
|
if (!isActivityBehaviourStateful) {
|
activityBehaviour = createdBehaviour;
|
}
|
return createdBehaviour;
|
}
|
return null;
|
}
|
|
// getters and setters //////////////////////////////////////////////////////
|
|
public ObservableElementImpl getParent() {
|
return (parentActivity!=null ? parentActivity : processDefinition);
|
}
|
|
public String getName() {
|
return name;
|
}
|
public void setName(String name) {
|
this.name = name;
|
}
|
public TransitionImpl getDefaultOutgoingTransition() {
|
return defaultOutgoingTransition;
|
}
|
public void setDefaultOutgoingTransition(TransitionImpl defaultOutgoingTransition) {
|
this.defaultOutgoingTransition = defaultOutgoingTransition;
|
}
|
public ActivityImpl getParentActivity() {
|
return parentActivity;
|
}
|
public void setParentActivity(ActivityImpl parentActivity) {
|
this.parentActivity = parentActivity;
|
}
|
public String getType() {
|
return type;
|
}
|
public void setType(String type) {
|
this.type = type;
|
}
|
public ActivityCoordinatesImpl getCoordinates() {
|
return coordinates;
|
}
|
public void setCoordinates(ActivityCoordinatesImpl coordinates) {
|
this.coordinates = coordinates;
|
}
|
public Continuation getContinuation() {
|
return continuation;
|
}
|
public void setContinuation(Continuation continuation) {
|
this.continuation = continuation;
|
}
|
public void setActivityBehaviour(ActivityBehaviour activityBehaviour) {
|
this.activityBehaviour = activityBehaviour;
|
}
|
public Descriptor getActivityBehaviourDescriptor() {
|
return activityBehaviourDescriptor;
|
}
|
public void setActivityBehaviourDescriptor(Descriptor activityBehaviourDescriptor) {
|
this.activityBehaviourDescriptor = activityBehaviourDescriptor;
|
}
|
public boolean isActivityBehaviourStateful() {
|
return isActivityBehaviourStateful;
|
}
|
public void setActivityBehaviourStateful(boolean isActivityBehaviourStateful) {
|
this.isActivityBehaviourStateful = isActivityBehaviourStateful;
|
}
|
}
|