Package de.danet.an.workflow.ejbs.admin

Source Code of de.danet.an.workflow.ejbs.admin.ProcessDefinitionDirectoryEJB$ProcessDefinitionInfo

/*
* 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: ProcessDefinitionDirectoryEJB.java 2921 2009-02-14 20:41:30Z mlipp $
*/
package de.danet.an.workflow.ejbs.admin;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OptionalDataException;
import java.io.Serializable;
import java.io.StringReader;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.commons.collections.map.ReferenceMap;
import org.xml.sax.InputSource;

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.util.logging.RequestLog;
import de.danet.an.util.logging.RequestScope;

import de.danet.an.workflow.internalapi.ExtProcessLocal;
import de.danet.an.workflow.localcoreapi.WfProcessLocal;
import de.danet.an.workflow.omgcore.InvalidRequesterException;
import de.danet.an.workflow.omgcore.NotEnabledException;
import de.danet.an.workflow.omgcore.RequesterRequiredException;
import de.danet.an.workflow.omgcore.WfRequester;

import de.danet.an.workflow.api.ImportException;
import de.danet.an.workflow.api.InvalidKeyException;
import de.danet.an.workflow.api.ProcessDefinition;
import de.danet.an.workflow.api.ProcessMgr;

import de.danet.an.workflow.domain.AbstractProcessDefinitionDirectory;
import de.danet.an.workflow.domain.DefaultProcessDefinition;

import de.danet.an.workflow.ejbs.core.WfProcessHome;
import de.danet.an.workflow.ejbs.core.WfProcessLocalHome;

/**
* The session bean <code>ProcessDefinitionDirectoryEJB</code> manage the
* process definitions.<P>
*
* Setting log level to <code>DEBUG</code> outputs messages about
* process definition caching.
*
* @ejb.bean name="ProcessDefinitionDirectory"
* display-name="ProcessDefinitionDirectory"
* jndi-name="ejb/@@@_JNDI_Name_Prefix_@@@ProcessDefinitionDirectory"
* local-jndi-name="ejb/@@@_JNDI_Name_Prefix_@@@ProcessDefinitionDirectoryLocal"
* type="Stateless" transaction-type="Container" view-type="both"
* @jonas.bean ejb-name="ProcessDefinitionDirectory"
* @ejb.home
* remote-class="de.danet.an.workflow.ejbs.admin.ProcessDefinitionDirectoryHome"
* @ejb.interface
* extends="javax.ejb.EJBObject, de.danet.an.workflow.api.ProcessDefinitionDirectory"
* remote-class="de.danet.an.workflow.ejbs.admin.ProcessDefinitionDirectory"
* local-extends="javax.ejb.EJBLocalObject, de.danet.an.workflow.localapi.ProcessDefinitionDirectoryLocal"
* local-class="de.danet.an.workflow.ejbs.admin.ProcessDefinitionDirectoryLocal"
* @ejb.ejb-ref ejb-name="ConfigurationBean" view-type="remote"
* ref-name="ejb/Configuration"
* @ejb.ejb-ref ejb-name="ProcessBean" view-type="remote"
* @ejb.ejb-ref ejb-name="ProcessBean" view-type="local"
* @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.transaction type="Required"
* @ejb.permission role-name="WfMOpenAdmin"
* @weblogic.transaction-isolation TRANSACTION_READ_COMMITTED
*/
public class ProcessDefinitionDirectoryEJB
    extends AbstractProcessDefinitionDirectory
    implements SessionBean {

    /**
     * logger of this class.
     */
    private static final org.apache.commons.logging.Log logger
  = org.apache.commons.logging.LogFactory.getLog
  (ProcessDefinitionDirectoryEJB.class);

    /**
     * A cache for for process definitions as found in the database
     */
    private static Map processDefinitionInfoCache
  = Collections.synchronizedMap(new HashMap());

    /**
     * A cache for archived process definitions.
     */
    private static Map archivedProcessDefinitionCache
        = Collections.synchronizedMap(new ReferenceMap());
   
    /**
     * An index on the cache using pacjageId/processId as key.
     */
    private static Map processDefinitionDBIds
  = Collections.synchronizedMap(new HashMap());

    /**
     * The SessionContext interface of the instance.
     */
    private SessionContext ctx;

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

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

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

    /** The cached home interface of the configuration EJB. */
    private ConfigurationHome configurationHomeCache = null;

    /**
     * This operation method delivers a WfProcessHome interface.
     * @return home interface of WfProcessBean
     * {@link de.danet.an.workflow.omgcore.WfProcess <code>WfProcess</code>}
     */
    private WfProcessHome processHome() throws ResourceNotAvailableException {
  if (processHomeCache == null) {
      processHomeCache = (WfProcessHome)EJBUtil.retrieveEJBHome
    (WfProcessHome.class, "java:comp/env/ejb/ProcessBean");
  }
  return processHomeCache;
    }

    /**
     * This operation method delivers a WfProcessLocalHome interface.
     * @return home interface of WfProcessBean
     * {@link de.danet.an.workflow.omgcore.WfProcess <code>WfProcess</code>}
     */
    private WfProcessLocalHome processLocalHome() {
        if (processLocalHomeCache == null) {
            try {
                processLocalHomeCache
                    = (WfProcessLocalHome)EJBUtil.retrieveEJBLocalHome
                    (WfProcessLocalHome.class,
                     "java:comp/env/ejb/ProcessBeanLocal");
            } catch (ResourceNotAvailableException e) {
                throw new EJBException(e);
            }
        }
        return processLocalHomeCache;
    }

    /**
     * set the session context and get new data source. 
     * @param context the given session context.
     * @throws EJBException if problem encountered with getting the data source.
     */
    public void setSessionContext(SessionContext context)
  throws EJBException {
        ctx = context;
  processHomeCache = null;
  configurationHomeCache = null;
  try {
      // getting new data source
      ds = JDBCUtil.refreshDS(null, DB_NAME);
  } catch (NamingException ne) {
      throw new EJBException(ne);
  }
    }
   
    /**
     * Not called for stateless session bean.
     */
    public void ejbActivate() {
    }

    /**
     * Not called for stateless session bean.
     */
    public void ejbPassivate() {
    }

    /**
     * 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.
     * @see javax.ejb.SessionBean
     */
    public void ejbRemove() {
  ds = null;
  processHomeCache = null;
  configurationHomeCache = null;
  ctx = null;
    }

    /**
     * Create an new instance of ProcessDefinitonDirectoryBean.
     * @throws CreateException Throws if the ProcessDefinitionDirectoryBean
     * can not be created.
     */
    public void ejbCreate() throws CreateException {
  init ();
    }

    private void init() {
    }

    /**
     * This operation method delivers a collection of all
     * defined process definitions or an empty collection if no process
     * definition are found.
     *
     * @return collection
     * @ejb.interface-method view-type="remote"
     */
    public Collection processDefinitions() {
        RequestScope scope = RequestLog.enterScope
            (this, "processDefinitions", new Object[] {});
  Collection definitions = new ArrayList();
  Connection con = null;
  PreparedStatement prepStmt = null;
  ResultSet rs = null;
  try {
      try {
    con = ds.getConnection();
    prepStmt = con.prepareStatement
        ("SELECT PACKAGEID, PROCESSID FROM PROCESSDEFINITION ");
    rs = prepStmt.executeQuery();
    while (rs.next()) {
        String pkgId = JDBCUtil.getString(ds, rs, 1);
        String prcId = JDBCUtil.getString(ds, rs, 2);
        try {
      definitions.add (lookupProcessDefinition(pkgId, prcId));
        } catch (InvalidKeyException e) {
      logger.debug ("Couldn't find definition, propably"
              + " deleted since key lookup.");
        }
    }
      } finally {
    JDBCUtil.closeAll (rs, prepStmt, con);
      }
  } catch (SQLException se) {
      throw new EJBException(se);
  } catch (OptionalDataException ode) {
      throw new EJBException(ode);
  } catch (IOException ioe) {
      throw new EJBException(ioe);
  } finally {
      scope.leave(definitions);
  }
  return definitions;
    }

    /**
     * This method delivers the process manager for the given process.
     *
     * @param packageId Id attribute of the process package.
     * @param processId Id attribute of the process.
     * @return the process manager for the process type.
     * @throws InvalidKeyException if no process definition with
     * the given ids exists.
     * @ejb.interface-method view-type="remote"
     */
    public ProcessMgr processMgr (String packageId, String processId)
    throws InvalidKeyException {
        RequestScope scope = RequestLog.enterScope
            (this, "processMgr", new Object[] { packageId, processId });
        ProcessMgr res = null;
  try {
      ProcessDefinition procDef
    = lookupProcessDefinition (packageId, processId);
      res = new ProcessMgrStub
    (packageId, processId, procDef.mgrName(), null,
     (ProcessDefinitionDirectoryHome)ctx.getEJBHome(),
     processHome());
  } catch (ResourceNotAvailableException re) {
      throw new EJBException (re);
  } catch (InvalidKeyException ikex) {
            ctx.setRollbackOnly();
      throw ikex;
  } finally {
      scope.leave (res);
  }
  return res;
    }

    /**
     * This method checks if a process definiton with the given ids
     * exists in the database.
     *
     * @param packageId Id attribute of the process package.
     * @param processId Id attribute of the process.
     * @return <code>true</code> if a process definition with the given
     * <code>id</code> exists, otherwise <code>false</code>.
     * @ejb.interface-method view-type="remote"
     */
    public boolean processDefinitionExists
  (String packageId, String processId) {
        RequestScope scope = RequestLog.enterScope
            (this, "processDefinitionExists",
             new Object[] { packageId, processId });
        boolean res = false;
  Connection con = null;
  PreparedStatement prepStmt = null;
  ResultSet rs = null;
  try {
      try {
    con = ds.getConnection();
    prepStmt = con.prepareStatement
        ("SELECT DBID FROM PROCESSDEFINITION "
         + "WHERE PACKAGEID = ? AND PROCESSID = ?");
    prepStmt.setString(1, packageId);
    prepStmt.setString(2, processId);
    rs = prepStmt.executeQuery();
    if(rs.next()) {
        res = true;
        return res;
    }
      } finally {
    JDBCUtil.closeAll (rs, prepStmt, con);
      }
  } catch (SQLException se) {
      throw new EJBException(se);
  } finally {
      scope.leave (new Boolean (res));
  }
  return res;
    }
   
    /**
     * This operation method import new process definitions from an
     * XPDL description.
     *
     * @param processDefinitions document describing the process definitions.
     * @return list of prioritized message
     * {@link de.danet.an.workflow.api.PrioritizedMessage
     * <code>PrioritizedMessage</code>}
     * @throws ImportException if the input is not a correct.
     * @ejb.interface-method view-type="remote"
     */
    public List importProcessDefinitions(String processDefinitions)
  throws ImportException {
        RequestScope scope = RequestLog.enterScope
            (this, "importProcessDefinitions",
             new Object[] { processDefinitions });
        List res = null;
        try {
            res = importProcessDefinitions
            (new InputSource(new StringReader(processDefinitions)));
        } finally {
            scope.leave (res);
        }
        return res;
    }

    /**
     * This operation method import new process definitions from an
     * XPDL description.
     *
     * @param processDefinitions byte array resulting from an
     * InputStream that describes the process definitions.
     * @return list of prioritized message
     * {@link de.danet.an.workflow.api.PrioritizedMessage
     * <code>PrioritizedMessage</code>}
     * @throws ImportException if the input is not a correct.
     * @ejb.interface-method view-type="remote"
     */
    public List importProcessDefinitions(byte[] processDefinitions)
  throws ImportException {
        RequestScope scope = RequestLog.enterScope
            (this, "importProcessDefinitions",
             new Object[] { processDefinitions });
        List res = null;
        try {
            res = importProcessDefinitions
      (new InputSource(new ByteArrayInputStream(processDefinitions)));
        } finally {
            scope.leave (res);
        }
        return res;
    }

    /**
     * This operation method import new process definitions from an
     * XPDL description.
     *
     * @param inSrc the input that describes the package as XPDL.
     * @return list of prioritized message
     * {@link de.danet.an.workflow.api.PrioritizedMessage
     * <code>PrioritizedMessage</code>}
     * @throws ImportException if the input is not a correct.
     */
    private List importProcessDefinitions(InputSource inSrc)
  throws ImportException {
  try {
      List l = AbstractProcessDefinitionDirectory
          .parseProcessDefinitions(inSrc);
      if (l.size() > 1) {
    // Remove all defintions with the imported package id
    String pkgId = ((ProcessDefinition)l.get(1)).packageId();
    List tbr = new ArrayList ();
    try {
        Connection con = null;
        PreparedStatement prepStmt = null;
        ResultSet rs = null;
        try {
      con = ds.getConnection();
      prepStmt = con.prepareStatement
          ("SELECT PROCESSID FROM PROCESSDEFINITION "
           + "WHERE PACKAGEID = ?");
      prepStmt.setString(1, pkgId);
      rs = prepStmt.executeQuery();
      while (rs.next()) {
          tbr.add (rs.getString(1));
      }
      rs.close ();
      rs = null;
      prepStmt.close();
      prepStmt = null;
                        for (Iterator ti = tbr.iterator(); ti.hasNext();) {
                            try {
                                removeProcessDefinition
                                    (pkgId, (String)ti.next());
                            } catch (InvalidKeyException e) {
                            }
                        }
                        prepStmt = con.prepareStatement
                            ("SELECT DBID FROM XPDLARCHIVE "
                             + "WHERE PACKAGEID = ?");
                        prepStmt.setString(1, pkgId);
                        rs = prepStmt.executeQuery();
                        while (rs.next()) {
                            removeXpdlIfOrphaned(rs.getLong(1));
                        }
                        Iterator it = l.subList(1, l.size()).iterator();
      while (it.hasNext()) {
          ProcessDefinition pd = (ProcessDefinition)it.next();
          insertProcessDefinition(ds, con, pd);
      }
        } finally {
      JDBCUtil.closeAll (rs, prepStmt, con);
        }
    } catch (SQLException e) {
        throw new EJBException (e);
    }
      }
      return (List)l.get(0);
        } catch (ImportException pex) {
            ctx.setRollbackOnly();
            throw pex;
        }
    }

    /**
     * Insert the process definition into the database.
     * @throws SQLException, if another process with the
     * same id already exist in the database.
     */
    private void insertProcessDefinition
  (DataSource ds, Connection con, ProcessDefinition processDefiniton)
  throws SQLException {
  UniversalPrepStmt prepStmt = null;
  try {
      // Insert new XPDL in archive
      long xpdlKey = EJBUtil.newPrimaryKey ("xpdlarchive");
      prepStmt = new UniversalPrepStmt
          (ds, con, "INSERT INTO XPDLARCHIVE ("
           + "DBID, PACKAGEID, XPDL) VALUES (?, ?, ?)");
      int offset = 1;
      prepStmt.setLong (offset++, xpdlKey);
      prepStmt.setString(offset++, processDefiniton.packageId());
      prepStmt.setLargeString(offset++, processDefiniton.toXPDL());
      prepStmt.executeUpdate();
      prepStmt.close();
      prepStmt = null;
      // Insert new process definition (with reference to XPDL in
      // archive). The XPDL column in processdefinition is deprecated.
      prepStmt = new UniversalPrepStmt
    (ds, con, "INSERT INTO PROCESSDEFINITION ("
     + "DBID, PACKAGEID, PROCESSID, XPDLREF, ENABLED) "
     + "VALUES (?, ?, ?, ?, 'T')");
      offset = 1;
      long procDefKey = EJBUtil.newPrimaryKey ("processdefinition");
      prepStmt.setLong (offset++, procDefKey);
      prepStmt.setString(offset++, processDefiniton.packageId());
      prepStmt.setString(offset++, processDefiniton.processId());
      prepStmt.setLong(offset++, xpdlKey);
      prepStmt.executeUpdate();
      cacheDefinition
          (new ProcessDefinitionInfo
           (procDefKey, new Long(xpdlKey), processDefiniton, true));
  } catch (ResourceNotAvailableException e) {
      throw new SQLException ("Cannot get primary key" + e.getMessage());
  } finally {
      JDBCUtil.closeAll (null, prepStmt, null);
  }
    }

    /**
     * This operation method removes a process definition with the
     * given ids from the database. If called for a definition that
     * does not exist, it does nothing.
     *
     * @param packageId Id attribute of the process package.
     * @param processId Id attribute of the process.
     * @throws InvalidKeyException if packageId or processId are
     * (formally) invalid ids.
     * @ejb.interface-method view-type="remote"
     */
    public void removeProcessDefinition(String packageId, String processId)
  throws InvalidKeyException {
        RequestScope scope = RequestLog.enterScope
            (this, "removeProcessDefinition",
             new Object[] { packageId, processId });
        try {
            prepareForRemoval(packageId, processId);
            PreparedStatement prepStmt = null;
            Connection con = null;
            ResultSet rs = null;
            try {
                String processType = packageId + "/" + processId;
                uncacheDefinition (processType);
                con = ds.getConnection();
                prepStmt = con.prepareStatement
                    ("SELECT XPDLREF FROM PROCESSDEFINITION "
                     + "WHERE PACKAGEID = ? AND PROCESSID = ?");
                prepStmt.setString(1, packageId);
                prepStmt.setString(2, processId);
                rs = prepStmt.executeQuery();
                if(!rs.next()) {
                    return;
                }
                long xpdlId = rs.getLong(1);
                rs.close();
                rs = null;
                prepStmt.close();
                prepStmt = null;
                // remove process definition from the database
                prepStmt = con.prepareStatement
                    ("DELETE FROM PROCESSDEFINITION "
                     + "WHERE PACKAGEID = ? AND PROCESSID = ?");
                prepStmt.setString(1, packageId);
                prepStmt.setString(2, processId);
                prepStmt.executeUpdate();
                removeXpdlIfOrphaned(xpdlId);
            } finally {
                JDBCUtil.closeAll (rs, prepStmt, con);
      }
  } catch (SQLException e) {
      throw new EJBException(e);
        } finally {
            scope.leave ();
        }
    }

    /**
     * Prepares old (i.e. without xpdl in xpdlarchive) process definitons
     * and processes for removal.
     *
     * @param packageId the package id
     * @param processId the process id
     */
    private void prepareForRemoval(String packageId, String processId) {
        try {
            UniversalPrepStmt prepStmt = null;
            Connection con = null;
            ResultSet rs = null;
            try {
                con = ds.getConnection();
                prepStmt = new UniversalPrepStmt
                    (ds, con, "SELECT XPDL FROM PROCESSDEFINITION "
                     + "WHERE PACKAGEID = ? AND PROCESSID = ?");
                prepStmt.setString(1, packageId);
                prepStmt.setString(2, processId);
                rs = prepStmt.executeQuery();
                if(!rs.next()) {
                    return;
                }
                String xpdl = JDBCUtil.getString(ds, rs, 1);
                if (xpdl == null) {
                    return;
                }
                rs.close();
                rs = null;
                prepStmt.close();
                prepStmt = null;
                // Add to archive
                long xpdlKey = EJBUtil.newPrimaryKey ("xpdlarchive");
                prepStmt = new UniversalPrepStmt
                    (ds, con, "INSERT INTO XPDLARCHIVE ("
                     + "DBID, PACKAGEID, XPDL) VALUES (?, ?, ?)");
                int offset = 1;
                prepStmt.setLong (offset++, xpdlKey);
                prepStmt.setString(offset++, packageId);
                prepStmt.setLargeString(offset++, xpdl);
                prepStmt.executeUpdate();
                prepStmt.close();
                prepStmt = null;
                // Update processes
                prepStmt = new UniversalPrepStmt
                    (ds, con, "UPDATE PROCESS SET XPDLREF = ? "
                     + "WHERE PACKAGEID = ? AND PROCESSID = ? "
                     + "AND XPDLREF IS NULL AND XPDL IS NULL");
                offset = 1;
                prepStmt.setLong (offset++, xpdlKey);
                prepStmt.setString(offset++, packageId);
                prepStmt.setString(offset++, processId);
                prepStmt.executeUpdate();
            } finally {
                JDBCUtil.closeAll (rs, prepStmt, con);
            }
        } catch (SQLException e) {
            throw new EJBException(e);
        } catch (IOException e) {
            throw new EJBException(e);
        }
    }

    /**
     * This method delivers the process definition for the
     * given ids. If no process definition with the ids exist, it
     * throws an <code>IllegalArgumentException</code>.
     *
     * @param packageId the package id
     * @param processId the process definition id
     * @return the found ProcessDefinition object
     * @throws InvalidKeyException if no process definition with
     * the given ids exists.
     * @ejb.interface-method view-type="remote"
     */
    public ProcessDefinition lookupProcessDefinition
  (String packageId, String processId) throws InvalidKeyException {
        RequestScope scope = RequestLog.enterScope
            (this, "lookupProcessDefinition",
             new Object[] { packageId, processId });
        ProcessDefinition res = null;
        try {
            res = lookupProcessDefinitionInfo
                (packageId, processId).processDefinition;
        } finally {
            scope.leave (res);
        }
        return res;
    }

    /**
     * Result type for {@link #lookupProcessDefinitionInfo
     * <code>lookupProcessDefinitionInfo</code>.
     */
    public class ProcessDefinitionInfo implements Serializable {
        /** The db id used to identify the current entry */
        public long dbid;
        /** The process definition id in the archive */
        public Long archivedXpdlId;
  /** The process definition. */
  public ProcessDefinition processDefinition;
  /** The enabled state. */
  public boolean enabled;

  /**
   * Create a new object with attributes initialized to the
   * given values.
   * @param dbid the id of the process definition in the database
   * @param ax the id of the archived xpdl
   * @param pd the process definition
   * @param enabState the enabled state
   */
  public ProcessDefinitionInfo
      (long dbid, Long ax, ProcessDefinition pd, boolean enabState) {
      this.dbid = dbid;
      archivedXpdlId = ax;
      processDefinition = pd;
      enabled = enabState;
  }
    }

    /**
     * This method delivers the process definition for the
     * given ids. If no process definition with the ids exist, it
     * throws an <code>IllegalArgumentException</code>.
     *
     * @param packageId the package id
     * @param processId the process definition id
     * @return the found ProcessDefinition object
     * @throws InvalidKeyException if no process definition with
     * the given ids exists.
     * @ejb.interface-method view-type="local"
     * @ejb.transaction type="RequiresNew"
     */
    public ProcessDefinitionInfo lookupProcessDefinitionInfo
  (String packageId, String processId) throws InvalidKeyException {
        RequestScope scope = RequestLog.enterScope
            (this, "lookupProcessDefinitionInfo",
             new Object[] { packageId, processId });
  ProcessDefinitionInfo processDefinitionInfo = null;
  try {
       Connection con = null;
      PreparedStatement prepStmt = null;
      ResultSet rs = null;
      try {
    String processType = packageId + "/" + processId;
    con = ds.getConnection();
    prepStmt = con.prepareStatement
        ("SELECT DBID, ENABLED, XPDLREF FROM PROCESSDEFINITION "
         + "WHERE PACKAGEID = ? AND PROCESSID = ?");
    prepStmt.setString(1, packageId);
    prepStmt.setString(2, processId);
    rs = prepStmt.executeQuery();
    if(!rs.next()) {
        // cleanup cache as a side effect
        uncacheDefinition (processType);
        throw new InvalidKeyException
      ("No process with packageId/processId = "+ processType);
    }
    long dbid = rs.getLong(1);
    boolean enabled = (rs.getString(2).charAt(0) == 'T');
                Long xpdlRef = JDBCUtil.getLong(rs, 3);
                synchronized (processDefinitionInfoCache) {
                    processDefinitionInfo = (ProcessDefinitionInfo)
                        processDefinitionInfoCache.get(new Long(dbid));
                    if (processDefinitionInfo != null) {
                        if (processDefinitionInfo.dbid != dbid) {
                            uncacheDefinition(processType);
                            processDefinitionInfo = null;
                        }
                    }
                }
    if (processDefinitionInfo != null) {
        processDefinitionInfo.enabled = enabled;
        if (logger.isDebugEnabled ()) {
      logger.debug
          ("found (" + processDefinitionInfo
           .processDefinition.packageId()
           + "/" + processDefinitionInfo
           .processDefinition.processId() + ") "
           + "in cache");
        }
        return processDefinitionInfo;
    }
                rs.close();
                rs = null;
                prepStmt.close();
                prepStmt = null;
                String xpdl = null;
                // For backward compatibility allow xpdlref to be null
                if (xpdlRef != null) {
                    prepStmt = new UniversalPrepStmt
                        (con, "SELECT XPDL FROM XPDLARCHIVE WHERE DBID = ?");
                    prepStmt.setLong(1, xpdlRef.longValue());
                    rs = prepStmt.executeQuery();
                    if (rs.next()) {
                        xpdl = JDBCUtil.getString(ds, rs, 1);
                    }
                } else {
                    prepStmt = new UniversalPrepStmt
                        (con, "SELECT XPDL FROM PROCESSDEFINITION "
                         + "WHERE DBID = ?");
                    prepStmt.setLong(1, dbid);
                    rs = prepStmt.executeQuery();
                    if (rs.next()) {
                        xpdl = JDBCUtil.getString(ds, rs, 1);
                    }
                }
    processDefinitionInfo = new ProcessDefinitionInfo
        (dbid, xpdlRef,
         new DefaultProcessDefinition (xpdl), enabled);
    cacheDefinition(processDefinitionInfo);
    return processDefinitionInfo;
      } finally {
    JDBCUtil.closeAll (rs, prepStmt, con);
      }
  } catch (SQLException se) {
      throw new EJBException(se);
  } catch (IOException ioe) {
      throw new EJBException(ioe);
  } catch (ImportException pe) {
      throw new EJBException(pe);
  } finally {
      scope.leave (processDefinitionInfo);
  }
    }

    /**
     * This method delivers the XPDL from the archive with the
     * given id.
     *
     * @param id the id
     * @return the xpdl
     * @ejb.interface-method view-type="local"
     */
    public ProcessDefinition lookupArchivedProcessDefinition (long id) {
        try {
            ProcessDefinition processDefinition = null;
            processDefinition = (ProcessDefinition)
                archivedProcessDefinitionCache.get(new Long(id));
            if (processDefinition != null) {
                return processDefinition;
            }
            PreparedStatement prepStmt = null;
            Connection con = null;
            ResultSet rs = null;
            try {
                con = ds.getConnection();
                prepStmt = new UniversalPrepStmt
                    (ds, con, "SELECT XPDL FROM XPDLARCHIVE WHERE DBID = ?");
                prepStmt.setLong(1, id);
                rs = prepStmt.executeQuery();
                if (!rs.next()) {
                    throw new IllegalArgumentException();
                }
                processDefinition = new DefaultProcessDefinition
                     (JDBCUtil.getString(ds, rs, 1));
                // Add new entry
                archivedProcessDefinitionCache
                    .put (new Long(id), processDefinition);
                return processDefinition;
            } finally {
                JDBCUtil.closeAll (rs, prepStmt, con);
            }
        } catch (ImportException e) {
            throw new EJBException(e);
        } catch (SQLException e) {
            throw new EJBException(e);
        } catch (IOException e) {
            throw new EJBException(e);
        }
    }

    /**
     * This method removes a XPDL from the archive if it is no longer
     * referenced.
     *
     * @param id the id
     * @ejb.interface-method view-type="local"
     */
    public void removeXpdlIfOrphaned (long id) {
        try {
            PreparedStatement prepStmt = null;
            Connection con = null;
            ResultSet rs = null;
            try {
                con = ds.getConnection();
                prepStmt = new UniversalPrepStmt
                    (ds, con, "SELECT XPDLREF "
                     + "FROM PROCESSDEFINITION WHERE XPDLREF = ?");
                prepStmt.setLong(1, id);
                prepStmt.setMaxRows(1);
                rs = prepStmt.executeQuery();
                if (rs.next()) {
                    return;
                }
                rs.close();
                rs = null;
                prepStmt.close();
                prepStmt = null;
                prepStmt = new UniversalPrepStmt
                    (ds, con, "SELECT XPDLREF "
                     + "FROM PROCESS WHERE XPDLREF = ?");
                prepStmt.setLong(1, id);
                prepStmt.setMaxRows(1);
                rs = prepStmt.executeQuery();
                if (rs.next()) {
                    return;
                }
                rs.close();
                rs = null;
                prepStmt.close();
                prepStmt = null;
                prepStmt = new UniversalPrepStmt
                    (ds, con, "DELETE FROM XPDLARCHIVE WHERE DBID = ?");
                prepStmt.setLong(1, id);
                prepStmt.executeUpdate();
                archivedProcessDefinitionCache.remove (new Long(id));
            } finally {
                JDBCUtil.closeAll (rs, prepStmt, con);
            }
        } catch (SQLException e) {
            throw new EJBException(e);
        }
    }

    /**
     * This operation method returns true if the process definition
     * with the given ids is enabled.
     *
     * @param packageId Id attribute of the process package.
     * @param processId Id attribute of the process.
     * @return <code>true</code> if the process definition is enabled.
     * @throws InvalidKeyException if no process definition with
     * the given ids exists.
     * @ejb.interface-method view-type="remote"
     */
    public boolean isEnabled(String packageId, String processId)
  throws InvalidKeyException {
        RequestScope scope = RequestLog.enterScope
            (this, "isEnabled", new Object[] { packageId, processId });
  boolean enabled = false;
  Connection con = null;
  ResultSet rs = null;
  PreparedStatement prepStmt = null;
  try {
      con = ds.getConnection();
      prepStmt = con.prepareStatement
    ("SELECT ENABLED FROM PROCESSDEFINITION "
    + "WHERE PACKAGEID = ? AND PROCESSID = ?");
      prepStmt.setString(1, packageId);
      prepStmt.setString(2, processId);
      rs = prepStmt.executeQuery();
      if(!rs.next()) {
    ctx.setRollbackOnly();
                throw new InvalidKeyException
        ("No process with packageId/processId = "
         + packageId + "/" + processId);
      }
      if (rs.getString(1).charAt(0) == 'T') {
    enabled = true;
      }
      return enabled;
  } catch (SQLException se) {
      throw new EJBException(se);
  } finally {
      try {
    JDBCUtil.closeAll (rs, prepStmt, con);
      } catch (SQLException e) {
    throw new EJBException(e);
      }
      scope.leave(new Boolean (enabled));
  }
    }

    /**
     * This operation method set the process definition with the given
     * ids as enabled or disabled.
     *
     * @param packageId Id attribute of the process package.
     * @param processId Id attribute of the process.
     * @param enabled enable the process definition or not.
     * @throws InvalidKeyException if no process definition with
     * the given ids exists.
     * @ejb.interface-method view-type="remote"
     */
    public void setEnabled
  (String packageId, String processId, boolean enabled)
  throws InvalidKeyException {
        RequestScope scope = RequestLog.enterScope
            (this, "setEnabled",
             new Object[] { packageId, processId, new Boolean (enabled) });
  Connection con = null;
  PreparedStatement prepStmt = null;
  try {
      con = ds.getConnection();
      prepStmt = con.prepareStatement
    ("UPDATE PROCESSDEFINITION SET ENABLED = ? "
     + "WHERE PACKAGEID = ? AND PROCESSID = ?");
      if (enabled) {
    prepStmt.setString(1, "T");
      } else {
    prepStmt.setString(1, "F");
      }
      prepStmt.setString(2, packageId);
      prepStmt.setString(3, processId);
      int rowCount = prepStmt.executeUpdate();
      if (rowCount == 0) {
                ctx.setRollbackOnly();
    throw new InvalidKeyException
        ("No process with packageId/processId = "
         + packageId + "/" + processId);
      }

  } catch (SQLException se) {
      throw new EJBException(se);
  } finally {
      try {
    JDBCUtil.closeAll (null, prepStmt, con);
      } catch (SQLException e) {
    throw new EJBException(e);
      }
      scope.leave();
  }
    } 

    /**
     * Create a process of the given type with the given requester.
     *
     * @param packageId Id attribute of the process package.
     * @param processId Id attribute of the process.
     * @param requester the requester.
     * @return the new process.
     * @throws NotEnabledException if processes of this type may not be
     * created.
     * @throws InvalidRequesterException if the requester is not valid.
     * @throws RequesterRequiredException if no requester is passed (i.e.
     * parameter is <code>null</code>.
     * @throws InvalidKeyException if no process definition with
     * the given ids exists.
     * @ejb.interface-method view-type="remote"
     */
    public de.danet.an.workflow.omgcore.WfProcess createProcess
        (String packageId, String processId, WfRequester requester)
        throws NotEnabledException, InvalidRequesterException,
               RequesterRequiredException, InvalidKeyException {
            return ((ExtProcessLocal)createProcessLocal
             (packageId, processId, requester)).toProcess();
    }

    /**
     * Create a process of the given type with the given requester.
     *
     * @param packageId Id attribute of the process package.
     * @param processId Id attribute of the process.
     * @param requester the requester.
     * @return the new process.
     * @throws NotEnabledException if processes of this type may not be
     * created.
     * @throws InvalidRequesterException if the requester is not valid.
     * @throws RequesterRequiredException if no requester is passed (i.e.
     * parameter is <code>null</code>.
     * @throws InvalidKeyException if no process definition with
     * the given ids exists.
     * @ejb.interface-method view-type="remote"
     */
    public WfProcessLocal createProcessLocal
  (String packageId, String processId, WfRequester requester)
  throws NotEnabledException, InvalidRequesterException,
         RequesterRequiredException, InvalidKeyException {
  try {
      if (requester == null) {
    ctx.setRollbackOnly();
                throw new RequesterRequiredException();
      }
      ProcessDefinitionInfo pdi
    = ((ProcessDefinitionDirectoryLocal)ctx.getEJBLocalObject())
    .lookupProcessDefinitionInfo (packageId, processId);
      if (!pdi.enabled) {
    ctx.setRollbackOnly();
                throw new NotEnabledException("Process definition disabled.");
      }
      return processLocalHome().create
          (pdi.archivedXpdlId, pdi.processDefinition, requester);
  } catch (CreateException ce) {
      throw new EJBException(ce);
  }
 
    }

    /**
     * @param processDefinitionInfo
     */
    private void cacheDefinition(ProcessDefinitionInfo processDefinitionInfo) {
        synchronized (processDefinitionInfoCache) {
            // Remove any existing entry
            String processType
                = processDefinitionInfo.processDefinition.packageId()
                + "/" + processDefinitionInfo.processDefinition.processId();
            Long curRef = (Long)processDefinitionDBIds.get(processType);
            if (curRef != null) {
                processDefinitionInfoCache.remove(curRef);
            }
            // Add new entry
            processDefinitionInfoCache.put
                (new Long(processDefinitionInfo.dbid), processDefinitionInfo);
            processDefinitionDBIds.put
                (processType, new Long(processDefinitionInfo.dbid));
            if (logger.isDebugEnabled()) {
                logger.debug
                    ("put (" + processDefinitionInfo
                     .processDefinition.packageId()
                     + "/" + processDefinitionInfo
                     .processDefinition.processId() + ") "
                     + "in cache");
            }
        }
    }

    /**
     * Remove given process definition from cache.
     */
    private void uncacheDefinition (String key) {
  synchronized (processDefinitionInfoCache) {
      Long ck = (Long)processDefinitionDBIds.get (key);
      if (ck != null) {
    processDefinitionDBIds.remove (key);
    processDefinitionInfoCache.remove(ck);
    if (logger.isDebugEnabled ()) {
        logger.debug("removed ("+key+") from cache");
    }
      }
  }
    }
}
TOP

Related Classes of de.danet.an.workflow.ejbs.admin.ProcessDefinitionDirectoryEJB$ProcessDefinitionInfo

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.