All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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.activity.Activity;
import org.ow2.bonita.pvm.internal.wire.Descriptor;
import org.ow2.bonita.pvm.model.Node;
import org.ow2.bonita.pvm.model.Transition;
import org.ow2.bonita.util.BonitaRuntimeException;
import org.ow2.bonita.util.ExceptionManager;

/**
 * @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 PVMProcessDefinitionImpl#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.
   */
  @SuppressWarnings("unchecked")
  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.
   */
  @SuppressWarnings("unchecked")
  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.
   */
  @SuppressWarnings("unchecked")
  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) {
    	String message = ExceptionManager.getInstance().getFullMessage(
    			"bp_NI_1", this);
      throw new BonitaRuntimeException(message);
    }
    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