Package de.danet.an.workflow.ejbs.core

Source Code of de.danet.an.workflow.ejbs.core.WfActivityEJB

/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 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
*
* $Id: WfActivityEJB.java 3205 2009-09-27 17:13:47Z mlipp $
*
* $Log$
* Revision 1.23  2007/09/21 06:19:35  mlipp
* Fixed problem with NamingException during process deletion.
*
* Revision 1.22  2007/07/08 20:35:01  mlipp
* Even more usage of local EJB interfaces.
*
* Revision 1.21  2007/06/10 05:55:30  drmlipp
* Using local interface for optimization.
*
* Revision 1.20  2007/05/03 21:58:16  mlipp
* Internal refactoring for making better use of local EJBs.
*
*/
package de.danet.an.workflow.ejbs.core;

import java.io.IOException;
import java.io.Serializable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.FinderException;
import javax.ejb.NoSuchEntityException;
import javax.ejb.NoSuchObjectLocalException;
import javax.ejb.ObjectNotFoundException;
import javax.ejb.RemoveException;
import javax.ejb.TimedObject;
import javax.ejb.Timer;
import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
import javax.naming.NamingException;
import javax.sql.DataSource;

import de.danet.an.util.EJBUtil;
import de.danet.an.util.JDBCUtil;
import de.danet.an.util.ResourceNotAvailableException;
import de.danet.an.util.UniversalPrepStmt;

import de.danet.an.workflow.internalapi.ExtActivityLocal;
import de.danet.an.workflow.internalapi.ExtExecutionObjectLocal;
import de.danet.an.workflow.internalapi.ExtProcessLocal;
import de.danet.an.workflow.internalapi.ThreadInfo;
import de.danet.an.workflow.localapi.ProcessLocal;
import de.danet.an.workflow.localapi.TransitionLocal;
import de.danet.an.workflow.localcoreapi.WfActivityLocal;
import de.danet.an.workflow.localcoreapi.WfProcessLocal;
import de.danet.an.workflow.omgcore.HistoryNotAvailableException;
import de.danet.an.workflow.omgcore.InvalidPriorityException;
import de.danet.an.workflow.omgcore.InvalidStateException;
import de.danet.an.workflow.omgcore.WfAssignment;
import de.danet.an.workflow.omgcore.WfAuditEvent;
import de.danet.an.workflow.omgcore.WfProcess;
import de.danet.an.workflow.omgcore.WfExecutionObject.NotRunningState;
import de.danet.an.workflow.omgcore.WfExecutionObject.State;

import de.danet.an.workflow.api.Activity;
import de.danet.an.workflow.api.InvalidKeyException;
import de.danet.an.workflow.api.Activity.Implementation;
import de.danet.an.workflow.api.Activity.JoinAndSplitMode;
import de.danet.an.workflow.api.Activity.StartFinishMode;
import de.danet.an.workflow.apix.ExtActivity;

import de.danet.an.workflow.domain.AbstractActivity;
import de.danet.an.workflow.domain.DefaultAuditEvent;
import de.danet.an.workflow.domain.RASInvocationHandler;
import de.danet.an.workflow.domain.ToolInvocationHandler;

import de.danet.an.workflow.ejbs.WorkflowEngine;
import de.danet.an.workflow.ejbs.WorkflowEngineHome;
import de.danet.an.workflow.ejbs.admin.WorkflowEngineLocal;
import de.danet.an.workflow.ejbs.admin.WorkflowEngineLocalHome;
import de.danet.an.workflow.ejbs.client.InvocationHelperLocal;
import de.danet.an.workflow.ejbs.client.InvocationHelperLocalHome;
import de.danet.an.workflow.ejbs.util.QueuerUtils;
import de.danet.an.workflow.spis.aii.ApplicationNotStoppedException;
import de.danet.an.workflow.spis.ras.ActivityFinder;
import de.danet.an.workflow.spis.ras.ResourceAssignmentService;

/**
* The entity bean <code>WfActivityEJB</code> represent a activity.
* <code>AbstractActivity</code> represents a simple implementation
* of the interface {@link ActivityLocal <code>Activity</code>}.
* It has the following additional features:
* <ul>
* <li>Support for transition restrictions of type SPLIT or JOIN.</li>
* </ul>
*
* @ejb.bean name="ActivityBean" display-name="ActivityBean"
* jndi-name="ejb/@@@_JNDI_Name_Prefix_@@@ActivityBean"
* type="BMP" reentrant="true" view-type="both"
* @jonas.bean ejb-name="ActivityBean"
* @ejb.pk class="java.lang.Long" generate="false"
* @ejb.home remote-class="de.danet.an.workflow.ejbs.core.WfActivityHome"
* local-class="de.danet.an.workflow.ejbs.core.WfActivityLocalHome"
* @ejb.interface
* extends="javax.ejb.EJBObject, de.danet.an.workflow.apix.ExtActivity"
* remote-class="de.danet.an.workflow.ejbs.core.WfActivity"
* local-extends="javax.ejb.EJBLocalObject,
* de.danet.an.workflow.internalapi.ExtActivityLocal"
* local-class="de.danet.an.workflow.ejbs.core.WfActivityLocal"
* @ejb.transaction type="Required"
* @ejb.security-identity run-as="WfMOpenAdmin"
* sunone-principal="WfMCorePrincipalForAdmin"
* @weblogic.run-as-identity-principal WfMCorePrincipalForAdmin
* @ejb.ejb-ref ejb-name="WorkflowEngine" view-type="remote"
* @ejb.ejb-ref ejb-name="WorkflowEngine" view-type="local"
* @ejb.ejb-ref ejb-name="ProcessBean" view-type="remote"
* @ejb.ejb-ref ejb-name="ProcessBean" view-type="local"
* @ejb.ejb-ref ejb-name="ConfigurationBean" view-type="remote"
* ref-name="ejb/Configuration"
* @ejb.ejb-external-ref ref-name="ejb/InvocationHelperLocal"
* link="InvocationHelper" type="Session" view-type="local"
* home="de.danet.an.workflow.ejbs.client.InvocationHelperLocalHome"
* business="de.danet.an.workflow.ejbs.client.InvocationHelperLocal"
* @ejb.ejb-external-ref ref-name="ejb/JdbcKeyGenLocal" link="KeyGen"
* type="Session" view-type="local" home="de.danet.an.util.KeyGenLocalHome"
* business="de.danet.an.util.KeyGenLocal"
* @ejb.resource-ref res-ref-name="jdbc/WfEngine"
* res-type="javax.sql.DataSource" res-auth="Container"
* @jonas.resource res-ref-name="jdbc/WfEngine" jndi-name="jdbc_1"
* @weblogic.enable-call-by-reference True
* @weblogic.resource-description
* res-ref-name="jdbc/WfEngine" jndi-name="DefaultDS"
* @ejb.permission role-name="WfMOpenAdmin"
* @weblogic.transaction-isolation TRANSACTION_READ_COMMITTED
* @weblogic.cache concurrency-strategy="Exclusive"
* @ejb.resource-ref res-ref-name="jms/QCF"
* res-type="javax.jms.QueueConnectionFactory" res-auth="Container"
* @jboss.resource-ref res-ref-name="jms/QCF" jndi-name="java:/JmsXA"
* @jonas.resource res-ref-name="jms/QCF" jndi-name="QCF"
* @weblogic.resource-description res-ref-name="jms/QCF"
* jndi-name="weblogic.jms.XAConnectionFactory"
* @ejb.resource-ref res-ref-name="jms/InternalEventQueue"
* res-type="javax.jms.Queue" res-auth="Container"
* @jboss.resource-ref res-ref-name="jms/InternalEventQueue"
* jndi-name="queue/@@@_JNDI_Name_Prefix_@@@InternalEventQueue"
* @jonas.resource res-ref-name="jms/InternalEventQueue"
* jndi-name="queue/@@@_JNDI_Name_Prefix_@@@InternalEventQueue"
* @weblogic.resource-description res-ref-name="jms/InternalEventQueue"
* jndi-name="queue/@@@_JNDI_Name_Prefix_@@@InternalEventQueue"
* @ejb.resource-ref res-ref-name="jms/ApplicationInvocations"
* res-type="javax.jms.Queue" res-auth="Container"
* @jboss.resource-ref res-ref-name="jms/ApplicationInvocations"
* jndi-name="queue/@@@_JNDI_Name_Prefix_@@@ApplicationInvocations"
* @jonas.resource res-ref-name="jms/ApplicationInvocations"
* jndi-name="queue/@@@_JNDI_Name_Prefix_@@@ApplicationInvocations"
* @weblogic.resource-description res-ref-name="jms/ApplicationInvocations"
* jndi-name="queue/@@@_JNDI_Name_Prefix_@@@ApplicationInvocations"
*/
public class WfActivityEJB extends AbstractActivity
    implements EntityBean, TimedObject {

    private static final org.apache.commons.logging.Log logger
  = org.apache.commons.logging.LogFactory.getLog(WfActivityEJB.class);

    private EntityContext ctx;

    /** The primary key of the process. */
    private Long processPk = null;

    /** The name of the process. */
    private String processName = null;

    /** The manager of the process. */
    private String processMgr = null;

    /** The version of the process (manager). */
    private String processMgrVers = null;

    /**
     * The data source of the database.
     * @see javax.sql.DataSource
     */
    private DataSource ds = null;

    /** Indicates if the database supports select for update. */
    private Boolean haveSelForUp = null;

    /** Database name. */
    private static final String DB_NAME = "java:comp/env/jdbc/WfEngine";

    /** The cached home interface of WfProcess. */
    private WfProcessHome processHomeCache = null;
    private WfProcessLocalHome processLocalHomeCache = null;

    /** Cache for QueueConnectionFactory. */
    private QueueConnectionFactory qcfCache = null;
   
    /** Cache for event queue. */
    private Queue eventQueueCache = null;
       
    /** Cache for application invocation queue. */
    private Queue aiQueueCache = null;
       
    /** The owning process of this activity. */
    private WfProcess containerCache = null;
    private WfProcessLocal containerLocalCache = null;

    /**
     * The list of activities that may follow this activity,
     * i.e. to which transitions exist.
     */
    private List nextActivitiesCache = null;

    /**
     * The activity finder used in {@link #activityFinderAndKey
     * <code>activityFinderAndKey</code>}.
     */
    private ActivityFinder activityFinderCache = null;

    /** The resource assignment service. */
    private RASInvocationHandler rasCache = null;

    /** The workflow engine. */
    private WorkflowEngine engineCache = null;
    private WorkflowEngineLocal engineLocalCache = null;
   
    private ToolInvocationHandler toolInvocationHandlerCache = null;
    private InvocationHelperLocal invocationHelperCache = null;

    /** This, as delivered to a client. */
    private Activity thisRemoteCache = null;

    //
    // Provide the persistent attributes
    //

    /** Indicates change of a persistent attribute. */
    private boolean persistentAttributeModified = false;

    /** Indicates change of a slowly changing persistent attribute. */
    private boolean slowlyChangingPaModified = false;

    /** Indicates change of thread info persistent attribute. */
    private boolean threadInfoModified = false;

    /** Indicates change of exec info attributes. */
    private boolean execTimesModified = false;

    /** Indicates change of deadline attribute. */
    private boolean deadlinesModified = false;

    /** Indicates change of waiting on attribute. */
    private boolean waitingOnModified = false;

    /** Persistent attribute <code>name</code>. */
    private String paName;

    /** Persistent attribute <code>description</code>. */
    private String paDescription;

    /** Persistent attribute <code>priority</code>. */
    private Priority paPriority;

    /** Persistent attribute <code>typedState</code>. */
    private State paTypedState;

    /** Persistent attribute <code>lastStateTime</code>. */
    private Date paLastStateTime;

    /** Persistent attribute <code>startMode</code>. */
    private StartFinishMode paStartMode;

    /** Persistent attribute <code>finishMode</code>. */
    private StartFinishMode paFinishMode;

    /** Persistent attribute <code>joinMode</code>. */
    private JoinAndSplitMode paJoinMode;

    /** Persistent attribute <code>splitMode</code>. */
    private JoinAndSplitMode paSplitMode;

    /** Persistent attribute <code>performer</code>. */
    private String paPerformer;

    /** Persistent attribute <code>executor</code>. */
    private Integer paExecStat;

    /** Persistent attribute <code>actImpl</code>. */
    private Implementation[] paActImpl;

    /** Persistent attribute <code>threadInfo</code>. */
    private ThreadInfo paThreadInfo;

    /** Persistent attribute <code>Subflow</code>. */
    private String paSubflow;

    /** Persistent attribute <code>deadlines</code>. */
    private List paDeadlines = null;

    /** Persistent attribute <code>startTime</code>. */
    private Date paStartTime;

    /** Persistent attribute <code>suspendStart</code>. */
    private Date paSuspendStart;

    /** Persistent attribute <code>suspendAccum</code>. */
    private long paSuspendAccum;

    /** Persistent attribute <code>pendingException</code>. */
    private String paPendingException;

    /** Persistent attribute <code>waitOnProc</code>. */
    private Long paWaitOnProc;

    /** Persistent attribute <code>waitOnChan</code>. */
    private String paWaitOnChan;

    /**
     * Persistent attribute <code>flags</code>. This attribute is not
     * exposed, it serves as space efficient storage for various
     * attributes that are exposed.
     */
    private int paFlags;

    private static final int FLAGS_DEBUG = 1;
    private static final int FLAGS_AUDIT_SELECTION_SHIFT = 1;
    private static final int FLAGS_AUDIT_SELECTION_MASK = 7 << 1;
    private static final int FLAGS_STORE_AUDIT_EVENTS = 16;

    private static final int FLAGS_SUB_STATE_SHIFT = 28;
    private static final int FLAGS_SUB_STATE_MASK
  = 0x7 << FLAGS_SUB_STATE_SHIFT;
    private static final int FLAGS_DEFERRED_CHOICE = 1 << 27;
    private static final int FLAGS_PRELIMINARILY_CHOSEN = 1 << 26;
    private static final int FLAGS_NO_ASSIGNMENTS = 1 << 25;
    private static final int FLAGS_PENDING_EXCEPTION_IS_FROM_BLOCK = 1 <<24;

    //
    // Accessor methods for cached attributes
    //

    private QueueConnectionFactory queueConnectionFactory ()
        throws ResourceNotAvailableException {
        if (qcfCache == null) {
            qcfCache = ((QueueConnectionFactory)EJBUtil
                        .retrieveJNDIEntry ("java:comp/env/jms/QCF"));
        }
        return qcfCache;
    }

    private Queue eventQueue ()
        throws ResourceNotAvailableException {
        if (eventQueueCache == null) {
            eventQueueCache = (Queue)EJBUtil.retrieveJNDIEntry
                ("java:comp/env/jms/InternalEventQueue");
        }
        return eventQueueCache;
    }
   
    private Queue applicationInvocationQueue ()
        throws ResourceNotAvailableException {
        if (aiQueueCache == null) {
            aiQueueCache = (Queue)EJBUtil.retrieveJNDIEntry
                ("java:comp/env/jms/ApplicationInvocations");
        }
        return aiQueueCache;
    }

    /**
     * The home interface of the WfProcessBean.
     * @return home interface of the WfProcessBean.
     */
    private WfProcessHome processHome()
  throws ResourceNotAvailableException {
  if (processHomeCache == null) {
      processHomeCache = (WfProcessHome)EJBUtil.retrieveEJBHome
    (WfProcessHome.class, "java:comp/env/ejb/ProcessBean");
  }
  return processHomeCache;
    }

    /**
     * The local home interface of the WfProcessBean.
     * @return local home interface of the WfProcessBean.
     */
    private WfProcessLocalHome processLocalHome()
        throws ResourceNotAvailableException {
        if (processLocalHomeCache == null) {
            processLocalHomeCache = (WfProcessLocalHome)
                EJBUtil.retrieveEJBLocalHome
                (WfProcessLocalHome.class,
                 "java:comp/env/ejb/ProcessBeanLocal");
        }
        return processLocalHomeCache;
    }

    /**
     * The workflow engine.
     * @return the workflow engine
     */
    private WorkflowEngine engine()
  throws ResourceNotAvailableException {
  if (engineCache == null) {
      engineCache = (WorkflowEngine)EJBUtil.createSession
    (WorkflowEngineHome.class, "java:comp/env/ejb/WorkflowEngine");
  }
  return engineCache;
    }

    /**
     * The workflow engine.
     * @return the workflow engine
     */
    private WorkflowEngineLocal engineLocal()
        throws ResourceNotAvailableException {
        if (engineLocalCache == null) {
            engineLocalCache = (WorkflowEngineLocal)EJBUtil.createSession
                (WorkflowEngineLocalHome.class,
                 "java:comp/env/ejb/WorkflowEngineLocal");
        }
        return engineLocalCache;
    }

    /**
     * The invocation helper must be created lazily as we need permissions that
     * we have in onMessage only.
     */
    private InvocationHelperLocal invocationHelper() {
        if (invocationHelperCache == null) {
            try {
                invocationHelperCache = (InvocationHelperLocal)
                    EJBUtil.createSession
                        (InvocationHelperLocalHome.class,
                         "java:comp/env/ejb/InvocationHelperLocal");
            } catch (RemoteException e) {
                throw new EJBException (e);
            }
        }
        return invocationHelperCache;
    }
   
   
    /**
     * Get the resource assignment invocation handler.
     * @return the configured resource assignment invocation handler.
     */
    protected RASInvocationHandler rasInvocationHandler() {
  if (rasCache == null) {
      WorkflowEngine engine = null;
      try {
    ResourceAssignmentService ras
                    = engineLocal().resourceAssignmentService ();
                if (ras == null) {
                    return null;
                }
                rasCache = new DefaultRASInvocationHandler (ras);
      } catch (RemoteException rex) {
    throw new EJBException (rex);
      }
  }
  return rasCache;
    }

    //
    // EJB container contract
    //

    /**
     * Set the associated session context. The container calls this method
     * after the instance creation.
     * @see javax.ejb.EntityBean
     * @param context - A SessionContext interface for the instance
     */
    public void setEntityContext(EntityContext context) {
  try {
      ctx = context;
      // getting new data source
      ds = JDBCUtil.refreshDS(null, DB_NAME);
  } catch (NamingException ex) {
      throw new EJBException(ex);
  }     
    }

    /**
     * Unset the associated session context.
     * @see javax.ejb.EntityBean
     */
    public void unsetEntityContext() {
        qcfCache = null;
  processHomeCache = null;
  engineCache = null;
        engineLocalCache = null;
  activityFinderCache = null;
  rasCache = null;
  ds = null;
        ctx = null;
    }

    /**
     * The activate method is called when the instance is activated from its
     * "passive" state. The instance should acquire any resource that it has
     * released earlier in the ejbPassivate() method.
     * This method gets the primary key from container.
     * @see javax.ejb.EntityBean
     */
    public void ejbActivate() {
  containerCache = null;
        containerLocalCache = null;
  nextActivitiesCache = null;
  thisRemoteCache = null;
    }

    /**
     * The passivate method is called before the instance enters the
     * "passive" state. The instance should release any resources that it
     * can re-acquire later in the ejbActivate() method.
     * @see javax.ejb.EntityBean
     */
    public void ejbPassivate() {
  containerCache = null;
        containerLocalCache = null;
  nextActivitiesCache = null;
  thisRemoteCache = null;
  paDeadlines = null;
  dispose();
    }

    /**
     * This method checks if the activity exists.
     * If it is ok, it returns the activity-primary-key.
     * EJBException is thrown on any error except finder exception.
     * @param primaryKey The activity primary key.
     * @return The activity-key
     * @throws FinderException (<code>ObjectNotFoundException</code>)
     * if no activity found.
     */
    public Long ejbFindByPrimaryKey(Long primaryKey)
  throws FinderException {
  boolean result = false;
  try {
      result = selectByPrimaryKey(primaryKey);
  } catch (SQLException ex) {
      throw new EJBException(ex);
  }
  if (!result) {
      throw new ObjectNotFoundException
    ("Row for id " + primaryKey + " not found.");
  }
  return primaryKey;
    }

    /**
     * This method retrieve the activities of a process.
     * @param primaryKey The process primary key.
     * @return Collection with whe activity-keys
     * @throws FinderException will not be thrown.
     * If no activities found, return a empty collection.
     */
    public Collection ejbFindByProcess(Long primaryKey)
  throws FinderException {
  Collection col = null;
  try {
      col = selectByProcess(primaryKey);
  } catch (SQLException ex) {
      throw new EJBException(ex);
  }
  return col;
    }

    /**
     * This method looks up an activity by its
     * {@link de.danet.an.workflow.localcoreapi.WfActivityLocal#key key}.
     * @param key the activity key
     * @return the activity EJB's primary key
     * @throws FinderException if no activity found
     */
    public Long ejbFindByActivityKey(String key)
  throws FinderException {

  Long pk = null;
  try {
      pk = Long.valueOf (key);
  } catch (NumberFormatException nex) {
      throw new ObjectNotFoundException
    ("Invalid key format for key = " + key);
  }
  return ejbFindByPrimaryKey (pk);
    }

    /**
     * This method looks up an activity by its
     * its container and waiting on attribute.
     * @param processId the containing process' id
     * @param channel the channel the activity is waiting on
     * @return the activity EJB's primary key
     * @throws FinderException if no activity found.
     */
    public Long ejbFindByWaitingOn(Long processId, String channel)
  throws FinderException {
  try {
      Long res = selectByWaitingOn(processId, channel);
      if (res == null) {
    throw new ObjectNotFoundException
        ("No activity of process " + processId
         + " waiting on " + channel);
      }
      return res;
  } catch (SQLException ex) {
      throw new EJBException(ex);
  }
    }

    /**
     * Create a new activity and save it into database.
     * @param process the containing process
     * @param procPk pk of process.
     * @param evtBase the base data for an audit event.
     * @param blockActId if the activity is part of a block activity,
     * else <code>null</code>
     * @param priority a <code>Priority</code> value
     * @param name the activity's name
     * @param description activity description
     * @param startMode the start mode
     * @param finishMode the finish mode
     * @param joinMode the join mode
     * @param splitMode the split mode
     * @param implementation the implementation description
     * @param performer the performer
     * @param deadlines the deadlines
     * @param deferChoiceOnSplit if the eventual choice of the
     * subsequent activity is to be deferred
     * @param auditEventSelection the audit event selection
     * @param storeAuditEvents if true, audit events are stored in the
     * database
     * @return primary key of the activity.
     * @throws CreateException if the activity can not be create.
     * @ejb.create-method view-type="local"
     */
    public Long ejbCreate
  (WfProcessLocal process, Long procPk, WfAuditEvent evtBase,
         Long blockActId, ExtExecutionObjectLocal.Priority priority,
   String name, String description,
   StartFinishMode startMode, StartFinishMode finishMode,
   JoinAndSplitMode joinMode, JoinAndSplitMode splitMode,
   Implementation[] implementation, String performer,
   List deadlines, boolean deferChoiceOnSplit,
   int auditEventSelection, boolean storeAuditEvents)
  throws CreateException {
  Long activityPk = null;
  try {
      containerLocalCache = process;
      nextActivitiesCache = null;
      thisRemoteCache = null;
      // create new activityPk
      activityPk = new Long(EJBUtil.newPrimaryKey("activity"));
      // Process id etc.
      processPk = procPk;
      processMgr = evtBase.processMgrName();
      processName = evtBase.processName();
      processMgrVers = evtBase.processMgrVersion();
      // assign default to deadlines to avoid loading on access
      paDeadlines = new ArrayList ();
      // initialize underlying domain object
      init(blockActId, priority, name, description, startMode, finishMode,
     joinMode, splitMode, implementation, performer, deadlines,
     deferChoiceOnSplit, auditEventSelection, storeAuditEvents);
  } catch (RemoteException ex) {
      throw new EJBException(ex);
  }
  return activityPk;
    }

    /**
     * Create a new activity with activity modes, join modes
     * and save it into database.
     * @param process the containing process
     * @param procPk pk of process
     * @param evtBase the base data for an audit event.
     * @param blockActId if the activity is part of a block activity,
     * else <code>null</code>
     * @param priority a <code>Priority</code> value
     * @param name the activity's name
     * @param description activity description
     * @param startMode the start mode
     * @param finishMode the finish mode
     * @param joinMode the join mode
     * @param splitMode the split mode
     * @param implementation the implementation description
     * @param performer the performer
     * @param deadlines the deadlines
     * @param deferChoiceOnSplit if the eventual choice of the
     * subsequent activity is to be deferred
     * @param auditEventSelection the audit event selection
     * @param storeAuditEvents if true, audit events are stored in the
     * database
     * @throws CreateException if the activity can not be create.
     */
    public void ejbPostCreate
  (WfProcessLocal process, Long procPk, WfAuditEvent evtBase,
         Long blockActId, ExtExecutionObjectLocal.Priority priority,
   String name, String description,
   StartFinishMode startMode, StartFinishMode finishMode,
   JoinAndSplitMode joinMode, JoinAndSplitMode splitMode,
   Implementation[] implementation, String performer,
   List deadlines, boolean deferChoiceOnSplit,
   int auditEventSelection, boolean storeAuditEvents)
  throws CreateException {
  try {
      // notify underlying domain object now (may throw exceptions)
      refresh ();
      // save the new activity into database
      insertActivity();
      persistentAttributeModified = false;
      slowlyChangingPaModified = false;
      threadInfoModified = false;
      execTimesModified = false;
      deadlinesModified = false;
      waitingOnModified = false;
  } catch (SQLException e) {
      throw new EJBException(e);
  }
    }

    /**
     * A container invokes this method to synchronize the state of the
     * entity object in the database with the state of the enterprise bean
     * instancee.
     * @see javax.ejb.EntityBean
     */
    public void ejbStore() {
  try {
      if (persistentAttributeModified) {
    storeActivity();
    persistentAttributeModified = false;
    slowlyChangingPaModified = false;
    threadInfoModified = false;
    execTimesModified = false;
    deadlinesModified = false;
    waitingOnModified = false;
      }
  } catch (SQLException ex) {
      throw new EJBException(ex);
  }
    }

    /**
     * A container invokes this method to synchronize the state of an
     * enterprise bean instance with the entity object's state in the database.
     * @see javax.ejb.EntityBean
     */
    public void ejbLoad() {
  try {
      // load activity attributes from persistent store
       loadActivity();
      // notify underlying domain object
      refresh ();
  } catch (SQLException ex) {
      throw new EJBException(ex);
  }
    }

    /**
     * A container invokes this method before it ends the life of the session
     * object. This happens as a result of a client's invoking a remove
     * operation, or when a container decides to terminate the session object
     * after a timeout.
     * @throws RemoveException if the activity is not closed.
     * @see javax.ejb.EntityBean
     */
    public void ejbRemove() throws RemoveException {
  try {
      if (getPaTypedState().workflowState() != State.CLOSED
    && (!getPaTypedState().isSameOrSubState
        (NotRunningState.NOT_STARTED))) {
    throw new RemoveException
        ("Cannot remove " + toString() + ": still running.");
      }
      dispose();
      removeActivity();
      containerCache = null;
            containerLocalCache = null;
      nextActivitiesCache = null;
      thisRemoteCache = null;
      paDeadlines = null;
  } catch (RemoteException ex) {
      throw new EJBException(ex);
  } catch (SQLException ex) {
      throw new EJBException(ex);
  }
    }

    /**
     * This method retrieve the activities of a process.
     * @param primaryKey key to looked for
     * @return A Collection with primary keys from the found activities.
     */
    private Collection selectByProcess(Long primaryKey) throws SQLException {
  Connection con = null;
  PreparedStatement prepStmt = null;
  ResultSet rs = null;
  try {
      Collection activities = new ArrayList();
      con = ds.getConnection();
      String selectStatement
                = "SELECT DBId FROM activity WHERE ProcessDBId = ? "
    + " ORDER BY DBId ";
      prepStmt = con.prepareStatement(selectStatement);
      prepStmt.setLong(1, primaryKey.longValue());
      rs = prepStmt.executeQuery();
      while (rs.next()) {
    activities.add(new Long(rs.getLong(1)));
      }
      return activities;
  } finally {
      JDBCUtil.closeAll (rs, prepStmt, con);
  }
    }

    /**
     * This method checks if the activity exists.
     * @param primaryKey key to check
     * @return If it is ok, it returns true.
     */
    private boolean selectByPrimaryKey(Long primaryKey) throws SQLException {
  Connection con = null;
  PreparedStatement prepStmt = null;
  ResultSet rs = null;
  try {
      con = ds.getConnection();
      String selectStatement
                = "SELECT DBId FROM activity WHERE DBId = ? ";
      prepStmt = con.prepareStatement(selectStatement);
      prepStmt.setLong(1, primaryKey.longValue());
      rs = prepStmt.executeQuery();
      boolean result = rs.next();
      return result;
  } finally {
      JDBCUtil.closeAll (rs, prepStmt, con);
  }
    }
   
    /**
     * This method finds an activity waiting on a channel.
     * @param processId the containing process' id
     * @param channel the channel
     * @return the primary key
     */
    private Long selectByWaitingOn(Long processId, String channel)
  throws SQLException {
  Connection con = null;
  PreparedStatement prepStmt = null;
  ResultSet rs = null;
  try {
      con = ds.getConnection();
      prepStmt = con.prepareStatement
    ("SELECT DBId FROM Activity "
     + "WHERE WaitOnProc = ? AND WaitOnChan = ?");
      prepStmt.setLong(1, processId.longValue());
      prepStmt.setString(2, channel);
      rs = prepStmt.executeQuery();
      if (rs.next()) {
    return new Long (rs.getLong (1));
      }
      return null;
  } finally {
      JDBCUtil.closeAll (rs, prepStmt, con);
  }
    }
   
    /**
     * Insert a new activity info into database.
     */
    private void insertActivity()
  throws SQLException {
  Connection con = null;
  UniversalPrepStmt prepStmt = null;
  try {
      con = ds.getConnection();
      prepStmt = new UniversalPrepStmt
    (ds, con, "INSERT INTO activity (DBId, "
     + "ProcessMgr, ProcessMgrVersion, ProcessName, ProcessDBId, "
     + "Name, Description, BlockActivity, "
     + "Implementation, Performer, Priority, Executor, StartMode, "
     + "FinishMode, State, StateTime, JoinMode, SplitMode, "
     + "ThreadInfo, Subflow, SuspendAccum, PendingException, "
                 + "WaitOnProc, WaitOnChan, Flags) "
     + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
     + "?, ?, ?, ?, ?, ?, ?, ?)");
      int offset = 1;
      prepStmt.setLong(offset++,
           ((Long)ctx.getPrimaryKey()).longValue());
      prepStmt.setString (offset++, processMgr);
      prepStmt.setString (offset++, processMgrVers);
      prepStmt.setString (offset++, processName);
      prepStmt.setLong(offset++, processPk.longValue());
      prepStmt.setString (offset++, paName);
      prepStmt.setString (offset++, paDescription);
      prepStmt.setLong (offset++, paBlockActivity);
      prepStmt.setBinary (offset++, paActImpl);
      prepStmt.setString (offset++, paPerformer);
      prepStmt.setInt(offset++, paPriority.toInt ());
      prepStmt.setInt (offset++, paExecStat);
      prepStmt.setString (offset++, paStartMode.toString());
      prepStmt.setString (offset++, paFinishMode.toString());
      prepStmt.setString (offset++, paTypedState.toString ());
      prepStmt.setTimestamp
    (offset++, new Timestamp (paLastStateTime.getTime()));
      prepStmt.setString (offset++, paJoinMode.toString ());
      prepStmt.setString (offset++, paSplitMode.toString ());
      prepStmt.setBinary (offset++, paThreadInfo);
      prepStmt.setLong
    (offset++, paSubflow == null ? null : new Long(paSubflow));
      prepStmt.setLong(offset++, new Long (0)); // SuspendAccum
      prepStmt.setString(offset++, null); // PendingException
      prepStmt.setLong(offset++, null); // WaitOnProc
      prepStmt.setString(offset++, null); // WaitOnChan
      prepStmt.setInt(offset++, paFlags); // Flags
      // now execute
      prepStmt.executeUpdate();
      WfProcessEJB.updateDeadlines
    (ds, con, processPk, (Long)ctx.getPrimaryKey(),
     paDeadlines, false);
  } catch (IOException ioe) {
      logger.error (ioe.getMessage(), ioe);
  } finally {
      JDBCUtil.closeAll (null, prepStmt, con);
  }
    }

    /**
     * Store activity info in the database.
     */
    private void storeActivity() throws SQLException {
  Connection con = null;
  UniversalPrepStmt prepStmt = null;
  try {
      con = ds.getConnection();
      prepStmt = new UniversalPrepStmt
    (ds, con, "UPDATE activity "
     + "SET State = ?, StateTime = ?, Executor = ?, Subflow = ?, "
     + "Flags = ?"
     + (execTimesModified
        ? ", StartTime = ?, SuspendStart = ?, SuspendAccum = ? "
        : "")
     + (threadInfoModified ? ", ThreadInfo = ? " : "")
     + (waitingOnModified ? ", WaitOnProc = ?, WaitOnChan = ? ":"")
     + (slowlyChangingPaModified
        ? (", ProcessName = ?, Name = ?, Description = ?, "
           + "Implementation = ?, Performer = ?, "
           + "Priority = ?, StartMode = ?, "
           + "FinishMode = ?, JoinMode = ?, SplitMode = ?, "
                       + "PendingException = ?")
        : "")
     + " WHERE DBId = ?");
      int offset = 1;
      prepStmt.setString (offset++, paTypedState.toString());
      prepStmt.setTimestamp
    (offset++, new Timestamp (paLastStateTime.getTime()));
      prepStmt.setInt (offset++, paExecStat);
      prepStmt.setLong
    (offset++, paSubflow==null ? null : new Long(paSubflow));
      prepStmt.setInt (offset++, paFlags);
      if (execTimesModified) {
    prepStmt.setTimestamp
        (offset++, (paStartTime == null ? null
        : new Timestamp (paStartTime.getTime())));
    prepStmt.setTimestamp
        (offset++, (paSuspendStart == null ? null
        : new Timestamp (paSuspendStart.getTime())));
    prepStmt.setLong
        (offset++, new Long(paSuspendAccum));
      }
      if (threadInfoModified) {
    prepStmt.setBinary (offset++, paThreadInfo);
      }
      if (waitingOnModified) {
    prepStmt.setLong (offset++, paWaitOnProc);
    prepStmt.setString (offset++, paWaitOnChan);
      }
      if (slowlyChangingPaModified) {
    prepStmt.setString (offset++, processName);
    prepStmt.setString (offset++, paName);
    prepStmt.setString (offset++, paDescription);
    prepStmt.setBinary (offset++, paActImpl);
    prepStmt.setString (offset++, paPerformer);
    prepStmt.setInt(offset++, paPriority.toInt());
    prepStmt.setString (offset++, paStartMode.toString());
    prepStmt.setString (offset++, paFinishMode.toString());
    prepStmt.setString (offset++, paJoinMode.toString());
    prepStmt.setString (offset++, paSplitMode.toString());
                prepStmt.setString (offset++, paPendingException);
      }
      // for where statement
      prepStmt.setLong(offset++,
           ((Long)ctx.getPrimaryKey()).longValue());
      int rowCount = prepStmt.executeUpdate();
      if (rowCount == 0) {
    throw new NoSuchEntityException
        ("Storing row for DBId "
         + (Long)ctx.getPrimaryKey() + " failed.");
      }
      if (deadlinesModified) {
    WfProcessEJB.updateDeadlines
        (ds, con, processPk, (Long)ctx.getPrimaryKey(),
         paDeadlines, true);
      }
  } catch (IOException ioe) {
      logger.error (ioe.getMessage(), ioe);
  } finally {
      JDBCUtil.closeAll (null, prepStmt, con);
  }
    }

    /**
     * Load activity info from the database.
     * After sucessful loading, the process attribute structure
     * is set with the values just loaded.
     */
    private void loadActivity()
  throws SQLException {
  Connection con = null;
  PreparedStatement prepStmt = null;
  ResultSet rs = null;
  try {
      con = ds.getConnection();
      if (haveSelForUp == null) {
    haveSelForUp = new Boolean(JDBCUtil.dbProperties(ds, con)
             .supportsSelectForUpdate ());
      }
      prepStmt = con.prepareStatement
    ("SELECT "
     + "ProcessMgr, ProcessMgrVersion, ProcessName, ProcessDBId, "
     + "Name, Description, BlockActivity, Implementation, "
     + "Performer,  Priority, executor, StartMode, FinishMode, "
     + "State, StateTime, JoinMode, SplitMode, ThreadInfo, "
     + "Subflow, StartTime, SuspendStart, SuspendAccum, "
     + "PendingException, WaitOnProc, WaitOnChan, Flags "
     + "FROM activity WHERE DBId = ? "
     + (haveSelForUp.booleanValue() ? " FOR UPDATE" : ""));
      prepStmt.setLong(1, ((Long)ctx.getPrimaryKey()).longValue());
      rs = prepStmt.executeQuery();
      if (!rs.next()) {
    throw new NoSuchEntityException
        ("Row for id " + (Long)ctx.getPrimaryKey()
         + " not found in database.");
      }
      // read activity from db
      int offset = 1;
      processMgr = rs.getString(offset++);
      processMgrVers = rs.getString(offset++);
      processName = rs.getString(offset++);
      processPk = new Long(rs.getLong(offset++));
      paName = rs.getString(offset++);
      paDescription = rs.getString(offset++);
      paBlockActivity = JDBCUtil.getLong(rs, offset++);
      paActImpl = (Implementation[])JDBCUtil.getBinary(rs, offset++);
      paPerformer = rs.getString(offset++);
      paPriority = Priority.fromInt(rs.getInt(offset++));
      paExecStat = JDBCUtil.getInteger(rs, offset++);
      paStartMode = StartFinishMode.fromString(rs.getString(offset++));
      paFinishMode = StartFinishMode.fromString(rs.getString(offset++));
      paTypedState = State.fromString(rs.getString(offset++));
      paLastStateTime = rs.getTimestamp(offset++);
      paJoinMode = JoinAndSplitMode.fromString(rs.getString(offset++));
      paSplitMode = JoinAndSplitMode.fromString(rs.getString(offset++));
      paThreadInfo = (ThreadInfo)JDBCUtil.getBinary(rs, offset++);
      Long sf = JDBCUtil.getLong (rs, offset++);
      paSubflow = (sf == null ? null : sf.toString());
      paStartTime = rs.getTimestamp(offset++);
      paSuspendStart = rs.getTimestamp(offset++);
      paSuspendAccum = rs.getLong(offset++);
            paPendingException = rs.getString(offset++);
      paWaitOnProc = JDBCUtil.getLong(rs, offset++);
      paWaitOnChan = rs.getString(offset++);
      paFlags = rs.getInt(offset++);
  } catch (IOException ioe) {
      logger.error (ioe.getMessage(), ioe);
      throw new SQLException(ioe.getMessage());
  } catch (ClassNotFoundException cnfe) {
      logger.error (cnfe.getMessage(), cnfe);
      throw new SQLException(cnfe.getMessage());
  } catch (InvalidStateException ise) {
      logger.error (ise.getMessage(), ise);
      throw new SQLException(ise.getMessage());
  } catch (InvalidPriorityException ipe) {
      logger.error (ipe.getMessage(), ipe);
      throw new SQLException(ipe.getMessage());
  } finally {
      JDBCUtil.closeAll (rs, prepStmt, con);
  }
    }

    /**
     * Remove activity info from the database.
     */
    private void removeActivity() throws SQLException, RemoteException {
  Connection con = null;
  PreparedStatement prepStmt = null;
  try {
      if (!typedState().isSameOrSubState (State.CLOSED)
    && !(typedState().isSameOrSubState
         (NotRunningState.NOT_STARTED))) {
    releaseResources ();
    try {
        terminateImpl();
    } catch (ApplicationNotStoppedException ans) {
        logger.warn ("Removing activity " + toString()
         + " while tool still running.");
    }
      }
      con = ds.getConnection();
      String deleteStatement = "DELETE FROM activity WHERE DBId = ? ";
      prepStmt = con.prepareStatement(deleteStatement);
      prepStmt.setLong(1, ((Long)ctx.getPrimaryKey()).longValue());
      prepStmt.executeUpdate();
      // deadlines are removed with the process
  } finally {
      JDBCUtil.closeAll (null, prepStmt, con);
  }
    }
   
    //
    // Domain methods and helpers
    //

    /**
     * Indicates if some other object is equal to this one. <P>
     *
     * Note that <code>obj</code> must implement the activity's
     * remote interface. Comparing a domain object usually
     * indicates some violation of the constraints of our
     * implementation environment.
     *
     * @param obj the object to compare with.
     * @return <code>true</code> if the other object is equal.
     */
    public boolean equals (Object obj) {
      return ctx.getPrimaryKey().toString()
    .equals (((WfActivityLocal)obj).key());
    }

    /**
     *  Return the hash code.<P>
     @return the result.
     */
    public int hashCode () {
        return ctx.getPrimaryKey().toString().hashCode();
    }
   
    /**
     * Check if the given assignment is among the assignments of this
     * activity.
     * @param member the assignment in question.
     * @return true if the assignment is among the assignments of this
     * activity.
     * @ejb.interface-method view-type="remote"
     */
    public boolean isMemberOfAssignments (WfAssignment member) {
  throw new UnsupportedOperationException();
    }

    /**
     * Return the remote version of this object. This is the client side
     * implementation of the remote interface (i.e. the EJB object).
     *
     * @return the remote stub.
     */
    public Activity toActivity () {
  if (thisRemoteCache == null) {
      try {
    thisRemoteCache = ActivityProxy
        .wrap ((ExtActivity)ctx.getEJBObject(),
         container (), uniqueKey());
      } catch (RemoteException e) {
    // actually, uniqueKey never throws a remote exception in
    // this context (and getEJBObject never does)
    logger.error (e.getMessage (), e);
    throw new IllegalStateException (e.getMessage());
      }
  }
  return thisRemoteCache;
    }

   
    /* (non-Javadoc)
     * Comment copied from interface or superclass.
     */
    public ExtActivityLocal toActivityLocal() {
        ExtActivityLocal actLocal = (ExtActivityLocal)ctx.getEJBLocalObject();
        return actLocal;
    }

    /**
     * Returns the <code>WfProcess</code> that this activity is a part of.
     * @return the process.
     * @ejb.interface-method view-type="remote"
     */
    public WfProcess container() {
  if (containerCache == null) {
      try {
    containerCache = processHome().findByPrimaryKey(processPk);
      } catch (FinderException fe) {
    throw new EJBException(fe);
      } catch (RemoteException re) {
    throw new EJBException(re);
      }
  }
  return containerCache;
    }

    /**
     * Returns the <code>WfProcessLocal</code> that this activity is a part of.
     * @return the process.
     * @ejb.interface-method view-type="local"
     */
    public WfProcessLocal containerLocal() {
        if (containerLocalCache == null) {
            try {
                containerLocalCache
                    = processLocalHome().findByPrimaryKey(processPk);
            } catch (FinderException fe) {
                throw new EJBException(fe);
            } catch (RemoteException re) {
                throw new EJBException(re);
            }
        }
        return containerLocalCache;
    }

    /**
     * Lookup a process by its key.
     * @param key the primary key
     * @return the process
     * @throws RemoteException if a system-level error occurs
     * @throws InvalidKeyException if no process with the given key
     * exists
     */
    protected ExtProcessLocal lookupProcessLocal (String key)
        throws InvalidKeyException {
        try {
            return processLocalHome().findByPrimaryKey(new Long(key));
        } catch (FinderException fe) {
            logger.debug (fe.getMessage (), fe);
            throw new InvalidKeyException(fe.getMessage ());
        } catch (ResourceNotAvailableException e) {
            throw new EJBException (e);
        } catch (RemoteException e) {
            throw new EJBException (e);
        }
    }

    /**
     * Returns an {@link de.danet.an.workflow.spis.ras.ActivityFinder
     * <code>ActivityFinder</code>} that identifies this activity
     * against a resource assignment service as defined by
     * {@link de.danet.an.workflow.spis.ras the ras package}.
     *
     * @return the activity finder.
     */
    public ActivityFinder activityFinder () {
  if (activityFinderCache == null) {
      activityFinderCache
    = new de.danet.an.workflow.ejbs.admin.ActivityFinder
    ("java:comp/env/ejb/Configuration");
  }
  return activityFinderCache;
    }

    /**
     * Returns an <code>WfAuditEvent</code> containing container-related
     * information.
     * @return the audit event
     */
    protected WfAuditEvent containerAuditEventBase () {
  return new DefaultAuditEvent
      (null, null, processPk.toString(), processName,
       processMgr, processMgrVers, getPaAuditEventSelection(),
       getPaStoreAuditEvents());
    }

    /**
     * Returns a <code>WfAuditEvent</code> containing information about the
     * activity and its container, only.
     * @return the event containing the required information.
     * @ejb.interface-method view-type="remote"
     */
    public WfAuditEvent auditEventBase () {
  return auditEventBase (null);
    }

    /**
     * Returns the list of activities that may follow this activity,
     * i.e. to which transitions exist.
     * The list follows the order of transitions as returend by the
     * container.
     * @return the list of {@link de.danet.an.workflow.domain Activity
     * <code>Activity</code>} objects.
     * @ejb.interface-method view-type="remote"
     */
    public List nextActivities () {

        // cached result?
  if (nextActivitiesCache != null) {
      return nextActivitiesCache;
  }

  // new evaluation needed
  nextActivitiesCache = new ArrayList();
  List allTrans = ((ProcessLocal)containerLocal()).transitionsLocal();
  for (Iterator tri = allTrans.iterator(); tri.hasNext();) {
      TransitionLocal trans = (TransitionLocal)tri.next();
      if (key().equals (trans.from().key())) {
    nextActivitiesCache.add
                    (((ExtActivityLocal)trans.to()).toActivity());
      }
  }
  return nextActivitiesCache;
    }

    /**
     * Return a <code>ToolInvocationHandler</code>.
     * @return a handler.
     */
    protected ToolInvocationHandler toolInvocationHandler () {
        if (toolInvocationHandlerCache == null) {
            try {
                toolInvocationHandlerCache
                    = new DefaultToolInvocationHandler
                        (engine(), engineLocal(),
                         queueConnectionFactory(), applicationInvocationQueue(),
                         invocationHelper());
            } catch (ResourceNotAvailableException e) {
                throw new EJBException (e);
            } catch (RemoteException e) {
                throw new EJBException (e);
            }
        }
        return toolInvocationHandlerCache;
    }

    /**
     * Process newly generated event.
     * @param evt Event
     */
    protected void fireAuditEvent(WfAuditEvent evt) {
  try {
      QueuerUtils.queue (queueConnectionFactory(), eventQueue(),
                         (DefaultAuditEvent)evt);
  } catch (RemoteException e) {
      throw new EJBException (e);
  }
    }

    /**
     * Returns a collection of <code>WfAuditEvent</code>s associated with
     * this process describing its history.
     * @return the collection of audit events
     * @throws HistoryNotAvailableException in case the history is not
     * available for any reason
     * @ejb.interface-method view-type="remote"
    */
    public Collection history()
  throws HistoryNotAvailableException {
  WorkflowEngine engine  = null;
  try {
      return engineLocal().history (toActivity());
  } catch (RemoteException rex){
      throw new EJBException (rex);
  }
    }

    /**
     * Updates the process name (which is cached by the activity EJB)
     * if the process name changes.
     * @param newName the new process name.
     * @ejb.interface-method view-type="remote"
     */
    public void updateProcessName (String newName) {
  processName = newName;
  slowlyChangingPaModified = true;
    }

    /**
     * Check if the given process is among the performers of this requester.
     *
     * @param member the process in question.
     * @return <code>true</code> if the <code>process</code> is among
     * the performers of this requester.
     */
    public boolean isMemberOfPerformers(WfProcess member) {
        for (Iterator ps = performers().iterator(); ps.hasNext();) {
            WfProcess p = (WfProcess)ps.next();
            try {
                if (p.key().equals (member.key())) {
                    return true;
                }
            } catch (RemoteException e) {
                throw new EJBException (e);
            }
        }
        return false;
    }

    //
    // Timers
    //

    /**
     * Start a timer that will call <code>handleTimeout</code> at the
     * given date with the given info.
     * @param due target date
     * @param info the context
     */
    public void startTimer (Date due, Serializable info) {
        if (logger.isDebugEnabled()) {
            logger.debug("Starting timer for " + toString()
                         + ", due at " + due);
        }
        // Adjust duration
        long duration = due.getTime() - System.currentTimeMillis();
        if (duration <= 0) {
            logger.warn("Deadline with zero or negative duration ("
                        + ((double)duration / 1000) + "s) for "
                        + toString() + " will be triggered immediately.");
            duration = 1;
        }
        if (ctx.getClass().getName().startsWith("org.jboss.ejb.")) {
            // create a timer with interval to circumvent JBoss bug JBAS-2274
            ctx.getTimerService().createTimer (duration, 3600 * 1000, info);
        } else {
            ctx.getTimerService().createTimer (duration, info);
        }
    }

    /**
     * Stop all timers that this object has created.
     */
    public void stopTimers () {
  for (Iterator i = ctx.getTimerService().getTimers().iterator ();
       i.hasNext ();) {
      Timer timer = (Timer)i.next();
      timer.cancel ();
  }
    }

    /**
     * Handle the timeout of a timer.
     * @param timer the timer that has expired.
     */
    public void ejbTimeout (Timer timer) {
  try {
            if (logger.isDebugEnabled()) {
                logger.debug ("Received timeout from " + timer
                              + " for " + toString());
            }
            try {
                handleTimeout (timer.getInfo());
                if (ctx.getClass().getName().startsWith("org.jboss.ejb.")) {
                    // Because of JBoss bug JBAS-2274 we have an interval and
                    // must therefore cancel the timer
                    timer.cancel();
                }
            } catch (NoSuchObjectLocalException e) {
                // JBoss may call this method with a canceled timer
                if (timer.getClass().getName()
                    .equals("org.jboss.ejb.txtimer.TimerImpl")) {
                    logger.debug("Exception \"" + e.getMessage()
                                 + "\" ignored, caused by JBoss bug.");
                    return;
                }
                throw e;
            }
  } catch (EJBException e) {
      throw e;
  } catch (Throwable e) {
      logger.error ("Problem handling timer event " + timer
        + "(discarded): " + e.getMessage(), e);     
  }
    }
   
    //
    // Implement accessor methods for the persistent attributes
    //

    /**
     * The getter method implementation for the persistent
     * attribute <code>key</code>.
     *
     * @return the value of key.
     */
    protected String getPaKey() {
  return ((Long)ctx.getPrimaryKey()).toString();
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>name</code>.
     *
     * @see #setPaName
     * @return the value of name.
     */
    protected String getPaName() {
  return paName;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>name</code>.
     *
     * @param newName the new value of name.
     * @see #getPaName
     */
    protected void setPaName(String newName) {
  paName = newName;
  persistentAttributeModified = true;
  slowlyChangingPaModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>description</code>.
     *
     * @see #setPaDescription
     * @return the value of description.
     */
    protected String getPaDescription() {
  return paDescription;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>description</code>.
     *
     * @param newDescription the new value of description.
     * @see #getPaDescription
     */
    protected void setPaDescription(String newDescription) {
  paDescription = newDescription;
  persistentAttributeModified = true;
  slowlyChangingPaModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>priority</code>.
     *
     * @see #setPaPriority
     * @return the value of priority.
     */
    protected Priority getPaPriority() {
  return paPriority;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>priority</code>.
     *
     * @param newPriority the new value of priority.
     * @see #getPaPriority
     */
    protected void setPaPriority(Priority newPriority) {
  paPriority = newPriority;
  persistentAttributeModified = true;
  slowlyChangingPaModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>typedState</code>.
     *
     * @see #setPaTypedState
     * @return the value of typedState.
     */
    protected State getPaTypedState() {
  return paTypedState;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>lastStateTime</code>.
     *
     * @see #setPaLastStateTime
     * @return the value of lastStateTime.
     */
    protected Date getPaLastStateTime() {
  return paLastStateTime;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>lastStateTime</code>.
     *
     * @param newLastStateTime the new value of lastStateTime.
     * @see #getPaLastStateTime
     */
    protected void setPaLastStateTime(Date newLastStateTime) {
  paLastStateTime = newLastStateTime;
  persistentAttributeModified = true;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>typedState</code>.
     *
     * @param newTypedState the new value of typedState.
     * @see #getPaTypedState
     */
    protected void setPaTypedState(State newTypedState) {
  paTypedState = newTypedState;
  persistentAttributeModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>startMode</code>.
     *
     * @see #setPaStartMode
     * @return the value of startMode.
     */
    protected StartFinishMode getPaStartMode() {
  return paStartMode;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>startMode</code>.
     *
     * @param newStartMode the new value of startMode.
     * @see #getPaStartMode
     */
    protected void setPaStartMode(StartFinishMode newStartMode) {
  paStartMode = newStartMode;
  persistentAttributeModified = true;
  slowlyChangingPaModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>finishMode</code>.
     *
     * @see #setPaFinishMode
     * @return the value of finishMode.
     */
    protected StartFinishMode getPaFinishMode() {
  return paFinishMode;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>finishMode</code>.
     *
     * @param newFinishMode the new value of finishMode.
     * @see #getPaFinishMode
     */
    protected void setPaFinishMode(StartFinishMode newFinishMode) {
  paFinishMode = newFinishMode;
  persistentAttributeModified = true;
  slowlyChangingPaModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>joinMode</code>.
     *
     * @see #setPaJoinMode
     * @return the value of joinMode.
     */
    protected JoinAndSplitMode getPaJoinMode() {
  return paJoinMode;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>joinMode</code>.
     *
     * @param newJoinMode the new value of joinMode.
     * @see #getPaJoinMode
     */
    protected void setPaJoinMode(JoinAndSplitMode newJoinMode) {
  paJoinMode = newJoinMode;
  persistentAttributeModified = true;
  slowlyChangingPaModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>splitMode</code>.
     *
     * @see #setPaSplitMode
     * @return the value of splitMode.
     */
    protected JoinAndSplitMode getPaSplitMode() {
  return paSplitMode;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>splitMode</code>.
     *
     * @param newSplitMode the new value of splitMode.
     * @see #getPaSplitMode
     */
    protected void setPaSplitMode(JoinAndSplitMode newSplitMode) {
  paSplitMode = newSplitMode;
  persistentAttributeModified = true;
  slowlyChangingPaModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>executor</code>.
     *
     * @see #setPaExecStat
     * @return the value of executor.
     */
    protected Integer getPaExecStat() {
  return paExecStat;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>performer</code>.
     *
     * @see #setPaPerformer
     * @return the value of performer.
     */
    protected String getPaPerformer() {
  return paPerformer;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>performer</code>.
     *
     * @param newPerformer the new value of performer.
     * @see #getPaPerformer
     */
    protected void setPaPerformer(String newPerformer) {
  paPerformer = newPerformer;
  persistentAttributeModified = true;
  slowlyChangingPaModified = true;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>executor</code>.
     *
     * @param newExecutor the new value of executor.
     * @see #getPaExecStat
     */
    protected void setPaExecStat(Integer newExecutor) {
  paExecStat = newExecutor;
  persistentAttributeModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>actImpl</code>.
     *
     * @see #setPaActImpl
     * @return the value of actImpl.
     */
    protected Implementation[] getPaActImpl() {
  return paActImpl;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>actImpl</code>.
     *
     * @param newActImpl the new value of actImpl.
     * @see #getPaActImpl
     */
    protected void setPaActImpl(Implementation[] newActImpl) {
  paActImpl = newActImpl;
  persistentAttributeModified = true;
  slowlyChangingPaModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * read-only attribute <code>processKey</code>.
     *
     * @return the value of processKey.
     */
    protected String getPaProcessKey() {
  return processPk.toString();
    }

    /**
     * The getter method implementation for the persistent
     * read-only attribute <code>processName</code>.
     *
     * @return the value of processName.
     */
    protected String getPaProcessName() {
  return processName;
    }

    /**
     * The getter method implementation for the persistent
     * read-only attribute <code>processMgrName</code>.
     *
     * @return the value of processMgrName.
     */
    protected String getPaProcessMgrName() {
  return processMgr;
    }

    /**
     * The getter method implementation for the persistent
     * read-only attribute <code>processMgrVersion</code>.
     *
     * @return the value of processMgrVersion.
     */
    protected String getPaProcessMgrVersion() {
  return processMgrVers;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>threadInfo</code>.
     *
     * @see #setPaThreadInfo
     * @return the value of threadInfo.
     */
    protected ThreadInfo getPaThreadInfo() {
  return paThreadInfo;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>threadInfo</code>.
     *
     * @param newThreadInfo the new value of threadInfo.
     * @see #getPaThreadInfo
     */
    protected void setPaThreadInfo(ThreadInfo newThreadInfo) {
  paThreadInfo = newThreadInfo;
  persistentAttributeModified = true;
  threadInfoModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>Subflow</code>.
     *
     * @see #setPaSubflow
     * @return the value of Subflow.
     */
    protected String getPaSubflow() {
  return paSubflow;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>Subflow</code>.
     *
     * @param newSubflow the new value of Subflow.
     * @see #getPaSubflow
     */
    protected void setPaSubflow(String newSubflow) {
  paSubflow = newSubflow;
  persistentAttributeModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>deadlines</code>.
     *
     * @see #setPaDeadlines
     * @return the value of deadlines.
     */
    protected List getPaDeadlines() {
  if (paDeadlines == null) {
      try {
    paDeadlines = WfProcessEJB.loadDeadlines
        (ds, (Long)ctx.getPrimaryKey());
      } catch (SQLException e) {
    throw new EJBException (e);
      } catch (IOException e) {
    throw new EJBException (e);
      }
  }
  return paDeadlines;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>deadlines</code>.
     *
     * @param newDeadlines the new value of deadlines.
     * @see #getPaDeadlines
     */
    protected void setPaDeadlines(List newDeadlines) {
  paDeadlines = newDeadlines;
  persistentAttributeModified = true;
  deadlinesModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>startTime</code>.
     *
     * @see #setPaStartTime
     * @return the value of startTime.
     */
    protected Date getPaStartTime() {
  return paStartTime;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>startTime</code>.
     *
     * @param newStartTime the new value of startTime.
     * @see #getPaStartTime
     */
    protected void setPaStartTime(Date newStartTime) {
  paStartTime = newStartTime;
  execTimesModified = true;
  persistentAttributeModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>suspendStart</code>.
     *
     * @see #setPaSuspendStart
     * @return the value of suspendStart.
     */
    protected Date getPaSuspendStart() {
  return paSuspendStart;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>suspendStart</code>.
     *
     * @param newSuspendStart the new value of suspendStart.
     * @see #getPaSuspendStart
     */
    protected void setPaSuspendStart(Date newSuspendStart) {
  paSuspendStart = newSuspendStart;
  persistentAttributeModified = true;
  execTimesModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>suspendAccum</code>.
     *
     * @see #setPaSuspendAccum
     * @return the value of suspendAccum.
     */
    protected long getPaSuspendAccum() {
  return paSuspendAccum;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>suspendAccum</code>.
     *
     * @param newSuspendAccum the new value of suspendAccum.
     * @see #getPaSuspendAccum
     */
    protected void setPaSuspendAccum(long newSuspendAccum) {
  paSuspendAccum = newSuspendAccum;
  persistentAttributeModified = true;
  execTimesModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>pendingException</code>.
     *
     * @see #setPaPendingException
     * @return the value of pendingException.
     */
    protected String getPaPendingException() {
        return paPendingException;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>pendingException</code>.
     *
     * @param newPendingException the new value of pendingException.
     * @see #getPaPendingException
     */
    protected void setPaPendingException(String newPendingException) {
        paPendingException = newPendingException;
        persistentAttributeModified = true;
        slowlyChangingPaModified = true;
    }

    /** Persistent attribute <code>blockActivity</code>. */
    private Long paBlockActivity;

    /**
     * The getter method implementation for the persistent
     * attribute <code>blockActivity</code>.
     *
     * @see #setPaBlockActivity
     * @return the value of blockActivity.
     */
    protected Long getPaBlockActivity() {
  return paBlockActivity;
    }

    /**
     * The setter method implementation for the persistent attribute
     * <code>blockActivity</code>. May only be used in base class'
     * init.
     *
     * @param newBlockActivity the new value of blockActivity.
     * @see #getPaBlockActivity
     */
    protected void setPaBlockActivity(Long newBlockActivity) {
  paBlockActivity = newBlockActivity;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>waitOnProc</code>.
     *
     * @see #setPaWaitOnProc
     * @return the value of waitOnProc.
     */
    protected Long getPaWaitOnProc() {
  return paWaitOnProc;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>waitOnProc</code>.
     *
     * @param newWaitOnProc the new value of waitingOn.
     * @see #getPaWaitOnProc
     */
    protected void setPaWaitOnProc(Long newWaitOnProc) {
  if (newWaitOnProc == null && paWaitOnProc == null
      || (newWaitOnProc != null && paWaitOnProc != null
    && newWaitOnProc.equals (paWaitOnProc))) {
      return;
  }
  paWaitOnProc = newWaitOnProc;
  persistentAttributeModified = true;
  waitingOnModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>waitOnChan</code>.
     *
     * @see #setPaWaitOnChan
     * @return the value of waitOnChan.
     */
    protected String getPaWaitOnChan() {
  return paWaitOnChan;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>waitOnChan</code>.
     *
     * @param newWaitOnChan the new value of waitingOn.
     * @see #getPaWaitOnChan
     */
    protected void setPaWaitOnChan(String newWaitOnChan) {
  if (newWaitOnChan == null && paWaitOnChan == null
      || (newWaitOnChan != null && paWaitOnChan != null
    && newWaitOnChan.equals (paWaitOnChan))) {
      return;
  }
  paWaitOnChan = newWaitOnChan;
  persistentAttributeModified = true;
  waitingOnModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>debug</code>.
     *
     * @see #setPaDebug
     * @return the value of debug.
     */
    protected boolean getPaDebug() {
  return (paFlags & FLAGS_DEBUG) != 0;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>debug</code>.
     *
     * @param newDebug the new value of debug.
     * @see #getPaDebug
     */
    protected void setPaDebug(boolean newDebug) {
  paFlags = (paFlags & ~FLAGS_DEBUG)
      | (newDebug ? FLAGS_DEBUG : 0);
  persistentAttributeModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>subStateBackup</code>.
     *
     * @see #setPaSubStateBackup
     * @return the value of subStateBackup.
     */
    protected int getPaSubStateBackup() {
  return (paFlags & FLAGS_SUB_STATE_MASK) >> FLAGS_SUB_STATE_SHIFT;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>subStateBackup</code>.
     *
     * @param newSubStateBackup the new value of subStateBackup.
     * @see #getPaSubStateBackup
     */
    protected void setPaSubStateBackup(int newSubStateBackup) {
  paFlags = (paFlags & ~FLAGS_SUB_STATE_MASK)
      | (newSubStateBackup << FLAGS_SUB_STATE_SHIFT);
  persistentAttributeModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>deferChoiceOnSplit</code>.
     *
     * @see #setPaDeferChoiceOnSplit
     * @return the value of deferChoiceOnSplit.
     */
    protected boolean getPaDeferChoiceOnSplit() {
  return (paFlags & FLAGS_DEFERRED_CHOICE) != 0;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>deferChoiceOnSplit</code>.
     *
     * @param newDeferChoiceOnSplit the new value of deferChoiceOnSplit.
     * @see #getPaDeferChoiceOnSplit
     */
    protected void setPaDeferChoiceOnSplit(boolean newDeferChoiceOnSplit) {
  paFlags = (paFlags & ~FLAGS_DEFERRED_CHOICE)
      | (newDeferChoiceOnSplit ? FLAGS_DEFERRED_CHOICE : 0);
  persistentAttributeModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>preliminaryChosen</code>.
     *
     * @see #setPaPreliminarilyChosen
     * @return the value of preliminarilyChosen.
     */
    protected boolean getPaPreliminarilyChosen() {
  return (paFlags & FLAGS_PRELIMINARILY_CHOSEN) != 0;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>preliminaryChosen</code>.
     *
     * @param newPreliminarilyChosen the new value of preliminarilyChosen.
     * @see #getPaPreliminarilyChosen
     */
    protected void setPaPreliminarilyChosen(boolean newPreliminarilyChosen) {
  paFlags = (paFlags & ~FLAGS_PRELIMINARILY_CHOSEN)
      | (newPreliminarilyChosen ? FLAGS_PRELIMINARILY_CHOSEN : 0);
  persistentAttributeModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>noAssignments</code>.
     *
     * @see #setPaNoAssignments
     * @return the value of noAssignments.
     */
    protected boolean getPaNoAssignments() {
  return (paFlags & FLAGS_NO_ASSIGNMENTS) != 0;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>noAssignments</code>.
     *
     * @param newNoAssignments the new value of noAssignments.
     * @see #getPaNoAssignments
     */
    protected void setPaNoAssignments(boolean newNoAssignments) {
  paFlags = (paFlags & ~FLAGS_NO_ASSIGNMENTS)
      | (newNoAssignments ? FLAGS_NO_ASSIGNMENTS : 0);
  persistentAttributeModified = true;
    }

    /**
     * The getter method for the persistent flag
     * <code>pendingExceptionIsFromBlock</code>.
     *
     * @return the value of the flag.
     * @see #setPaPendingExceptionIsFromBlock
     */
    protected boolean getPaPendingExceptionIsFromBlock() {
        return (paFlags & FLAGS_PENDING_EXCEPTION_IS_FROM_BLOCK) != 0;
    }

    /**
     * The setter method for the persistent flags
     * <code>pendingExceptionIsFromBlock</code>.
     *
     * @param newValue the new value of the flag.
     * @see #getPaPendingExceptionIsFromBlock
     */
    protected void setPaPendingExceptionIsFromBlock (boolean newValue) {
        paFlags = (paFlags & ~FLAGS_PENDING_EXCEPTION_IS_FROM_BLOCK)
            | (newValue ? FLAGS_PENDING_EXCEPTION_IS_FROM_BLOCK : 0);
        persistentAttributeModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>auditEventSelection</code>.
     *
     * @see #setPaAuditEventSelection
     * @return the value of auditEventSelection.
     */
    protected int getPaAuditEventSelection() {
  return (paFlags & FLAGS_AUDIT_SELECTION_MASK)
      >> FLAGS_AUDIT_SELECTION_SHIFT;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>auditEventSelection</code>.
     *
     * @param newValue the new value of auditEventSelection.
     * @see #getPaAuditEventSelection
     */
    protected void setPaAuditEventSelection (int newValue) {
  paFlags = (paFlags & ~FLAGS_AUDIT_SELECTION_MASK)
      | (newValue << FLAGS_AUDIT_SELECTION_SHIFT);
  persistentAttributeModified = true;
    }

    /**
     * The getter method implementation for the persistent
     * attribute <code>storeAuditEvents</code>.
     *
     * @see #setPaStoreAuditEvents
     * @return the value of storeAuditEvents.
     */
    protected boolean getPaStoreAuditEvents() {
  return (paFlags & FLAGS_STORE_AUDIT_EVENTS) != 0;
    }

    /**
     * The setter method implementation for the persistent
     * attribute <code>storeAuditEvents</code>.
     *
     * @param newValue the new value of storeAuditEvents.
     * @see #getPaStoreAuditEvents
     */
    protected void setPaStoreAuditEvents(boolean newValue) {
  paFlags = (paFlags & ~FLAGS_STORE_AUDIT_EVENTS)
      | (newValue ? FLAGS_STORE_AUDIT_EVENTS : 0);
  persistentAttributeModified = true;
    }
   
}
TOP

Related Classes of de.danet.an.workflow.ejbs.core.WfActivityEJB

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.