Package org.infoglue.cms.util.workflow

Source Code of org.infoglue.cms.util.workflow.WorkflowFacade

/* ===============================================================================
*
* Part of the InfoGlue Content Management Platform (www.infoglue.org)
*
* ===============================================================================
*
*  Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2, as published by the
* Free Software Foundation. See the file LICENSE.html for more information.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY, including the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc. / 59 Temple
* Place, Suite 330 / Boston, MA 02111-1307 / USA.
*
* ===============================================================================
*/

package org.infoglue.cms.util.workflow;

import java.util.ArrayList;
import java.util.Collection;
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 net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.cfg.Configuration;

import org.apache.log4j.Logger;
import org.infoglue.cms.entities.mydesktop.WorkflowActionVO;
import org.infoglue.cms.entities.mydesktop.WorkflowStepVO;
import org.infoglue.cms.entities.mydesktop.WorkflowVO;
import org.infoglue.cms.exception.SystemException;
import org.infoglue.cms.security.InfoGluePrincipal;
import org.infoglue.deliver.util.CacheController;

import com.opensymphony.module.propertyset.PropertySet;
import com.opensymphony.workflow.AbstractWorkflow;
import com.opensymphony.workflow.InvalidActionException;
import com.opensymphony.workflow.StoreException;
import com.opensymphony.workflow.WorkflowException;
import com.opensymphony.workflow.config.DefaultConfiguration;
import com.opensymphony.workflow.loader.ActionDescriptor;
import com.opensymphony.workflow.loader.StepDescriptor;
import com.opensymphony.workflow.loader.WorkflowDescriptor;
import com.opensymphony.workflow.query.Expression;
import com.opensymphony.workflow.query.FieldExpression;
import com.opensymphony.workflow.query.NestedExpression;
import com.opensymphony.workflow.query.WorkflowExpressionQuery;
import com.opensymphony.workflow.spi.Step;
import com.opensymphony.workflow.spi.WorkflowEntry;

/**
* A facade to OSWorkflow that gives us a place to cache workflow data as we need it while interacting with it.
* This class has kind of a strange interface due to the idiosyncracies of the OSWorkflow, particularly
* the Workflow interface.  The idea is to encapsulate the interactions with OSWorkflow and eliminate the
* need to pass a Workflow reference and the workflow ID all over the place when extracting data from OSWorkflow
* @author <a href="mailto:jedprentice@gmail.com">Jed Prentice</a>
* @version $Revision: 1.42 $ $Date: 2010/02/22 08:14:28 $
*/
public class WorkflowFacade
{
  /**
   * If the following attribute is specified in the workflow meta attributes,
   * The title will be fetch from the propertyset associated with the workflow, using the meta value as a key.
   */
  private static final String WORKFLOW_TITLE_EXTENSION_META_ATTRIBUTE = "org.infoglue.title";
 
  /**
   * If the following attribute is specified in the workflow meta attributes,
   * then all actions will have access to a DatabaseSession instance controlled by this class.
   */
  private static final String WORKFLOW_DATABASE_EXTENSION_META_ATTRIBUTE = "org.infoglue.database";
 
 
  private final static Logger logger = Logger.getLogger(WorkflowFacade.class.getName());

  private static SessionFactory hibernateSessionFactory;

  static
  {
    try
    {
      hibernateSessionFactory = new Configuration().configure().buildSessionFactory();
    }
    catch (HibernateException e)
    {
      logger.error("An exception occurred when we tried to initialize the hibernateSessionFactory", e);
      throw new ExceptionInInitializerError(e);
    }
  }
 
  /**
   * Keep track of the workflows that is currently executing.
   */
  private static final Collection currentWorkflows = new ArrayList();

  private final AbstractWorkflow workflow;
  private long workflowId;

  private WorkflowDescriptor workflowDescriptor;

  /**
   * Constructs a WorkflowFacade with the given owner.
   *
   * @param owner the owner of the workflow.
   */

  public WorkflowFacade(final Owner owner)
  {
    this(owner, true);
  }

  /**
   * Constructs a WorkflowFacade with the given owner.
   *
   * @param owner the owner of the workflow.
   */
 
  public WorkflowFacade(final Owner owner, boolean createSession)
  {
    workflow = new InfoGlueBasicWorkflow(owner.getIdentifier());
    workflow.getConfiguration().getPersistenceArgs().put("sessionFactory", hibernateSessionFactory);

    if(createSession)
    {
      try
      {
        Session session = hibernateSessionFactory.openSession();
        try
        {
          Map args = new HashMap();
          args.put("sessionFactory", hibernateSessionFactory);
          args.put("session", session);
          workflow.getConfiguration().getWorkflowStore().init(args);
        }
        catch (StoreException e)
        {
          e.printStackTrace();
        }

        workflow.getConfiguration().getPersistenceArgs().put("session", session);
      }
      catch (HibernateException e)
      {
        e.printStackTrace();
      }
    }
  }
 
  /**
   * Constructs a WorkflowFacade with the given owner.
   *
   * @param owner the owner of the workflow.
   */
  public WorkflowFacade(final Owner owner, SessionFactory sessionFactory, Session session)
  {
    if(sessionFactory != null)
      hibernateSessionFactory = sessionFactory;
   
    workflow = new InfoGlueBasicWorkflow(owner.getIdentifier());
    if(session != null)
    {
      com.opensymphony.workflow.config.Configuration config = new /*InfoGlueHibernate*/DefaultConfiguration();
      config.getPersistenceArgs().put("session", session);
      config.getPersistenceArgs().put("sessionFactory", hibernateSessionFactory);
      workflow.setConfiguration(config);
    }
    else
    {
      workflow.getConfiguration().getPersistenceArgs().put("sessionFactory", hibernateSessionFactory);
    }
  }

  /**
   * Constructs a WorkflowFacade with the given user principal
   * @param userPrincipal an InfoGluePrincipal representing a system user
   */

  public WorkflowFacade(InfoGluePrincipal userPrincipal)
  {
    this(OwnerFactory.create(userPrincipal));
  }

  /**
   * Constructs a WorkflowFacade with the given user principal
   * @param userPrincipal an InfoGluePrincipal representing a system user
   */
 
  public WorkflowFacade(InfoGluePrincipal userPrincipal, boolean createSession)
  {
    this(OwnerFactory.create(userPrincipal), createSession);
  }
 
 
  /**
   * Constructs a WorkflowFacade with the given user principal
   * @param userPrincipal an InfoGluePrincipal representing a system user
   */
  public WorkflowFacade(InfoGluePrincipal userPrincipal, SessionFactory sessionFactory, Session session)
  {
    this(OwnerFactory.create(userPrincipal), sessionFactory, session);
  }

  /**
   * Constructs a WorkflowFacade with the given user principal representing an initialized instance of the workflow
   * with the given name.  "Initialized" in this context means that the initial action has been executed and we have
   * the workflow ID.
   * @param userPrincipal an InfoGluePrincipal representing a system user
   * @param name the name of the workflow to create
   * @param initialAction the ID of the initial action to perform to get the workflow started.
   */
  public WorkflowFacade(InfoGluePrincipal userPrincipal, String name, int initialAction) throws SystemException
  {
    this(userPrincipal, name, initialAction, new HashMap());
  }

  /**
   * Constructs a WorkflowFacade with the given user principal representing an initialized instance of the workflow
   * with the given name.  "Initialized" in this context means that the initial action has been executed and we have
   * the workflow ID.
   * @param userPrincipal an InfoGluePrincipal representing a system user
   * @param name the name of the workflow to create
   * @param initialAction the ID of the initial action to perform to get the workflow started.
   * @param inputs a map of inputs to use to initialize the workflow.
   */
  public WorkflowFacade(InfoGluePrincipal userPrincipal, String name, int initialAction, Map inputs) throws SystemException
  {
    this(userPrincipal);
    initialize(name, initialAction, inputs);
  }

  /**
   * Constructs a WorkflowFacade with the given user principal representing an initialized instance of the workflow
   * with the given name.  "Initialized" in this context means that the initial action has been executed and we have
   * the workflow ID.
   * @param userPrincipal an InfoGluePrincipal representing a system user
   * @param name the name of the workflow to create
   * @param initialAction the ID of the initial action to perform to get the workflow started.
   * @param inputs a map of inputs to use to initialize the workflow.
   */
  public WorkflowFacade(InfoGluePrincipal userPrincipal, String name, int initialAction, Map inputs, SessionFactory sessionFactory, Session session) throws SystemException
  {
    this(userPrincipal, sessionFactory, session);
    initialize(name, initialAction, inputs);
  }

  /**
   * Constructs a WorkflowFacade for a user with the given workflow ID.
   * @param userPrincipal an InfoGluePrincipal representing a system user
   * @param workflowId the ID representing an instance of the desired workflow
   */
  public WorkflowFacade(InfoGluePrincipal userPrincipal, long workflowId)
  {
    this(userPrincipal);
    setWorkflowIdAndDescriptor(workflowId);
  }

  /**
   * Constructs a WorkflowFacade for a user with the given workflow ID.
   * @param userPrincipal an InfoGluePrincipal representing a system user
   * @param workflowId the ID representing an instance of the desired workflow
   */
 
  public WorkflowFacade(InfoGluePrincipal userPrincipal, long workflowId, boolean createSession)
  {
    this(userPrincipal, createSession);
    setWorkflowIdAndDescriptor(workflowId);
  }
 

  /**
   * Constructs a WorkflowFacade for a user with the given workflow ID.
   * @param userPrincipal an InfoGluePrincipal representing a system user
   * @param workflowId the ID representing an instance of the desired workflow
   */
  public WorkflowFacade(InfoGluePrincipal userPrincipal, long workflowId, SessionFactory sessionFactory, Session session)
  {
    this(userPrincipal, sessionFactory, session);
    setWorkflowIdAndDescriptor(workflowId);
  }

  /**
   * Sets the workflow ID to the given value, and caches the associated workflow descriptor
   * @param workflowId the desired workflow ID
   */
  private void setWorkflowIdAndDescriptor(long workflowId)
  {
    this.workflowId = workflowId;
    String key = "workflowName_" + workflowId;
    String workflowName = (String)CacheController.getCachedObject("workflowNameCache", key);
    if(workflowName == null)
    {
      workflowName = workflow.getWorkflowName(workflowId);
      CacheController.cacheObject("workflowNameCache", key, workflowName);
    }

    String keyDescriptor = "workflowDescriptor_" + workflowId;
    WorkflowDescriptor workflowDescriptorTemp = (WorkflowDescriptor)CacheController.getCachedObject("workflowNameCache", keyDescriptor);
    if(workflowDescriptorTemp == null)
    {
      workflowDescriptorTemp = workflow.getWorkflowDescriptor(workflowName);
      workflowDescriptor = workflowDescriptorTemp;
      CacheController.cacheObject("workflowNameCache", keyDescriptor, workflowDescriptorTemp);
    }
    else
      workflowDescriptor = workflowDescriptorTemp;
   
    //workflowDescriptor = workflow.getWorkflowDescriptor(workflowName);
  }

  /**
   * Returns the workflow ID
   * @return the workflow ID
   */
  public long getWorkflowId()
  {
    return workflowId;
  }

  /**
   * Initializes the workflow, setting workflowId as a side-effect.
   * @param name the name of the workflow to initialize
   * @param initialAction the ID of the initial action to perform to get the workflow started.
   * @param inputs a map of inputs to use to initialize the workflow.
   * @throws SystemException if a workflow error occurs.
   */
  private void initialize(String name, int initialAction, Map inputs) throws SystemException
  {
    try
    {
      if(useDatabaseExtension(workflow.getWorkflowDescriptor(name)))
      {
        setWorkflowIdAndDescriptor(doExtendedInitialize(name, initialAction, inputs));
      }
      else
      {
        setWorkflowIdAndDescriptor(workflow.initialize(name, initialAction, inputs));
      }
    }
    catch (Exception e)
    {
      logger.error("An error occurred when we tried to get workflow with name:" + name);
      throw new SystemException(e);
    }
  }

  /**
   * Initializes the workflow. 
   * A <code>DatabaseSession</code> object whose lifecycle is handled by this method is inserted into the <code>inputs</code>.
   *
   * @param name the name of the workflow to initialize
   * @param initialAction the ID of the initial action to perform to get the workflow started.
   * @param inputs a map of inputs to use to initialize the workflow.
   * @throws SystemException if a workflow error occurs.
   */

  private long doExtendedInitialize(final String name, final int initialAction, final Map inputs) throws WorkflowException
  {
    long result = 0;
    final DatabaseSession db = new DatabaseSession();
    try
    {
      final Map copy = new HashMap();
      copy.putAll(inputs);
      copy.put(workflow.getWorkflowDescriptor(name).getMetaAttributes().get(WORKFLOW_DATABASE_EXTENSION_META_ATTRIBUTE), db);
      result = workflow.initialize(name, initialAction, copy);
    }
    catch(Exception e)
    {
      e.printStackTrace();
      if(db != null)
      {
        db.setRollbackOnly();
      }
         
      throw (e instanceof WorkflowException) ? (WorkflowException) e : new WorkflowException(e);
    }
    finally
    {
      db.releaseDB();
    }
    return result;
  }

  /**
   * Performs an action using the given inputs
   * @param actionId the ID of the action to perform
   * @param inputs a map of inputs to the action
   * @throws WorkflowException if a workflow error occurs, or if the underlying workflow is not active
   */
  public synchronized void doAction(int actionId, Map inputs) throws WorkflowException
  {
    if(logger.isInfoEnabled())
      logger.info("doAction with " + actionId + " on " + this.workflowId);

    try
    {
      final Long id = new Long(workflowId);

      if(getEntryState() == WorkflowEntry.CREATED)
        workflow.changeEntryState(workflowId, WorkflowEntry.ACTIVATED);

      if(logger.isInfoEnabled())
      {
        logger.info("workflowId:" + workflowId);
        logger.info("actionId:" + actionId);
      }
     
      synchronized(currentWorkflows)
      { 
        if(!isActive())
        {
          if(getEntryState() == WorkflowEntry.UNKNOWN)
            throw new WorkflowException("The workflow with id " + workflowId + " is in an unknown state - the database could be down or the workflow corrupt");
          else
            throw new InvalidActionException("Workflow " + workflowId + " is no longer active");
        }
        if(currentWorkflows.contains(id))
        {
          throw new WorkflowException("The selected workflow is executing...");
        }
        currentWorkflows.add(id);
      }
     
      try
      {
        if(useDatabaseExtension(workflowDescriptor))
        {
          doExtendedAction(actionId, inputs);
        }
        else
        {
          workflow.doAction(workflowId, actionId, inputs);
        }
      }
      finally
      {
        synchronized(currentWorkflows)
        {
          currentWorkflows.remove(id);
        }
      }
    }
    catch(Exception we)
    {
      logger.error("An error occurred when we tried to invoke an workflow action:" + we.getMessage());
      //restoreSessionFactory(workflow, we);
      throw new WorkflowException("An error occurred when we tried to invoke an workflow action:" + we.getMessage());
    }
  }
 

  /**
   * Performs an action using the given inputs.
   * A <code>DatabaseSession</code> object whose lifecycle is handled by this method is inserted into the <code>inputs</code>.
   *
   * @param actionId the ID of the action to perform
   * @param inputs a map of inputs to the action
   * @throws WorkflowException if a workflow error occurs, or if the underlying workflow is not active
   */
  private void doExtendedAction(final int actionId, final Map inputs) throws WorkflowException
  {
    final DatabaseSession db = new DatabaseSession();

    try
    {
      final Map copy = new HashMap();
      copy.putAll(inputs);
      copy.put(workflowDescriptor.getMetaAttributes().get(WORKFLOW_DATABASE_EXTENSION_META_ATTRIBUTE), db);

      workflow.doAction(workflowId, actionId, copy);
    }
    catch(Exception e)
    {
      logger.error("An error occurred in doExtendedAction:" + e.getMessage(), e);
      //e.printStackTrace();
      if(db != null)
      {
        db.setRollbackOnly();
      }

      throw (e instanceof WorkflowException) ? (WorkflowException) e : new WorkflowException(e);
    }
    finally
    {
      db.releaseDB();
    }
  }

  /**
   * Returns the property set associated with the underlying workflow
   * @return the property set associated with the underlying workflow
   */
  public PropertySet getPropertySet()
  {
    //Timer t = new Timer();
      String key = "psCache_" + workflowId;
      PropertySet ps = (PropertySet)CacheController.getCachedObject("propertySetCache", key);
      if(ps == null)
      {
        ps = workflow.getPropertySet(workflowId);
        CacheController.cacheObject("propertySetCache", key, ps);
      }

      //t.printElapsedTime("getPropertySet took");
    return ps;
  }

  /**
   * Returns the state of the underlying workflow entry
   * @return the state of the underlying workflow entry
   */
  private int getEntryState() throws WorkflowException
  {
    try
    {
      return workflow.getEntryState(workflowId);
    }
    catch(Throwable we)
    {
      logger.error("An error occurred when we tried to check for entry state:" + we.getMessage());
      //restoreSessionFactory(workflow, we);
      throw new WorkflowException("An error occurred when we tried to check for entry state:" + we.getMessage());
     }
  }

  /**
   * Indicates whether the underlying workflow is active.
   *
   * @return true if the underlying workflow's state is WorkflowEntry.ACTIVATED, otherwise returns false.
   */
  public boolean isActive() throws WorkflowException
  {
    return getEntryState() == WorkflowEntry.ACTIVATED;
  }

  /**
   * Indicates whether the underlying workflow is finished.
   *
   * @return true if the underlying workflow's state is WorkflowEntry.KILLED or WorkflowEntry.COMPLETED, otherwise returns false.
   */
  public boolean isFinished() throws WorkflowException
  {
    int state = getEntryState();
    return state == WorkflowEntry.KILLED || state == WorkflowEntry.COMPLETED;
  }
 
  /**
   * Returns a list of all declared workflows, i.e., workflows defined in workflows.xml
   * @return a list WorkflowVOs representing all declared workflows
   */
  public List<WorkflowVO> getDeclaredWorkflows()
  {
    String[] workflowNames = workflow.getWorkflowNames();
    List<WorkflowVO> availableWorkflows = new ArrayList<WorkflowVO>();

    for (int i = 0; i < workflowNames.length; i++)
    {
      try
      {
        availableWorkflows.add(createWorkflowVO(workflowNames[i]));
      }
      catch(Exception e)
      {
        logger.error("The workflow " + workflowNames[i] + " could not be instantiated:" + e.getMessage(), e);
      }
    }
   
    return availableWorkflows;
  }

  /**
   * Returns a list of all active workflows.
   *
   * @return a list of WorkflowVOs representing all active workflows
   * @throws SystemException if an error occurs finding the active workflows
   */
  public List<WorkflowVO> getActiveWorkflows(Integer maxNumberOfWorkflows) throws SystemException
  {
    List<WorkflowVO> workflowVOs = new ArrayList<WorkflowVO>();

    List<WorkflowVO> activeWorkflows = findActiveWorkflows();
    //logger.info("activeWorkflows:" + activeWorkflows.size());
    if(maxNumberOfWorkflows != null && activeWorkflows.size() > maxNumberOfWorkflows)
      activeWorkflows = activeWorkflows.subList(0, maxNumberOfWorkflows);
    Iterator activeWorkflowsIterator = activeWorkflows.iterator();
    while (activeWorkflowsIterator.hasNext())
    {
      setWorkflowIdAndDescriptor(((Long)activeWorkflowsIterator.next()).longValue());
      //logger.info("workflowId:" + workflowId);
      workflowVOs.add(createWorkflowVO());
    }

    return workflowVOs;
  }
 
  /**
   * Returns a list of workflows owned by the specified principal. If the principal is
   * an administrator, all active workflows are returned.
   *
   * @param principal the principal.
   * @return the workflows owned by the specified principal.
   */
 
  public List getMyActiveWorkflows(final InfoGluePrincipal principal, Integer maxNumberOfWorkflows) throws SystemException
  {   
    String key = "myWorkflows_" + principal.getName();
    List workflows = (List)CacheController.getCachedObject("myActiveWorkflows", key);
   
    if(workflows == null)
    {
        if(principal.getIsAdministrator())
        {
          workflows = getActiveWorkflows(maxNumberOfWorkflows);
        }
        else
        {
          Collection owners = OwnerFactory.createAll(principal);
          Expression[] expressions = new Expression[owners.size()];
         
          Iterator ownersIterator = owners.iterator();
          int i = 0;
          while(ownersIterator.hasNext())
          {
            Owner owner = (Owner)ownersIterator.next();
            Expression expression = new FieldExpression(FieldExpression.OWNER, FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS, owner.getIdentifier());
            expressions[i] = expression;
            i++;
          }       
         
          final Set workflowVOs = new HashSet();
          workflowVOs.addAll(createWorkflowsForOwner(expressions, maxNumberOfWorkflows));
   
          /*
          final Set workflowVOs = new HashSet();
          for(final Iterator owners = OwnerFactory.createAll(principal).iterator(); owners.hasNext(); )
          {
            final Owner owner = (Owner) owners.next();
            workflowVOs.addAll(createWorkflowsForOwner(owner));
          }
          */
         
          workflows = new ArrayList(workflowVOs);
        }
        CacheController.cacheObject("myActiveWorkflows", key, workflows);
    }
   
    return workflows;
  }
 
  /**
   * Creates value object for all workflows having the specified owner.
   *
   * @param owner the owner.
   * @return the value objects.
   * @throws SystemException if an error occurs when creating the value objects.
   */
  private final Set createWorkflowsForOwner(final Owner owner) throws SystemException
  {
    final Set workflowVOs = new HashSet();
    List workflows = findWorkflows(owner);
    Iterator workflowsIterator = workflows.iterator();
    while (workflowsIterator.hasNext())
    {
      setWorkflowIdAndDescriptor(((Long)workflowsIterator.next()).longValue());
      workflowVOs.add(createWorkflowVO());
    }
    return workflowVOs;
  }

  /**
   * Creates value object for all workflows having the specified owner.
   *
   * @param owner the owner.
   * @return the value objects.
   * @throws SystemException if an error occurs when creating the value objects.
   */
  private final Set createWorkflowsForOwner(final Expression[] expressions, Integer maxNumberOfWorkflows) throws SystemException
  {
    try
    {
      final Set workflowVOs = new HashSet();
      List workflows = findWorkflows(expressions);
      if(maxNumberOfWorkflows != null && workflows.size() > maxNumberOfWorkflows)
        workflows = workflows.subList(0, maxNumberOfWorkflows);
      Iterator workflowsIterator = workflows.iterator();
      while (workflowsIterator.hasNext())
      {
        setWorkflowIdAndDescriptor(((Long)workflowsIterator.next()).longValue());
        workflowVOs.add(createWorkflowVO());
      }

      return workflowVOs;
    }
    catch (WorkflowException e)
    {
      throw new SystemException(e);
    }
  }

  /**
   * Finds all active workflows
   * @return A list of workflowIds representing workflows that match the hard-wored query expression.
   * @throws SystemException if a workflow error occurs during the search
   */
  private List<WorkflowVO> findActiveWorkflows() throws SystemException
  {
    try
    {
      List<WorkflowVO> workflows = workflow.query(new WorkflowExpressionQuery(new FieldExpression(FieldExpression.STATE, FieldExpression.ENTRY, FieldExpression.EQUALS, new Integer(WorkflowEntry.ACTIVATED))));
      return workflows;
      //return workflow.query(new WorkflowExpressionQuery(new FieldExpression(FieldExpression.STATE, FieldExpression.ENTRY, FieldExpression.EQUALS, new Integer(WorkflowEntry.ACTIVATED))));
    }
    catch (WorkflowException e)
    {
      throw new SystemException(e);
    }
  }

  /**
   * Finds all workflows for the specified owner.
   *
   * @param owner the owner.
   * @return The active workflows owned by the specified owner.
   * @throws SystemException
   */
  private List findWorkflows(final Owner owner) throws SystemException
  {
    try
    {
      List workflows = workflow.query(new WorkflowExpressionQuery(new FieldExpression(FieldExpression.OWNER,
          FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS, owner.getIdentifier())));

      return workflows;
    }
    catch (WorkflowException e)
    {
      throw new SystemException(e);
    }
  }

  /**
   * Finds all workflows for the specified owner.
   *
   * @param owner the owner.
   * @return The active workflows owned by the specified owner.
   * @throws SystemException
   */
  private List findWorkflows(final Expression[] expressions) throws WorkflowException
  {
    try
    {
      List workflows = workflow.query(new WorkflowExpressionQuery(new NestedExpression(expressions, NestedExpression.OR)));

      //List workflows = workflow.query(new WorkflowExpressionQuery(new FieldExpression(FieldExpression.OWNER, FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS, owner.getIdentifier())));
      return workflows;
    }
    catch (WorkflowException we)
    {
      logger.error("An error occurred when we tried to invoke an workflow action:" + we.getMessage());
      //restoreSessionFactory(workflow, we);
      throw new WorkflowException("An error occurred when we tried to invoke an workflow action:" + we.getMessage());
    }
  }

  /**
   * Returns all current steps for the workflow, i.e., steps that could be performed in the workflow's current state
   * Steps are filtered according to ownership; if a step has an owner, it is only included if the ownser matches
   * the caller or if the current user is an administrator.
   * @return a list of WorkflowStepVOs representing the current steps of the workflow with workflowId
   */
  public List getCurrentSteps()
  {
    return getCurrentSteps(null);
  }
 
  public List getCurrentSteps(final WorkflowVO workflowVO)
  {
    return createStepVOs(workflowVO, workflow.getCurrentSteps(workflowId));
  }

  /**
   * Returns all history steps for the workflow, i.e., all the steps that have already been performed.
   * @return a list of WorkflowStepVOs representing all history steps for the workflow with workflowId
   */
  public List getHistorySteps()
  {
    return getHistorySteps(null);
  }
 
  public List getHistorySteps(final WorkflowVO workflowVO)
  {
    return createStepVOs(workflowVO, workflow.getHistorySteps(workflowId));
  }

  /**
   * Returns all steps for a workflow definition.  These are the steps declared in the workfow descriptor; there is
   * no knowledge of current or history steps at this point.
   * @return a list of WorkflowStepVOs representing all steps in the workflow.
   */
  public List getDeclaredSteps()
  {
    return getDeclaredSteps(workflowDescriptor);
  }

  /**
   * Creates a list of WorkflowStepVOs from the given list of steps
   * @param steps a list of Steps
   * @return a list of WorkflowStepVOs corresponding to all steps that pass the filter
   */
  private List createStepVOs(final WorkflowVO workflowVO, final List steps)
  {
    List stepVOs = new ArrayList();
    for (Iterator i = steps.iterator(); i.hasNext();)
    {
      Step step = null;
      step = (Step)i.next();
      try
      {
        stepVOs.add(createStepVO(workflowVO, step));
      }
      catch(Exception e)
      {
        logger.warn("There was an invalid step:" + workflowVO, e);
      }
    }
   
    return stepVOs;
  }

  /**
   * Returns all steps for a workflow definition.  These are the steps declared in the workfow descriptor; there is
   * no knowledge of current or history steps at this point.
   * @param descriptor a workflow descriptor from which to get current steps
   * @return a list of WorkflowStepVOs representing all steps in the workflow.
   */
  private List getDeclaredSteps(WorkflowDescriptor descriptor)
  {
    List steps = new ArrayList();
    for (Iterator i = descriptor.getSteps().iterator(); i.hasNext();)
      steps.add(createStepVO((StepDescriptor)i.next()));

    return steps;
  }

  /**
   * Returns a list of initial actions for the workflow
   * @return a list of WorkflowActionVOs representing the global actions for the workflow with workflowId
   */
  private List getInitialActions()
  {
    if(workflowDescriptor != null)
      return createActionVOs(workflowDescriptor.getInitialActions());
    else
      return null;
  }

  /**
   * Returns a list of global actions for the workflow
   * @return a list of WorkflowActionVOs representing the global actions for the workflow with workflowId
   */
  private List getGlobalActions()
  {
    if(workflowDescriptor != null)
      return createActionVOs(workflowDescriptor.getGlobalActions());
    else
      return null;
  }

  /**
   * Creates a list of WorkflowActionVOs from a list of action descriptors
   * @param actionDescriptors a list of ActionDescriptors
   * @return a list of WorkflowActionVOs representing actionDescriptors
   */
  private List createActionVOs(List actionDescriptors)
  {
    List actions = new ArrayList();
    for (Iterator i = actionDescriptors.iterator(); i.hasNext();)
      actions.add(createActionVO((ActionDescriptor)i.next()));

    return actions;

  }

  /**
   * Creates a new WorkflowVO.  This represents a pretty complete workflow; you get all the current steps, history
   * steps, available actions, and global actions.
   * @return a WorkflowVO representing workflow, with workflowId
   */
  public WorkflowVO createWorkflowVO()
  {
    WorkflowVO workflowVO = new WorkflowVO(new Long(workflowId), workflow.getWorkflowName(workflowId));
    if(workflowDescriptor != null)
    {
      if(useTitleExtension(workflowDescriptor))
        workflowVO.setTitle(getWorkflowTitle());
    }
   
    workflowVO.setCurrentSteps(getCurrentSteps(workflowVO));
    workflowVO.setHistorySteps(getHistorySteps(workflowVO));
    workflowVO.setInitialActions(getInitialActions());
    workflowVO.setGlobalActions(getGlobalActions());

    return workflowVO;
  }

  /**
   * Returns the title of the workflow instance.
   *
   * @return the title of the workflow instance.
   */
  private String getWorkflowTitle()
  {
    if(!workflowDescriptor.getMetaAttributes().containsKey(WORKFLOW_TITLE_EXTENSION_META_ATTRIBUTE))
    {
      return null;
    }
   
    final String key = (String) workflowDescriptor.getMetaAttributes().get(WORKFLOW_TITLE_EXTENSION_META_ATTRIBUTE);
    final PropertySet ps = getPropertySet();
    return ps.exists(key) ? ps.getString(key) : null;
  }
 
  /**
   * Creates a new WorkflowVO from workflow with the given name.  The resulting workflow VO contains only a
   * minimal amount of data because we don't have the workflow ID.  Basically all you get is all the steps.
   * @param name the name of the desired workflow
   * @return a new WorkflowVO representing workflow
   */
  private WorkflowVO createWorkflowVO(String name)
  {
    WorkflowVO workflowVO = new WorkflowVO(null, name);
    try
    {
      workflowVO.setDeclaredSteps(getDeclaredSteps(workflow.getWorkflowDescriptor(name)));
    }
    catch(Exception e)
    {
      workflowVO.setStatus(WorkflowVO.STATUS_NOT_OK);
      workflowVO.setStatusMessage("Error in workflow:" + e.getMessage());
     
      logger.error("Could not read workflow:" + e.getMessage(), e);
    }
   
    return workflowVO;
  }

  /**
   * Creates a WorkflowStepVO from the given step
   * @param step the desired step
   * @return a new WorkflowStepVO representing step.
   */
  private WorkflowStepVO createStepVO(final WorkflowVO workflowVO, final Step step) throws Exception
  {
    logger.info("step:" + step + ':' + step.getId());
    logger.info("Owner:" + step.getOwner());

    WorkflowStepVO stepVO = new WorkflowStepVO(workflowVO);
    stepVO.setId(new Integer((int)step.getId()));// Hope it doesn't get too big; we are stuck with int thanks to BaseEntityVO
    stepVO.setStepId(new Integer(step.getStepId()));
    stepVO.setWorkflowId(new Long(workflowId));
    stepVO.setStatus(step.getStatus());
    stepVO.setStartDate(step.getStartDate());
    stepVO.setFinishDate(step.getFinishDate());
    stepVO.setOwner(step.getOwner());
    stepVO.setCaller(step.getCaller());
   
    try
    {
      StepDescriptor stepDescriptor = workflowDescriptor.getStep(step.getStepId());
      if(stepDescriptor != null)
      {
        stepVO.setName(stepDescriptor.getName());
        for (Iterator i = stepDescriptor.getActions().iterator(); i.hasNext();)
          stepVO.addAction(createActionVO((ActionDescriptor)i.next()));
      }
      else
      {
        throw new SystemException("No stepDescriptor found for " + step);
      }
    }
    catch(Exception e)
    {
     
    }
   
    return stepVO;
  }

  /**
   * Creates a WorkflowStepVO from a step descriptor.  Some of the step data, e.g., status, startDate,
   * finishDate, etc. cannot be populated here because the step descriptor does not know about these things.
   * @param stepDescriptor a step descriptor
   * @return a WorkflowStepVO representing stepDescriptor
   */
  private WorkflowStepVO createStepVO(StepDescriptor stepDescriptor)
  {
    WorkflowStepVO step = new WorkflowStepVO();
    step.setStepId(new Integer(stepDescriptor.getId()));
    step.setName(stepDescriptor.getName());
    step.setStatus("Not started");

    for (Iterator i = stepDescriptor.getActions().iterator(); i.hasNext();)
      step.addAction(createActionVO((ActionDescriptor)i.next()));

    return step;
  }

  /**
   * Creates a WorkflowActionVO for the given action descriptor
   * @param actionDescriptor an action descriptor
   * @return a WorkflowActionVO representing actionDescriptor
   */
  private WorkflowActionVO createActionVO(ActionDescriptor actionDescriptor)
  {
    logger.info("Action:" + actionDescriptor.getId() + ':' + actionDescriptor.getName()
          + ':' + actionDescriptor.getParent().getClass());

    WorkflowActionVO actionVO = new WorkflowActionVO(new Integer(actionDescriptor.getId()));
    actionVO.setWorkflowId(new Long(workflowId));
    actionVO.setName(actionDescriptor.getName());
    actionVO.setView(actionDescriptor.getView());
    actionVO.setAutoExecute(actionDescriptor.getAutoExecute());
    actionVO.setMetaAttributes(actionDescriptor.getMetaAttributes());
    return actionVO;
  }
 
  /**
   * Checks if the title extension should be used.
   *
   * @return true if the extension should be used, false otherwise.
   */
  private boolean useTitleExtension(final WorkflowDescriptor descriptor)
  {
    return descriptor.getMetaAttributes().containsKey(WORKFLOW_TITLE_EXTENSION_META_ATTRIBUTE);
  }

  /**
   * Checks if the database extension should be used.
   *
   * @return true if the extension should be used, false otherwise.
   */
  private boolean useDatabaseExtension(final WorkflowDescriptor descriptor)
  {
    return descriptor.getMetaAttributes().containsKey(WORKFLOW_DATABASE_EXTENSION_META_ATTRIBUTE);
 
}
TOP

Related Classes of org.infoglue.cms.util.workflow.WorkflowFacade

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.