All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zodiac.actuate.context.ApplicationRestartEndpoint Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
package org.zodiac.actuate.context;

import java.io.Closeable;
import java.io.IOException;
import java.util.Collections;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.integration.monitor.IntegrationMBeanExporter;
import org.springframework.util.ClassUtils;
import org.zodiac.commons.constants.SystemPropertiesConstants;

@Endpoint(id = ApplicationRestartEndpoint.ENDPOINT_NAME, enableByDefault = false)
public class ApplicationRestartEndpoint implements ApplicationListener {

    private static Logger logger = LoggerFactory.getLogger(ApplicationRestartEndpoint.class);

    public static final String ENDPOINT_NAME = "app-restart";

    private ConfigurableApplicationContext context;

    private SpringApplication application;

    private String[] args;

    private ApplicationPreparedEvent event;

    private IntegrationShutdown integrationShutdown;

    private long timeout;

    // @ManagedAttribute
    public long getTimeout() {
        return this.timeout;
    }

    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }

    public void setIntegrationMBeanExporter(Object exporter) {
        if (exporter != null) {
            this.integrationShutdown = new IntegrationShutdown(exporter);
        }
    }

    @Override
    public void onApplicationEvent(ApplicationPreparedEvent input) {
        this.event = input;
        if (this.context == null) {
            this.context = this.event.getApplicationContext();
            this.args = this.event.getArgs();
            this.application = this.event.getSpringApplication();
        }
    }

    @WriteOperation
    public Object restart() {
        Thread thread = new Thread(this::safeRestart);
        thread.setDaemon(false);
        thread.start();
        return Collections.singletonMap("message", "Application restarting");
    }

    private Boolean safeRestart() {
        try {
            doRestart();
            logger.info("Application restarted");
            return true;
        } catch (Exception e) {
            if (logger.isDebugEnabled()) {
                logger.info("Could not doRestart", e);
            } else {
                logger.info("Could not doRestart: {}", e.getMessage());
            }
            return false;
        }
    }

    public PauseEndpoint getPauseEndpoint() {
        return new PauseEndpoint();
    }

    public ResumeEndpoint getResumeEndpoint() {
        return new ResumeEndpoint();
    }

    // @ManagedOperation
    public synchronized ConfigurableApplicationContext doRestart() {
        if (this.context != null) {
            if (this.integrationShutdown != null) {
                this.integrationShutdown.stop(this.timeout);
            }
            this.application.setEnvironment(this.context.getEnvironment());
            close();
            // If running in a webapp then the context classloader is probably going to
            // die so we need to revert to a safe place before starting again
            overrideClassLoaderForRestart();
            this.context = this.application.run(this.args);
        }
        return this.context;
    }

    private void close() {
        ApplicationContext context = this.context;
        while (context instanceof Closeable) {
            try {
                ((Closeable)context).close();
            } catch (IOException e) {
                logger.error("Cannot close context: " + context.getId(), e);
            }
            context = context.getParent();
        }
    }

    // @ManagedAttribute
    public boolean isRunning() {
        if (this.context != null) {
            return this.context.isRunning();
        }
        return false;
    }

    // @ManagedOperation
    public synchronized void doPause() {
        if (this.context != null) {
            this.context.stop();
        }
    }

    // @ManagedOperation
    public synchronized void doResume() {
        if (this.context != null) {
            this.context.start();
        }
    }

    private void overrideClassLoaderForRestart() {
        ClassUtils.overrideThreadContextClassLoader(this.application.getClass().getClassLoader());
    }

    /**
     * Pause endpoint configuration.
     */
    @Endpoint(id = PauseEndpoint.ENDPOINT_NAME)
    public class PauseEndpoint {
        public static final String ENDPOINT_NAME = "app-pause";

        @WriteOperation
        public Boolean pause() {
            if (isRunning()) {
                doPause();
                return true;
            }
            return false;
        }

    }

    /**
     * Resume endpoint configuration.
     */
    @Endpoint(id = ResumeEndpoint.ENDPOINT_NAME)
    @ConfigurationProperties(value = SystemPropertiesConstants.Spring.MANAGEMENT_ENDPOINT_RESUME)
    public class ResumeEndpoint {
        public static final String ENDPOINT_NAME = "app-resume";

        @WriteOperation
        public Boolean resume() {
            if (!isRunning()) {
                doResume();
                return true;
            }
            return false;
        }

    }

    private class IntegrationShutdown {

        private IntegrationMBeanExporter exporter;

        IntegrationShutdown(Object exporter) {
            this.exporter = (IntegrationMBeanExporter)exporter;
        }

        public void stop(long timeout) {
            this.exporter.stopActiveComponents(timeout);
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy