Package org.jbpm.graph.def

Source Code of org.jbpm.graph.def.GraphElement

/*
* 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.def;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.command.ExecuteActionCommand;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.RuntimeAction;
import org.jbpm.graph.exe.Token;
import org.jbpm.graph.log.ActionLog;
import org.jbpm.msg.Message;
import org.jbpm.msg.MessageService;
import org.jbpm.svc.Services;
import org.jbpm.util.EqualsUtil;

public abstract class GraphElement implements Serializable {
 
  private static final long serialVersionUID = 1L;

  long id = 0;
  protected String name = null;
  protected ProcessDefinition processDefinition = null;
  protected Map events = null;
  protected List exceptionHandlers = null;

  public GraphElement() {
  }
 
  public GraphElement( String name ) {
    setName( name );
  }

  // events ///////////////////////////////////////////////////////////////////

  /**
   * indicative set of event types supported by this graph element.
   * this is currently only used by the process designer to know which
   * event types to show on a given graph element.  in process definitions
   * and at runtime, there are no contstraints on the event-types.
   */
  public abstract String[] getSupportedEventTypes();

  /**
   * gets the events, keyd by eventType (java.lang.String).
   */
  public Map getEvents() {
    return events;
  }

  public boolean hasEvents() {
    return ( (events!=null)
             && (events.size()>0) );
  }

  public Event getEvent(String eventType) {
    Event event = null;
    if (events!=null) {
      event = (Event) events.get(eventType);
    }
    return event;
  }
 
  public boolean hasEvent(String eventType) {
    boolean hasEvent = false;
    if (events!=null) {
      hasEvent = events.containsKey(eventType);
    }
    return hasEvent;
  }
 
  public Event addEvent(Event event) {
    if (event == null) throw new IllegalArgumentException("can't add a null event to a graph element");
    if (event.getEventType() == null) throw new IllegalArgumentException("can't add an event without an eventType to a graph element");
    if (events == null) events = new HashMap();
    events.put(event.getEventType(), event);
    event.graphElement = this;
    return event;
  }
 
  public Event removeEvent(Event event) {
    Event removedEvent = null;
    if (event == null) throw new IllegalArgumentException("can't remove a null event from a graph element");
    if (event.getEventType() == null) throw new IllegalArgumentException("can't remove an event without an eventType from a graph element");
    if (events != null) {
      removedEvent = (Event) events.remove(event.getEventType());
      if (removedEvent!=null) {
        event.graphElement = null;
      }
    }
    return removedEvent;
  }

  // exception handlers ///////////////////////////////////////////////////////

  /**
   * is the list of exception handlers associated to this graph element.
   */
  public List getExceptionHandlers() {
    return exceptionHandlers;
  }
 
  public ExceptionHandler addExceptionHandler(ExceptionHandler exceptionHandler) {
    if (exceptionHandler == null) throw new IllegalArgumentException("can't add a null exceptionHandler to a graph element");
    if (exceptionHandlers == null) exceptionHandlers = new ArrayList();
    exceptionHandlers.add(exceptionHandler);
    exceptionHandler.graphElement = this;
    return exceptionHandler;
  }
 
  public void removeExceptionHandler(ExceptionHandler exceptionHandler) {
    if (exceptionHandler == null) throw new IllegalArgumentException("can't remove a null exceptionHandler from an graph element");
    if (exceptionHandlers != null) {
      if (exceptionHandlers.remove(exceptionHandler)) {
        exceptionHandler.graphElement = null;
      }
    }
  }

  public void reorderExceptionHandler(int oldIndex, int newIndex) {
    if ( (exceptionHandlers!=null)
         && (Math.min(oldIndex, newIndex)>=0)
         && (Math.max(oldIndex, newIndex)<exceptionHandlers.size()) ) {
      Object o = exceptionHandlers.remove(oldIndex);
      exceptionHandlers.add(newIndex, o);
    } else {
      throw new IndexOutOfBoundsException("couldn't reorder element from index '"+oldIndex+"' to index '"+newIndex+"' in exceptionHandler-list '"+exceptionHandlers+"'");
    }
  }

  // event handling ///////////////////////////////////////////////////////////

  public void fireEvent(String eventType, ExecutionContext executionContext) {
    Token token = executionContext.getToken();

    log.debug( "event '"+eventType+"' on '"+this+"' for '"+token+"'" );

    try {
      executionContext.setEventSource(this);
      fireAndPropagateEvent(eventType, executionContext);
    } finally {
      executionContext.setEventSource(null);
    }
  }

  public void fireAndPropagateEvent(String eventType, ExecutionContext executionContext) {
    // calculate if the event was fired on this element or if it was a propagated event
    boolean isPropagated = (this.equals(executionContext.getEventSource()));
   
    // execute static actions
    Event event = getEvent(eventType);
    if (event!=null) {
      // update the context
      executionContext.setEvent(event);
      // execute the static actions specified in the process definition
      executeActions(event.getActions(), executionContext, isPropagated);
    }
   
    // execute the runtime actions
    List runtimeActions = getRuntimeActionsForEvent(executionContext, eventType);
    executeActions(runtimeActions, executionContext, isPropagated);

    // remove the event from the context
    executionContext.setEvent(null);
   
    // propagate the event to the parent element
    GraphElement parent = getParent();
    if (parent!=null) {
      parent.fireAndPropagateEvent(eventType, executionContext);
    }
  }

  void executeActions(List actions, ExecutionContext executionContext, boolean isPropagated) {
    if (actions!=null) {
      Iterator iter = actions.iterator();
      while (iter.hasNext()) {
        Action action = (Action) iter.next();
        if ( action.acceptsPropagatedEvents()
             || (!isPropagated)
           ) {
          if (action.isAsync()) {
            Message continuationMsg = new ExecuteActionCommand(action, executionContext.getToken());
            MessageService messageService = (MessageService) Services.getCurrentService(Services.SERVICENAME_MESSAGE);
            messageService.send(continuationMsg);
          } else {
            executeAction(action, executionContext);
          }
        }
      }
    }
  }

  public void executeAction(Action action, ExecutionContext executionContext) {
    Token token = executionContext.getToken();

    // create action log
    ActionLog actionLog = new ActionLog(action);
    token.startCompositeLog(actionLog);

    try {
      // update the execution context
      executionContext.setAction(action);

      // execute the action
      log.debug("executing action '"+action+"'");
      try {
        token.lock();
       
        action.execute(executionContext);

      } finally {
        token.unlock();
      }
  
    } catch (Throwable exception) {
      log.error("action threw exception: "+exception.getMessage(), exception);
     
      // log the action exception
      actionLog.setException(exception);
  
      // if an exception handler is available
      raiseException(exception, executionContext);
     
    } finally {
      executionContext.setAction(null);
      token.endCompositeLog();
    }
  }

  List getRuntimeActionsForEvent(ExecutionContext executionContext, String eventType) {
    List runtimeActionsForEvent = null;
    List runtimeActions = executionContext.getProcessInstance().getRuntimeActions();
    if (runtimeActions!=null) {
      Iterator iter = runtimeActions.iterator();
      while (iter.hasNext()) {
        RuntimeAction runtimeAction = (RuntimeAction) iter.next();
        // if the runtime-action action is registered on this element and this eventType
        if ( (this==runtimeAction.getGraphElement())
             && (eventType.equals(runtimeAction.getEventType()))
           ) {
          // ... add its action to the list of runtime actions
          if (runtimeActionsForEvent==null) runtimeActionsForEvent = new ArrayList();
          runtimeActionsForEvent.add(runtimeAction.getAction());
        }
      }
    }
    return runtimeActionsForEvent;
  }

/*   
      // the next instruction merges the actions specified in the process definition with the runtime actions
      List actions = event.collectActions(executionContext);
     
      // loop over all actions of this event
      Iterator iter = actions.iterator();
      while (iter.hasNext()) {
        Action action = (Action) iter.next();
        executionContext.setAction(action);
       
        if ( (!isPropagated)
             || (action.acceptsPropagatedEvents() ) ) {
     
          // create action log
          ActionLog actionLog = new ActionLog(action);
          executionContext.getToken().startCompositeLog(actionLog);
     
          try {
            // execute the action
            action.execute(executionContext);
     
          } catch (Throwable exception) {
            Event.log.error("action threw exception: "+exception.getMessage(), exception);
           
            // log the action exception
            actionLog.setException(exception);
     
            // if an exception handler is available
            event.graphElement.raiseException(exception, executionContext);
          } finally {
            executionContext.getToken().endCompositeLog();
          }
        }
      }
    }
*/

  /**
   * throws an ActionException if no applicable exception handler is found.
   * An ExceptionHandler is searched for in this graph element and then recursively up the
   * parent hierarchy. 
   * If an exception handler is found, it is applied.  If the exception handler does not
   * throw an exception, the exception is considered handled.  Otherwise the search for
   * an applicable exception handler continues where it left of with the newly thrown
   * exception.
   */
  public void raiseException(Throwable exception, ExecutionContext executionContext) throws DelegationException {
    boolean isHandled = false;
    if (exceptionHandlers!=null) {
      try {
        ExceptionHandler exceptionHandler = findExceptionHandler(exception);
        if (exceptionHandler!=null) {
          executionContext.setException(exception);
          exceptionHandler.handleException(executionContext);
          isHandled = true;
        }
      } catch (Throwable t) {
        exception = t;
      }
    }

    if (!isHandled) {
      GraphElement parent = getParent();
      // if this graph element has a parent
      if ( (parent!=null)
           && (parent!=this) ){
        // action to the parent
        parent.raiseException(exception, executionContext);
      } else {
        // rollback the actions
        // rollbackActions(executionContext);
       
        // if there is no parent we need to throw an action exception to the client
        throw new DelegationException(exception, executionContext);
      }
    }
  }

  protected ExceptionHandler findExceptionHandler(Throwable exception) {
    ExceptionHandler exceptionHandler = null;
   
    if (exceptionHandlers!=null) {
      Iterator iter = exceptionHandlers.iterator();
      while (iter.hasNext() && (exceptionHandler==null)) {
        ExceptionHandler candidate = (ExceptionHandler) iter.next();
        if (candidate.matches(exception)) {
          exceptionHandler = candidate;
        }
      }
    }
   
    return exceptionHandler;
  }

  public GraphElement getParent() {
    return processDefinition;
  }

  /**
   * @return all the parents of this graph element ordered by age.
   */
  public List getParents() {
    List parents = new ArrayList();
    GraphElement parent = getParent();
    if (parent!=null) {
      parent.addParentChain(parents);
    }
    return parents;
  }

  /**
   * @return this graph element plus all the parents ordered by age.
   */
  public List getParentChain() {
    List parents = new ArrayList();
    this.addParentChain(parents);
    return parents;
  }

  void addParentChain(List parentChain) {
    parentChain.add(this);
    GraphElement parent = getParent();
    if (parent!=null) {
      parent.addParentChain(parentChain);
    }
  }
 
  public String toString() {
    String className = getClass().getName();
    className = className.substring(className.lastIndexOf('.')+1);
    if (name!=null) {
      className = className+"("+name+")";
    } else {
      className = className+"("+Integer.toHexString(System.identityHashCode(this))+")";
    }
    return className;
  }

  // equals ///////////////////////////////////////////////////////////////////
  // hack to support comparing hibernate proxies against the real objects
  // since this always falls back to ==, we don't need to overwrite the hashcode
  public boolean equals(Object o) {
    return EqualsUtil.equals(this, o);
  }
 
  // getters and setters //////////////////////////////////////////////////////
 
  public long getId() {
    return id;
  }
  public String getName() {
    return name;
  }
  public void setName( String name ) {
    this.name = name;
  }

  public ProcessDefinition getProcessDefinition() {
    return processDefinition;
  }
  public void setProcessDefinition(ProcessDefinition processDefinition) {
    this.processDefinition = processDefinition;
  }
 
  // logger ///////////////////////////////////////////////////////////////////
  private static final Log log = LogFactory.getLog(GraphElement.class);
}
TOP

Related Classes of org.jbpm.graph.def.GraphElement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.