package org.jbpm.ejb.impl; import java.util.Collection; import java.util.Iterator; import javax.ejb.CreateException; import javax.ejb.EJBException; import javax.ejb.EntityBean; import javax.ejb.EntityContext; import javax.ejb.TimedObject; import javax.ejb.TimerService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jbpm.ejb.LocalCommandService; import org.jbpm.ejb.LocalCommandServiceHome; import org.jbpm.graph.exe.ProcessInstance; import org.jbpm.graph.exe.Token; import org.jbpm.job.Timer; import org.jbpm.scheduler.ejbtimer.ExecuteTimerCommand; import org.jbpm.scheduler.ejbtimer.TimerInfo; import org.jbpm.util.JndiUtil; /** * Entity bean that interacts with the EJB timer service to schedule jBPM {@linkplain Timer * timers}. * * <h3>Environment</h3> * * <p> * The environment entries and resources available for customization are summarized in the table * below. * </p> * * <table border="1"> * <tr> * <th>Name</th> * <th>Type</th> * <th>Description</th> * </tr> * <tr> * <td><code>ejb/LocalCommandServiceBean</code></td> * <td>EJB Reference</td> * <td>Link to the local {@linkplain CommandServiceBean session bean} that executes timers on a * separate jBPM context.</td> * </tr> * </table> * * @author Tom Baeyens * @author Alejandro Guizar * @author Fady Matar */ public abstract class TimerEntityBean implements EntityBean, TimedObject { private EntityContext entityContext; private LocalCommandService commandService; private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(TimerEntityBean.class); public abstract Long getTimerId(); public abstract void setTimerId(Long timerId); public abstract String getName(); public abstract void setName(String name); public abstract Long getTokenId(); public abstract void setTokenId(Long tokenId); public abstract Long getProcessInstanceId(); public abstract void setProcessInstanceId(Long processInstanceId); public abstract String getDiscriminator(); public abstract void setDiscriminator(String discriminator); public void ejbActivate() { try { LocalCommandServiceHome commandServiceHome = (LocalCommandServiceHome) JndiUtil .lookup("java:comp/env/ejb/LocalCommandServiceBean", LocalCommandServiceHome.class); commandService = commandServiceHome.create(); } catch (CreateException e) { throw new EJBException("command service creation failed", e); } } public void ejbPassivate() { commandService = null; } public void ejbRemove() { commandService = null; } public void ejbLoad() { } public void ejbStore() { } public void setEntityContext(EntityContext entityContext) { this.entityContext = entityContext; } public void unsetEntityContext() { entityContext = null; } /** * No ejbCreate operation is allowed, ensuring that this bean is set as read-only. * * @throws CreateException if invoked */ public Long ejbCreate() throws CreateException { throw new CreateException("direct creation of timer entities is prohibited"); } public void ejbPostCreate() { } public void ejbTimeout(javax.ejb.Timer ejbTimer) { boolean debug = log.isDebugEnabled(); if (debug) log.debug(ejbTimer + " fired"); TimerInfo timerInfo = (TimerInfo) ejbTimer.getInfo(); Timer timer = (Timer) commandService.execute(new ExecuteTimerCommand(timerInfo.getTimerId())); // if the timer has repeat if (timer.getRepeat() != null) { // create a new timer if (debug) log.debug("scheduling timer for repeat on " + timer.getDueDate()); createTimer(timer); } } public void createTimer(org.jbpm.job.Timer timer) { TimerService timerService = entityContext.getTimerService(); javax.ejb.Timer ejbTimer = timerService.createTimer(timer.getDueDate(), new TimerInfo(timer)); if (log.isDebugEnabled()) log.debug("created " + ejbTimer); } public void cancelTimer(org.jbpm.job.Timer timer) { long timerId = timer.getId(); Collection timers = entityContext.getTimerService().getTimers(); boolean debug = log.isDebugEnabled(); if (debug) log.debug("retrieved " + timers.size() + " ejb timer(s) by id " + timerId); int count = 0; for (Iterator i = timers.iterator(); i.hasNext();) { javax.ejb.Timer ejbTimer = (javax.ejb.Timer) i.next(); TimerInfo timerInfo = (TimerInfo) ejbTimer.getInfo(); if (timerInfo.getTimerId() == timerId) { ejbTimer.cancel(); ++count; } } if (debug) log.debug("canceled " + count + " ejb timer(s) by id " + timerId); } public void cancelTimersByName(String timerName, Token token) { Collection timers = entityContext.getTimerService().getTimers(); boolean debug = log.isDebugEnabled(); if (debug) { log.debug("retrieved " + timers.size() + " ejb timer(s) by name '" + timerName + "' for " + token); } int count = 0; for (Iterator i = timers.iterator(); i.hasNext();) { javax.ejb.Timer ejbTimer = (javax.ejb.Timer) i.next(); TimerInfo timerInfo = (TimerInfo) ejbTimer.getInfo(); if (timerInfo.matchesName(timerName, token)) { ejbTimer.cancel(); ++count; } } if (debug) { log.debug("canceled " + count + " ejb timer(s) by name '" + timerName + "' for " + token); } } public void cancelTimersForProcessInstance(ProcessInstance processInstance) { Collection timers = entityContext.getTimerService().getTimers(); boolean debug = log.isDebugEnabled(); if (debug) log.debug("retrieved " + timers.size() + " timer(s) for " + processInstance); int count = 0; for (Iterator i = timers.iterator(); i.hasNext();) { javax.ejb.Timer ejbTimer = (javax.ejb.Timer) i.next(); TimerInfo timerInfo = (TimerInfo) ejbTimer.getInfo(); if (timerInfo.matchesProcessInstance(processInstance)) { ejbTimer.cancel(); ++count; } } if (debug) log.debug("canceled " + count + " ejb timer(s) for " + processInstance); } }