/* * JBoss, Home of Professional Open Source. * Copyright 2014, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.capedwarf.cron; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.TimeZone; import java.util.concurrent.Callable; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.capedwarf.common.async.WireWrapper; import org.jboss.capedwarf.shared.compatibility.Compatibility; import org.jboss.capedwarf.shared.components.ComponentRegistry; import org.jboss.capedwarf.shared.components.Keys; import org.jboss.capedwarf.shared.config.ApplicationConfiguration; import org.jboss.capedwarf.shared.config.CronEntry; import org.jboss.capedwarf.shared.config.CronXml; import org.jboss.capedwarf.shared.util.Utils; import org.jboss.modules.ModuleIdentifier; import org.jboss.modules.ModuleLoader; import org.quartz.JobBuilder; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.ScheduleBuilder; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; /** * @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a> */ public class CapewarfCron { private static final Logger log = Logger.getLogger(CapewarfCron.class.getName()); private static final Properties DEFAULT_PROPERTIES; static { DEFAULT_PROPERTIES = new Properties(); URL cronProperties = CapewarfCron.class.getResource("cron.properties"); try { try (InputStream stream = cronProperties.openStream()) { DEFAULT_PROPERTIES.load(stream); } } catch (IOException e) { throw Utils.toRuntimeException(e); } } private final ApplicationConfiguration configuration; private final ModuleIdentifier mi; private final ModuleLoader loader; private final Properties properties; private List<JobDetail> details; private List<Trigger> triggers; private Scheduler scheduler; CapewarfCron(ApplicationConfiguration configuration) { this.configuration = configuration; this.mi = Utils.toModule().getIdentifier(); this.loader = ComponentRegistry.getInstance().getComponent(Keys.MODULE_LOADER); this.properties = Compatibility.getInstance().asProperties(); } boolean prepare() { final CronXml cronXml = configuration.getCronXml(); if (cronXml.getEntries().isEmpty()) { final String appId = configuration.getAppEngineWebXml().getApplication(); final String module = configuration.getAppEngineWebXml().getModule(); log.info(String.format("No cron jobs: %s/%s", appId, module)); return false; } details = new ArrayList<>(); triggers = new ArrayList<>(); for (CronEntry entry : cronXml.getEntries()) { final String timezone = entry.getTimezone() != null ? entry.getTimezone() : "GMT"; final String name = String.format("%s@%s#%s", entry.getUrl(), entry.getSchedule(), timezone); Callable<Void> callable = new WireWrapper<>(new CronCallable(entry.getUrl())); JobDataMap map = new JobDataMap(); map.put("callable", callable); JobDetail jobDetail = JobBuilder.newJob(CronJob.class).withIdentity(name).usingJobData(map).build(); ScheduleBuilder scheduleBuilder = new GrocScheduleBuilder(new GoogleGrocAdapter(entry.getSchedule(), TimeZone.getTimeZone(timezone))); Trigger trigger = TriggerBuilder.newTrigger().withIdentity(name).withSchedule(scheduleBuilder).build(); details.add(jobDetail); triggers.add(trigger); } return true; } void start() { try { final ClassLoader cl = loader.loadModule(mi).getClassLoader(); final ClassLoader previous = Utils.setTCCL(cl); try { startInternal(); } finally { Utils.setTCCL(previous); } } catch (Exception e) { throw Utils.toRuntimeException(e); } } private void startInternal() throws Exception { final String appId = configuration.getAppEngineWebXml().getApplication(); final String module = configuration.getAppEngineWebXml().getModule(); final Properties config = new Properties(DEFAULT_PROPERTIES); config.putAll(properties); SchedulerFactory factory = new StdSchedulerFactory(config) { @Override public void initialize(Properties props) throws SchedulerException { props.put(StdSchedulerFactory.PROP_SCHED_INSTANCE_NAME, String.format("%s.%s", appId, module)); props.put("org.quartz.threadPool.module", String.format("%s", mi)); super.initialize(props); } }; scheduler = factory.getScheduler(); scheduler.start(); for (int i = 0; i < details.size(); i++) { scheduler.scheduleJob(details.get(i), triggers.get(i)); } } void destroy() { if (scheduler != null) { try { try { scheduler.clear(); } finally { scheduler.shutdown(); } } catch (SchedulerException e) { log.log(Level.WARNING, String.format("Error during cron destroy."), e); } } } }