/* Copyright (C) 2019 AGNITAS AG (https://www.agnitas.org) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ package com.agnitas.emm.core.commons.spring.hooks; import java.util.Objects; import org.apache.log4j.Logger; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.springframework.beans.factory.annotation.Required; import org.springframework.context.SmartLifecycle; public final class QuartzShutdownHook implements SmartLifecycle { private static final Logger LOGGER = Logger.getLogger(QuartzShutdownHook.class); private boolean isRunning = false; private Scheduler scheduler; @Override public final boolean isRunning() { return this.isRunning; } @Override public final void start() { this.isRunning = true; } @Override public final void stop() { if(LOGGER.isInfoEnabled()) { LOGGER.info("Received container shutdown event"); } try { interruptRunningJobs(); // Shutdown scheduler waiting for jobs to complete this.scheduler.shutdown(true); } catch(final SchedulerException e) { try { // Shutdown scheduler killing jobs this.scheduler.shutdown(false); } catch(final SchedulerException e2) { LOGGER.error("Cannot shutdown Quartz scheduler", e2); } } this.isRunning = false; } @Override public final int getPhase() { return Integer.MAX_VALUE; } @Override public final boolean isAutoStartup() { return true; } @Override public final void stop(final Runnable runnable) { stop(); runnable.run(); } private final void interruptRunningJobs() throws SchedulerException { for(final JobExecutionContext jobExecutionContext : this.scheduler.getCurrentlyExecutingJobs()) { final JobDetail jobDetail = jobExecutionContext.getJobDetail(); if(LOGGER.isInfoEnabled()) { LOGGER.info(String.format( "Interrupting job '%s' of group='%s'.", jobDetail.getKey().getName(), jobDetail.getKey().getGroup())); } scheduler.interrupt(jobDetail.getKey()); } } @Required public final void setScheduler(final Scheduler scheduler) { this.scheduler = Objects.requireNonNull(scheduler, "Scheduler is null"); } }