org.grouplens.grapht.LifecycleManager.java Source code

Java tutorial

Introduction

Here is the source code for org.grouplens.grapht.LifecycleManager.java

Source

/*
 * Grapht, an open source dependency injector.
 * Copyright 2014-2015 various contributors (see CONTRIBUTORS.txt)
 * Copyright 2010-2014 Regents of the University of Minnesota
 *
 * This program 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 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.grouplens.grapht;

import com.google.common.base.Throwables;
import com.google.common.util.concurrent.UncheckedExecutionException;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PreDestroy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Deque;
import java.util.LinkedList;

public class LifecycleManager implements AutoCloseable {
    private static final Logger logger = LoggerFactory.getLogger(LifecycleManager.class);
    private Deque<TeardownAction> actions = new LinkedList<TeardownAction>();

    /**
     * Register a component with the lifecycle manager.  The component will be torn down when the lifecycle manager
     * is closed, using whatever teardown the lifecycle manager institutes.
     *
     * @param instance The component to register.
     */
    public void registerComponent(Object instance) {
        if (instance == null) {
            return;
        }

        if (instance instanceof AutoCloseable) {
            actions.add(new CloseAction((AutoCloseable) instance));
        }
        for (Method m : MethodUtils.getMethodsListWithAnnotation(instance.getClass(), PreDestroy.class)) {
            actions.add(new PreDestroyAction(instance, m));
        }
    }

    /**
     * Close the lifecycle manager, shutting down all components it manages.
     */
    @Override
    public void close() {
        Throwable error = null;
        while (!actions.isEmpty()) {
            TeardownAction action = actions.removeFirst();
            try {
                action.destroy();
            } catch (Throwable th) {
                if (error == null) {
                    error = th;
                } else {
                    error.addSuppressed(th);
                }
            }
        }
        if (error != null) {
            throw Throwables.propagate(error);
        }
    }

    /**
     * Interface for actions that tear down components.
     */
    interface TeardownAction {
        void destroy();
    }

    static class PreDestroyAction implements TeardownAction {
        private final Object instance;
        private final Method method;

        public PreDestroyAction(Object inst, Method m) {
            instance = inst;
            method = m;
        }

        @Override
        public void destroy() {
            try {
                logger.debug("invoking pre-destroy method {} on {}", method, instance);
                method.invoke(instance);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("cannot access " + method, e);
            } catch (InvocationTargetException e) {
                throw new UncheckedExecutionException("error invoking " + method, e);
            }
        }
    }

    static class CloseAction implements TeardownAction {
        private final AutoCloseable instance;

        public CloseAction(AutoCloseable inst) {
            instance = inst;
        }

        @Override
        public void destroy() {
            try {
                logger.debug("closing {}", instance);
                instance.close();
            } catch (Exception e) {
                throw new UncheckedExecutionException("Error destroying " + instance, e);
            }
        }
    }
}