/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jbpm.services.ejb.timer; import java.io.Serializable; import java.util.Date; import java.util.concurrent.Callable; import javax.annotation.Resource; import javax.ejb.ConcurrencyManagement; import javax.ejb.ConcurrencyManagementType; import javax.ejb.Lock; import javax.ejb.LockType; import javax.ejb.NoSuchObjectLocalException; import javax.ejb.Singleton; import javax.ejb.Startup; import javax.ejb.Timeout; import javax.ejb.Timer; import javax.ejb.TimerConfig; import org.drools.core.time.JobHandle; import org.drools.core.time.impl.TimerJobInstance; import org.jbpm.process.core.timer.TimerServiceRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton @Startup @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) @Lock(LockType.READ) public class EJBTimerScheduler { private static final Logger logger = LoggerFactory.getLogger(EJBTimerScheduler.class); private static final Integer OVERDUE_WAIT_TIME = Integer.parseInt(System.getProperty("org.jbpm.overdue.timer.wait", "20000")); @Resource private javax.ejb.TimerService timerService; @SuppressWarnings("unchecked") @Timeout public void executeTimerJob(Timer timer) { EjbTimerJob timerJob = (EjbTimerJob) timer.getInfo(); logger.debug("About to execute timer for job {}", timerJob); TimerJobInstance timerJobInstance = timerJob.getTimerJobInstance(); String timerServiceId = ((EjbGlobalJobHandle)timerJobInstance.getJobHandle()).getDeploymentId(); // handle overdue timers as ejb timer service might start before all deployments are ready long time = 0; while (TimerServiceRegistry.getInstance().get(timerServiceId) == null) { logger.debug("waiting for timer service to be available, elapsed time {} ms", time); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } time += 500; if (time > OVERDUE_WAIT_TIME) { logger.debug("No timer service found after waiting {} ms", time); break; } } try { ((Callable<Void>) timerJobInstance).call(); } catch (Exception e) { logger.warn("Execution of time failed due to {}", e.getMessage(), e); } } public void internalSchedule(TimerJobInstance timerJobInstance) { TimerConfig config = new TimerConfig(new EjbTimerJob(timerJobInstance), true); Date expirationTime = timerJobInstance.getTrigger().hasNextFireTime(); logger.debug("Timer expiration date is {}", expirationTime); if (expirationTime != null) { timerService.createSingleActionTimer(expirationTime, config); logger.debug("Timer scheduled {} on {} scheduler service", timerJobInstance); } else { logger.info("Timer that was to be scheduled has already expired"); } } public boolean removeJob(JobHandle jobHandle) { EjbGlobalJobHandle ejbHandle = (EjbGlobalJobHandle) jobHandle; for (Timer timer : timerService.getTimers()) { try { Serializable info = timer.getInfo(); if (info instanceof EjbTimerJob) { EjbTimerJob job = (EjbTimerJob) info; EjbGlobalJobHandle handle = (EjbGlobalJobHandle) job.getTimerJobInstance().getJobHandle(); if (handle.getUuid().equals(ejbHandle.getUuid())) { logger.debug("Job handle {} does match timer and is going to be canceled", jobHandle); try { timer.cancel(); } catch (Throwable e) { logger.debug("Timer cancel error due to {}", e.getMessage()); return false; } return true; } } } catch (NoSuchObjectLocalException e) { logger.debug("Timer {} has already expired or was canceled ", timer); } } logger.debug("Job handle {} does not match any timer on {} scheduler service", jobHandle, this); return false; } public TimerJobInstance getTimerByName(String jobName) { for (Timer timer : timerService.getTimers()) { try { Serializable info = timer.getInfo(); if (info instanceof EjbTimerJob) { EjbTimerJob job = (EjbTimerJob) info; EjbGlobalJobHandle handle = (EjbGlobalJobHandle) job.getTimerJobInstance().getJobHandle(); if (handle.getUuid().equals(jobName)) { logger.debug("Job {} does match timer and is going to be returned", jobName); return handle.getTimerJobInstance(); } } } catch (NoSuchObjectLocalException e) { logger.debug("Timer info for {} was not found ", timer); } } return null; } }