/** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.aurora.common.application; import java.util.List; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import org.apache.aurora.common.base.Command; import org.apache.aurora.common.base.ExceptionalCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A shutdown action controller. It executes actions in the reverse order they were registered, and * logs a warning for every shutdown action that fails, but doesn't prevent completion of subsequent * actions or the normal completion of the {@code execute()} method. * * @author Attila Szegedi */ public interface ShutdownRegistry { /** * Adds an action to the shutdown registry. * * @param action Action to register. * @param <E> Exception type thrown by the action. * @param <T> Type of command. */ <E extends Exception, T extends ExceptionalCommand<E>> void addAction(T action); /** * Implementation of a shutdown registry. */ public static class ShutdownRegistryImpl implements ShutdownRegistry, Command { private static final Logger LOG = LoggerFactory.getLogger(ShutdownRegistryImpl.class); private final List<ExceptionalCommand<? extends Exception>> actions = Lists.newLinkedList(); private boolean completed = false; /** * Registers an action to execute during {@link #execute()}. It is an error to call this method * after calling {@link #execute()}. * * @param action the action to add to the list of actions to execute during execution */ @Override public synchronized <E extends Exception, T extends ExceptionalCommand<E>> void addAction( T action) { Preconditions.checkState(!completed); actions.add(action); } /** * Executes an application shutdown stage by executing all registered actions. This method can * be called multiple times but will only execute the registered actions the first time. * * This sends output to System.out because logging is unreliable during JVM shutdown, which * this class may be used for. */ @Override public synchronized void execute() { if (!completed) { LOG.info("Executing {} shutdown commands.", actions.size()); completed = true; try { for (ExceptionalCommand<? extends Exception> action : Lists.reverse(actions)) { // Part of our contract is ensuring each shutdown action executes so we must catch all // exceptions. // SUPPRESS CHECKSTYLE:OFF IllegalCatch try { action.execute(); } catch (Exception e) { LOG.warn("Shutdown action failed.", e); } // SUPPRESS CHECKSTYLE:ON IllegalCatch } } finally { actions.clear(); } } else { LOG.info("Action controller has already completed, subsequent calls ignored."); } } } }