package rocks.inspectit.server.util; import java.io.IOException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import javax.annotation.PostConstruct; import org.slf4j.Logger; import org.springframework.stereotype.Component; import rocks.inspectit.server.CMR; import rocks.inspectit.shared.all.spring.logger.Log; /** * This component can shutdown or restart the CMR. * * @author Ivan Senic * */ @Component public class ShutdownService { /** * Code that JVM will exit if restart is required. Note that this code must be max in 8bits size * and changing it requires the change of the CMR startup script. */ private static final int RESTART_EXIT_CODE = 10; /** * Command for restarting the CMR on Windows machines. Note that this command is used only if * the CMR was started as a Windows Service (Procrun). */ private static final String RESTART_CMR_COMMAND = "cmd.exe /c net stop inspectITCMR >NUL & net start inspectITCMR >NUL"; /** * Command for shutting down the CMR on Windows machines. Note that this command is used only if * the CMR was started as a Windows Service (Procrun). */ private static final String SHUTDOWN_CMR_COMMAND = "cmd.exe /c net stop inspectITCMR >NUL"; /** * The logger of this class. */ @Log Logger log; /** * Flag for shutdown initialization. */ private volatile boolean isShutdown = false; /** * Executor service for executing restart/shutdown. We need any thread created to be daemon. * We'll use the executor to asynchronously restart so that the methods can return. */ private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1, new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setDaemon(true); return t; } }); /** * {@inheritDoc} */ public void restart() { synchronized (this) { if (this.isShutdown) { return; } this.isShutdown = true; } doShutdown(true); } /** * {@inheritDoc} */ public void shutdown() { synchronized (this) { if (this.isShutdown) { return; } this.isShutdown = true; } doShutdown(false); } /** * Executes shutdown. If restart is true, there will be a shutdown hook added that will execute * the {@link #restartCommand} so that new CMR is launched. * * @param restart * If new CMR should be launched. */ private void doShutdown(final boolean restart) { if (restart) { log.info("Restart initialized"); } else { log.info("Shutdown initialized"); } Runnable shutdownRunnable = new Runnable() { @Override public void run() { if (restart) { if (CMR.isStartedAsService()) { try { // Not the best solution. // Start the Windows console due to the restart of the CMR Windows // Service through inspectIT UI. Runtime.getRuntime().exec(RESTART_CMR_COMMAND); } catch (IOException e) { log.error(e.getMessage()); } } else { System.exit(RESTART_EXIT_CODE); } } else { if (CMR.isStartedAsService()) { try { // Start the Windows console due to the shutdown of the CMR Windows // Service through inspectIT UI. Runtime.getRuntime().exec(SHUTDOWN_CMR_COMMAND); } catch (IOException e) { log.error(e.getMessage()); } } else { System.exit(0); } } } }; // we execute the shutdown in 500ms so that this method can return executorService.schedule(shutdownRunnable, 500, TimeUnit.MILLISECONDS); } /** * Loads restart command from startup file. * * @throws IOException * If {@link IOException} occurs during reading. */ @PostConstruct public void postConstruct() throws IOException { if (log.isInfoEnabled()) { log.info("|-Shutdown Service active..."); } } }