/* * RHQ Management Platform * Copyright (C) 2005-2013 Red Hat, Inc. * 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 version 2 of the License. * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package org.rhq.enterprise.server.scheduler; import java.io.InputStream; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.ejb.ConcurrencyManagement; import javax.ejb.ConcurrencyManagementType; import javax.ejb.LocalBean; import javax.ejb.Singleton; import javax.ejb.Startup; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.quartz.Calendar; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.JobListener; import org.quartz.Scheduler; import org.quartz.SchedulerContext; import org.quartz.SchedulerException; import org.quartz.SchedulerListener; import org.quartz.SchedulerMetaData; import org.quartz.Trigger; import org.quartz.TriggerListener; import org.quartz.UnableToInterruptJobException; import org.quartz.impl.StdSchedulerFactory; import org.quartz.spi.JobFactory; import org.jboss.util.StringPropertyReplacer; import org.rhq.core.util.stream.StreamUtil; import org.rhq.enterprise.server.util.JMXUtil; /** * Scheduler MBean service that simply wraps the Quartz scheduler. */ @Singleton @Startup @LocalBean @ConcurrencyManagement(ConcurrencyManagementType.BEAN) @TransactionAttribute(TransactionAttributeType.SUPPORTS) public class SchedulerService implements SchedulerServiceMBean { private static final Log LOG = LogFactory.getLog(SchedulerService.class); private static final String TIMEOUT_PROPERTY_NAME = "rhq.server.operation-timeout"; /** * The configuration properties for Quartz. */ private Properties quartzProperties; // quartz stuff private StdSchedulerFactory schedulerFactory = new StdSchedulerFactory(); private Scheduler scheduler; public Properties getQuartzProperties() { return quartzProperties; } public void setQuartzProperties(Properties quartzProps) throws SchedulerException { if (quartzProps != null) { Properties overrides = new Properties(); for (Map.Entry<Object, Object> entry : quartzProps.entrySet()) { String key = entry.getKey().toString(); String value = entry.getValue().toString(); value = StringPropertyReplacer.replaceProperties(value); overrides.put(key, value); } quartzProps = overrides; } this.quartzProperties = quartzProps; schedulerFactory.initialize(quartzProps); LOG.info("Scheduler has a default operation timeout of [" + getDefaultOperationTimeout() + "] seconds."); } public Integer getDefaultOperationTimeout() { Integer timeout = null; if (this.quartzProperties != null) { String timeoutStr = this.quartzProperties.getProperty(TIMEOUT_PROPERTY_NAME); try { timeout = Integer.valueOf(timeoutStr); } catch (Exception e) { LOG.warn("Invalid operation timeout value specified in the quartz properties: " + TIMEOUT_PROPERTY_NAME + "=" + timeoutStr); } } return timeout; } public void initQuartzScheduler() throws SchedulerException { if (scheduler == null) { // TODO: if we are running in a server cluster, make sure we are using Quartz's clustering capability LOG.debug("Scheduler service will initialize Quartz scheduler now."); scheduler = schedulerFactory.getScheduler(); } else { LOG.debug("Quartz scheduler is initialized and can be started"); } } public void startQuartzScheduler() throws SchedulerException { initQuartzScheduler(); LOG.info("Scheduler service will start Quartz scheduler now - jobs will begin executing."); scheduler.start(); return; } /** * Shuts down the scheduler. * * @throws SchedulerException if failed to shutdown the scheduler */ public synchronized void stop() throws SchedulerException { if ((scheduler != null) && !scheduler.isShutdown()) { LOG.info("Stopping " + scheduler); shutdown(); scheduler = null; } } //--------------------------------------------------------------------- // Scheduler interface methods //--------------------------------------------------------------------- public String getSchedulerName() throws SchedulerException { return scheduler.getSchedulerName(); } public String getSchedulerInstanceId() throws SchedulerException { return scheduler.getSchedulerInstanceId(); } public SchedulerContext getContext() throws SchedulerException { return scheduler.getContext(); } public SchedulerMetaData getMetaData() throws SchedulerException { return scheduler.getMetaData(); } public void start() { LOG.debug("Scheduler Service has started - however, Quartz is not going to be starting yet"); } /** * Quartz 1.5.1 deprecates this method. * * @see org.rhq.enterprise.server.scheduler.SchedulerServiceMBean#pause() * @deprecated */ @Deprecated public void pause() throws SchedulerException { scheduler.pause(); } /** * Quartz 1.5.1 deprecates this method. * * @see org.rhq.enterprise.server.scheduler.SchedulerServiceMBean#isPaused() * @deprecated */ @Deprecated public boolean isPaused() throws SchedulerException { return scheduler.isPaused(); } public void shutdown() throws SchedulerException { if (isStarted()) { scheduler.shutdown(); } } public void shutdown(boolean waitForJobsToComplete) throws SchedulerException { if (isStarted()) { scheduler.shutdown(waitForJobsToComplete); } } public boolean isShutdown() throws SchedulerException { return scheduler.isShutdown(); } public List getCurrentlyExecutingJobs() throws SchedulerException { return scheduler.getCurrentlyExecutingJobs(); } public Date scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException { return scheduler.scheduleJob(jobDetail, trigger); } public Date scheduleJob(Trigger trigger) throws SchedulerException { return scheduler.scheduleJob(trigger); } public void addJob(JobDetail jobDetail, boolean replace) throws SchedulerException { scheduler.addJob(jobDetail, replace); } public boolean deleteJob(String jobName, String groupName) throws SchedulerException { return scheduler.deleteJob(jobName, groupName); } public boolean unscheduleJob(String triggerName, String groupName) throws SchedulerException { return scheduler.unscheduleJob(triggerName, groupName); } public void triggerJob(String jobName, String groupName) throws SchedulerException { scheduler.triggerJob(jobName, groupName); } public void triggerJobWithVolatileTrigger(String jobName, String groupName) throws SchedulerException { scheduler.triggerJobWithVolatileTrigger(jobName, groupName); } public void pauseTrigger(String triggerName, String groupName) throws SchedulerException { scheduler.pauseTrigger(triggerName, groupName); } public void pauseTriggerGroup(String groupName) throws SchedulerException { scheduler.pauseTriggerGroup(groupName); } public void pauseJob(String jobName, String groupName) throws SchedulerException { scheduler.pauseJob(jobName, groupName); } public void pauseJobGroup(String groupName) throws SchedulerException { scheduler.pauseJobGroup(groupName); } public void resumeTrigger(String triggerName, String groupName) throws SchedulerException { scheduler.resumeTrigger(triggerName, groupName); } public void resumeTriggerGroup(String groupName) throws SchedulerException { scheduler.resumeTriggerGroup(groupName); } public void resumeJob(String jobName, String groupName) throws SchedulerException { scheduler.resumeJob(jobName, groupName); } public void resumeJobGroup(String groupName) throws SchedulerException { scheduler.resumeJobGroup(groupName); } public String[] getJobGroupNames() throws SchedulerException { return scheduler.getJobGroupNames(); } public String[] getJobNames(String groupName) throws SchedulerException { return scheduler.getJobNames(groupName); } public Trigger[] getTriggersOfJob(String jobName, String groupName) throws SchedulerException { return scheduler.getTriggersOfJob(jobName, groupName); } public String[] getTriggerGroupNames() throws SchedulerException { return scheduler.getTriggerGroupNames(); } public String[] getTriggerNames(String groupName) throws SchedulerException { return scheduler.getTriggerNames(groupName); } public JobDetail getJobDetail(String jobName, String jobGroup) throws SchedulerException { return scheduler.getJobDetail(jobName, jobGroup); } public Trigger getTrigger(String triggerName, String triggerGroup) throws SchedulerException { return scheduler.getTrigger(triggerName, triggerGroup); } public boolean deleteCalendar(String calName) throws SchedulerException { return scheduler.deleteCalendar(calName); } public Calendar getCalendar(String calName) throws SchedulerException { return scheduler.getCalendar(calName); } public String[] getCalendarNames() throws SchedulerException { return scheduler.getCalendarNames(); } public void addGlobalJobListener(JobListener jobListener) throws SchedulerException { scheduler.addGlobalJobListener(jobListener); } public void addJobListener(JobListener jobListener) throws SchedulerException { scheduler.addJobListener(jobListener); } public boolean removeGlobalJobListener(JobListener jobListener) throws SchedulerException { return scheduler.removeGlobalJobListener(jobListener); } public boolean removeJobListener(String name) throws SchedulerException { return scheduler.removeJobListener(name); } public List getGlobalJobListeners() throws SchedulerException { return scheduler.getGlobalJobListeners(); } public Set getJobListenerNames() throws SchedulerException { return scheduler.getJobListenerNames(); } public JobListener getJobListener(String name) throws SchedulerException { return scheduler.getJobListener(name); } public void addGlobalTriggerListener(TriggerListener triggerListener) throws SchedulerException { scheduler.addGlobalTriggerListener(triggerListener); } public void addTriggerListener(TriggerListener triggerListener) throws SchedulerException { scheduler.addTriggerListener(triggerListener); } public boolean removeGlobalTriggerListener(TriggerListener triggerListener) throws SchedulerException { return scheduler.removeGlobalTriggerListener(triggerListener); } public boolean removeTriggerListener(String name) throws SchedulerException { return scheduler.removeTriggerListener(name); } public List getGlobalTriggerListeners() throws SchedulerException { return scheduler.getGlobalTriggerListeners(); } public Set getTriggerListenerNames() throws SchedulerException { return scheduler.getTriggerListenerNames(); } public TriggerListener getTriggerListener(String name) throws SchedulerException { return scheduler.getTriggerListener(name); } public void addSchedulerListener(SchedulerListener schedulerListener) throws SchedulerException { scheduler.addSchedulerListener(schedulerListener); } public boolean removeSchedulerListener(SchedulerListener schedulerListener) throws SchedulerException { return scheduler.removeSchedulerListener(schedulerListener); } public List getSchedulerListeners() throws SchedulerException { return scheduler.getSchedulerListeners(); } @PostConstruct private void init() { Properties properties = new Properties(); InputStream propertiesStream = getClass().getClassLoader().getResourceAsStream("quartz.properties"); try { properties.load(propertiesStream); setQuartzProperties(properties); } catch (Exception e) { throw new RuntimeException(e); } finally { StreamUtil.safeClose(propertiesStream); } JMXUtil.registerMBean(this, SCHEDULER_MBEAN_NAME); } @PreDestroy private void destroy() { try { stop(); } catch (SchedulerException ignore) { } JMXUtil.unregisterMBeanQuietly(SCHEDULER_MBEAN_NAME); } // Quartz methods that are new in 1.5.1 that were not in 1.0.7 public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException { scheduler.addCalendar(calName, calendar, replace, updateTriggers); } public Set getPausedTriggerGroups() throws SchedulerException { return scheduler.getPausedTriggerGroups(); } public int getTriggerState(String triggerName, String triggerGroup) throws SchedulerException { return scheduler.getTriggerState(triggerName, triggerGroup); } public boolean interrupt(String jobName, String groupName) throws UnableToInterruptJobException { return scheduler.interrupt(jobName, groupName); } public boolean isInStandbyMode() throws SchedulerException { return scheduler.isInStandbyMode(); } public void pauseAll() throws SchedulerException { scheduler.pauseAll(); } public Date rescheduleJob(String triggerName, String groupName, Trigger newTrigger) throws SchedulerException { return scheduler.rescheduleJob(triggerName, groupName, newTrigger); } public void resumeAll() throws SchedulerException { scheduler.resumeAll(); } public void setJobFactory(JobFactory factory) throws SchedulerException { scheduler.setJobFactory(factory); } public void standby() throws SchedulerException { scheduler.standby(); } public void triggerJob(String jobName, String groupName, JobDataMap data) throws SchedulerException { scheduler.triggerJob(jobName, groupName, data); } public void triggerJobWithVolatileTrigger(String jobName, String groupName, JobDataMap data) throws SchedulerException { scheduler.triggerJob(jobName, groupName, data); } public JobListener getGlobalJobListener(String jobName) throws SchedulerException { return scheduler.getGlobalJobListener(jobName); } public TriggerListener getGlobalTriggerListener(String triggerName) throws SchedulerException { return scheduler.getGlobalTriggerListener(triggerName); } public boolean isStarted() throws SchedulerException { return scheduler != null && scheduler.isStarted(); } public boolean removeGlobalJobListener(String jobName) throws SchedulerException { return scheduler.removeGlobalJobListener(jobName); } public boolean removeGlobalTriggerListener(String triggerName) throws SchedulerException { return scheduler.removeGlobalTriggerListener(triggerName); } public void startDelayed(int delay) throws SchedulerException { scheduler.startDelayed(delay); } }