/* * Copyright (c) 2016 Red Hat, Inc. and/or its affiliates. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Cheng Fang - Initial API and implementation */ package org.jberet.schedule; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import javax.annotation.Resource; import javax.batch.operations.BatchRuntimeException; import javax.ejb.Singleton; import javax.ejb.Timeout; import javax.ejb.Timer; import javax.ejb.TimerConfig; import javax.ejb.TimerService; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import org.jberet.schedule._private.ScheduleExecutorMessages; /** * EJB-Timer-based job scheduler, as a singleton session bean. * This job scheduler class supports single action, repeatable, and * calendar-based job schedule. Persistent job schedule is also supported. * * @since 1.3.0 * @see JobScheduler */ @Singleton() @TransactionAttribute(TransactionAttributeType.SUPPORTS) public class TimerSchedulerBean extends JobScheduler { @Resource private TimerService timerService; @Override public JobSchedule schedule(final JobScheduleConfig scheduleConfig) { final Timer timer; final JobSchedule jobSchedule = new JobSchedule(null, scheduleConfig); if (scheduleConfig.initialDelay > 0) { if (scheduleConfig.interval > 0) { timer = timerService.createIntervalTimer(toMillis(scheduleConfig.initialDelay), toMillis(scheduleConfig.interval), new TimerConfig(jobSchedule, scheduleConfig.isPersistent())); } else if (scheduleConfig.afterDelay > 0) { timer = timerService.createIntervalTimer(toMillis(scheduleConfig.initialDelay), toMillis(scheduleConfig.afterDelay), new TimerConfig(jobSchedule, scheduleConfig.isPersistent())); } else { timer = timerService.createSingleActionTimer(toMillis(scheduleConfig.initialDelay), new TimerConfig(jobSchedule, scheduleConfig.isPersistent())); } } else if (scheduleConfig.scheduleExpression != null) { timer = timerService.createCalendarTimer(scheduleConfig.scheduleExpression, new TimerConfig(jobSchedule, scheduleConfig.isPersistent())); } else { throw ScheduleExecutorMessages.MESSAGES.invalidJobScheduleConfig(scheduleConfig); } jobSchedule.setId(getTimerId(timer)); return jobSchedule; } @Override public List<JobSchedule> getJobSchedules() { final List<JobSchedule> result = new ArrayList<JobSchedule>(); final Collection<Timer> timers = timerService.getTimers(); for (final Timer t : timers) { Serializable info = t.getInfo(); if (info instanceof JobSchedule) { final JobSchedule jobSchedule = (JobSchedule) info; if (jobSchedule.getId() == null) { jobSchedule.setId(getTimerId(t)); } result.add(jobSchedule); } } Collections.sort(result, Collections.<JobSchedule>reverseOrder()); return result; } @Override public boolean cancel(final String scheduleId) { final Collection<Timer> timers = timerService.getTimers(); for (final Timer t : timers) { if (scheduleId.equals(getTimerId(t))) { t.cancel(); return true; } } return false; } @Override public JobSchedule getJobSchedule(final String scheduleId) { final Collection<Timer> timers = timerService.getTimers(); for (final Timer e : timers) { final JobSchedule js = (JobSchedule) e.getInfo(); if (scheduleId.equals(js.getId())) { return js; } } return null; } @Override public String[] getFeatures() { return new String[]{PERSISTENT, CALENDAR}; } /** * Timeout method, which starts the job, or restarts the job execution, and * saves the new job execution id to {@link JobSchedule}. * * @param timer the current timer which has just expired */ @Timeout protected void timeout(final Timer timer) { final JobSchedule jobSchedule = (JobSchedule) timer.getInfo(); final JobScheduleConfig scheduleConfig = jobSchedule.getJobScheduleConfig(); if (scheduleConfig.getJobExecutionId() > 0) { jobSchedule.addJobExecutionIds( JobScheduler.getJobOperator().restart(scheduleConfig.jobExecutionId, scheduleConfig.jobParameters)); } else { jobSchedule.addJobExecutionIds( JobScheduler.getJobOperator().start(scheduleConfig.jobName, scheduleConfig.jobParameters)); } } private static long toMillis(final long t) { return JobScheduler.timeUnit.toMillis(t); } /** * Gets timer id from its string representation, e.g., * <p/> * [id=ea4f6ae1-4a73-4480-bf89-d1f361c7d56a timedObjectId=...] * <p/> * Improve it when appropriate timer API is available. * * @param timer the timer * @return timer id */ private static String getTimerId(final Timer timer) { final String s = timer.toString(); int start = s.indexOf("id="); if (start < 0) { throw new BatchRuntimeException("Failed to get timer id: " + timer); } start += 3; final int end = s.indexOf(' ', start); return end > 0 ? s.substring(start, end) : s.substring(start); } }