/*
* 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.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.batch.operations.JobOperator;
import javax.batch.runtime.BatchRuntime;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jberet.schedule._private.ScheduleExecutorLogger;
import org.jberet.schedule._private.ScheduleExecutorMessages;
/**
* This class defines operations for a job scheduler, and also static methods
* for obtaining an instance of {@code JobScheduler}.
*
* @see JobSchedule
* @see JobScheduleConfig
* @since 1.3.0
*/
public abstract class JobScheduler {
/**
* Convenience empty string array.
*/
public static final String[] EMPTY_STRING_ARRAY = new String[0];
/**
* Feature name for persistent job schedule.
*/
public static final String PERSISTENT = "persistent";
/**
* Feature name for calendar-based job schedule.
*/
public static final String CALENDAR = "calendar";
/**
* Time unit for job schedule.
*/
protected static final TimeUnit timeUnit = TimeUnit.MINUTES;
/**
* Lookup name for EJB-Timer-based job scheduler implementation.
*/
protected static final String TIMER_SCHEDULER_LOOKUP = "java:module/TimerSchedulerBean";
/**
* Lookup name for the managed scheduled executor service.
*/
protected static final String MANAGED_EXECUTOR_SERVICE_LOOKUP =
"java:comp/DefaultManagedScheduledExecutorService";
/**
* The job scheduler instance.
*/
private static volatile JobScheduler jobScheduler;
/**
* Default no-arg constructor.
*/
protected JobScheduler() {
}
/**
* Gets the job scheduler without passing any parameters.
* @return job scheduler
*
* @see #getJobScheduler(Class, ConcurrentMap, String)
*/
public static JobScheduler getJobScheduler() {
return getJobScheduler(null, null, null);
}
/**
* Gets the job scheduler, specifying scheduler type,
* {@code ConcurrentMap<String, JobSchedule>} for storing all job schedules, and the lookup
* name of {@code ManagedScheduledExecutorService} resource.
*
* This method determines which type of job scheduler to use as follows:
* <ul>
* <li>If {@code schedulerType} is specified, instantiate the specified type.
* <li>Else if lookup of {@value #TIMER_SCHEDULER_LOOKUP} succeeds,
* use the job scheduler obtained from that lookup.
* <li>Else if lookup of the resource specified by {@code managedScheduledExecutorServiceLookup} succeeds,
* creates {@link ExecutorSchedulerImpl} with the executor from that lookup.
* <li>Else if lookup of {@value #MANAGED_EXECUTOR_SERVICE_LOOKUP} succeeds,
* creates {@link ExecutorSchedulerImpl} with the executor from that lookup.
* <li>Else creates {@link ExecutorSchedulerImpl}.
* </ul>
*
* @param schedulerType fully-qualified class name of job scheduler type
* @param schedules {@code ConcurrentMap<String, JobSchedule>} for storing all job schedules
* @param managedScheduledExecutorServiceLookup lookup name of {@code ManagedScheduledExecutorService} resource
* @return job scheduler
*/
public static JobScheduler getJobScheduler(final Class<? extends JobScheduler> schedulerType,
final ConcurrentMap<String, JobSchedule> schedules,
final String managedScheduledExecutorServiceLookup) {
JobScheduler result = jobScheduler;
if (result == null) {
synchronized (JobScheduler.class) {
result = jobScheduler;
if (result == null) {
if (schedulerType != null) {
try {
jobScheduler = result = schedulerType.newInstance();
ScheduleExecutorLogger.LOGGER.createdJobScheduler(result, null);
} catch (final Throwable e) {
throw ScheduleExecutorMessages.MESSAGES.failToCreateJobScheduler(e, schedulerType);
}
} else {
InitialContext ic = null;
try {
ic = new InitialContext();
try {
jobScheduler = result = (JobScheduler) ic.lookup(TIMER_SCHEDULER_LOOKUP);
ScheduleExecutorLogger.LOGGER.createdJobScheduler(result, TIMER_SCHEDULER_LOOKUP);
} catch (final NamingException e) {
ScheduledExecutorService mexe;
if (managedScheduledExecutorServiceLookup != null) {
try {
mexe = (ScheduledExecutorService) ic.lookup(managedScheduledExecutorServiceLookup);
jobScheduler = result = new ExecutorSchedulerImpl(schedules, mexe);
ScheduleExecutorLogger.LOGGER.createdJobScheduler(result, managedScheduledExecutorServiceLookup);
} catch (final NamingException e2) {
ScheduleExecutorLogger.LOGGER.failToLookupManagedScheduledExecutorService(managedScheduledExecutorServiceLookup);
mexe = (ScheduledExecutorService) ic.lookup(MANAGED_EXECUTOR_SERVICE_LOOKUP);
jobScheduler = result = new ExecutorSchedulerImpl(schedules, mexe);
ScheduleExecutorLogger.LOGGER.createdJobScheduler(result, MANAGED_EXECUTOR_SERVICE_LOOKUP);
}
} else {
mexe = (ScheduledExecutorService) ic.lookup(MANAGED_EXECUTOR_SERVICE_LOOKUP);
jobScheduler = result = new ExecutorSchedulerImpl(schedules, mexe);
ScheduleExecutorLogger.LOGGER.createdJobScheduler(result, MANAGED_EXECUTOR_SERVICE_LOOKUP);
}
}
} catch (final NamingException e) {
jobScheduler = result = new ExecutorSchedulerImpl(schedules);
ScheduleExecutorLogger.LOGGER.createdJobScheduler(result, null);
} finally {
if (ic != null) {
try {
ic.close();
} catch (final NamingException e2) {
//ignore it
}
}
}
}
}
}
}
return result;
}
/**
* Convenience method for getting {@code JobOperator}.
* @return {@code JobOperator}
*/
public static JobOperator getJobOperator() {
return Holder.jobOperator;
}
private static class Holder {
private static final JobOperator jobOperator = BatchRuntime.getJobOperator();
}
/**
* Gets the features supported by the current job scheduler.
* @return feature names as a string array
*
* @see #EMPTY_STRING_ARRAY
* @see #PERSISTENT
* @see #CALENDAR
*/
public String[] getFeatures() {
return EMPTY_STRING_ARRAY;
}
/**
* submits a job schedule specified with the job schedule config.
* @param scheduleConfig job schedule config
* @return the job schedule resulting from the submission
*/
public abstract JobSchedule schedule(final JobScheduleConfig scheduleConfig);
/**
* Gets all job schedules known to the scheduler.
* Some implementation may keep the job schedule record after its expiration
* or cancellation, and some may just remove them immediately.
*
* @return all job schedules
*/
public abstract List<JobSchedule> getJobSchedules();
/**
* Cancels a job schedule by its id.
* @param scheduleId the schedule id to cancel
* @return true if cancelled successfully; false otherwise
*/
public abstract boolean cancel(final String scheduleId);
/**
* Gets the job schedule by its id.
* @param scheduleId id of the job schedule to retrieve
* @return the job schedule matching the specified id
*/
public abstract JobSchedule getJobSchedule(final String scheduleId);
}