X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fconfig%2Fshutdown-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fconfig%2Fyang%2Fshutdown%2Fimpl%2FShutdownServiceImpl.java;h=74634dd1577cc781edddc82cfda633d35c6d8879;hp=e5b95c812bd63545289d536d7a12894b6b217c95;hb=1417bcd892b1dc9a4d68c9562d91eee8320de38f;hpb=58fa0dd65634800eccaa1bbe85769835a0e6e071 diff --git a/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownServiceImpl.java b/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownServiceImpl.java index e5b95c812b..74634dd157 100644 --- a/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownServiceImpl.java +++ b/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownServiceImpl.java @@ -8,6 +8,8 @@ package org.opendaylight.controller.config.yang.shutdown.impl; import com.google.common.base.Optional; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; import org.opendaylight.controller.config.shutdown.ShutdownService; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; @@ -18,8 +20,8 @@ public class ShutdownServiceImpl implements ShutdownService, AutoCloseable { private final ShutdownService impl; private final ShutdownRuntimeRegistration registration; - public ShutdownServiceImpl(String secret, Bundle systemBundle, - ShutdownRuntimeRegistrator rootRuntimeBeanRegistratorWrapper) { + public ShutdownServiceImpl(final String secret, final Bundle systemBundle, + final ShutdownRuntimeRegistrator rootRuntimeBeanRegistratorWrapper) { if (secret == null) { throw new IllegalArgumentException("Secret cannot be null"); } @@ -28,8 +30,8 @@ public class ShutdownServiceImpl implements ShutdownService, AutoCloseable { } @Override - public void shutdown(String inputSecret, Optional reason) { - impl.shutdown(inputSecret, reason); + public void shutdown(final String inputSecret, final Long maxWaitTime, final Optional reason) { + impl.shutdown(inputSecret, maxWaitTime, reason); } @Override @@ -39,66 +41,124 @@ public class ShutdownServiceImpl implements ShutdownService, AutoCloseable { } class Impl implements ShutdownService { - private static final Logger logger = LoggerFactory.getLogger(Impl.class); + private static final Logger LOG = LoggerFactory.getLogger(Impl.class); private final String secret; private final Bundle systemBundle; - Impl(String secret, Bundle systemBundle) { + Impl(final String secret, final Bundle systemBundle) { this.secret = secret; this.systemBundle = systemBundle; } @Override - public void shutdown(String inputSecret, Optional reason) { - logger.warn("Shutdown issued with secret {} and reason {}", inputSecret, reason); + public void shutdown(final String inputSecret, final Long maxWaitTime, final Optional reason) { + LOG.warn("Shutdown issued with secret {} and reason {}", inputSecret, reason); try { Thread.sleep(1000); // prevent brute force attack - } catch (InterruptedException e) { + } catch (final InterruptedException e) { Thread.currentThread().interrupt(); - logger.warn("Shutdown process interrupted", e); + LOG.warn("Shutdown process interrupted", e); } if (this.secret.equals(inputSecret)) { - logger.info("Server is shutting down"); - - Thread stopSystemBundle = new Thread() { - @Override - public void run() { - try { - // wait so that JMX response is received - Thread.sleep(1000); - systemBundle.stop(); - } catch (BundleException e) { - logger.warn("Can not stop OSGi server", e); - } catch (InterruptedException e) { - logger.warn("Shutdown process interrupted", e); - } - } - }; - stopSystemBundle.start(); + LOG.info("Server is shutting down"); + // actual work: + Thread stopSystemBundleThread = new StopSystemBundleThread(systemBundle); + stopSystemBundleThread.start(); + if (maxWaitTime != null && maxWaitTime > 0) { + Thread systemExitThread = new CallSystemExitThread(maxWaitTime); + LOG.debug("Scheduling {}", systemExitThread); + systemExitThread.start(); + } + // end } else { - logger.warn("Unauthorized attempt to shut down server"); + LOG.warn("Unauthorized attempt to shut down server"); throw new IllegalArgumentException("Invalid secret"); } } } +class StopSystemBundleThread extends Thread { + private static final Logger LOG = LoggerFactory.getLogger(StopSystemBundleThread.class); + private final Bundle systemBundle; + + StopSystemBundleThread(final Bundle systemBundle) { + super("stop-system-bundle"); + this.systemBundle = systemBundle; + } + + @Override + public void run() { + try { + // wait so that JMX response is received + Thread.sleep(1000); + LOG.debug("Stopping system bundle"); + systemBundle.stop(); + } catch (final BundleException e) { + LOG.warn("Can not stop OSGi server", e); + } catch (final InterruptedException e) { + LOG.warn("Shutdown process interrupted", e); + } + } +} + +class CallSystemExitThread extends Thread { + private static final Logger LOG = LoggerFactory.getLogger(CallSystemExitThread.class); + private final long maxWaitTime; + CallSystemExitThread(final long maxWaitTime) { + super("call-system-exit-daemon"); + setDaemon(true); + if (maxWaitTime <= 0){ + throw new IllegalArgumentException("Cannot schedule to zero or negative time:" + maxWaitTime); + } + this.maxWaitTime = maxWaitTime; + } + + @Override + public String toString() { + return "CallSystemExitThread{" + + "maxWaitTime=" + maxWaitTime + + '}'; + } + + @Override + public void run() { + try { + // wait specified time + Thread.sleep(maxWaitTime); + LOG.error("Since some threads are still running, server is going to shut down via System.exit(1) !"); + // do a thread dump + ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true); + StringBuffer sb = new StringBuffer(); + for(ThreadInfo info : threads) { + sb.append(info); + sb.append("\n"); + } + LOG.warn("Thread dump:{}", sb); + System.exit(1); + } catch (final InterruptedException e) { + LOG.warn("Interrupted, not going to call System.exit(1)"); + } + } +} + + class MXBeanImpl implements ShutdownRuntimeMXBean { private final ShutdownService impl; - MXBeanImpl(ShutdownService impl) { + MXBeanImpl(final ShutdownService impl) { this.impl = impl; } @Override - public void shutdown(String inputSecret, String nullableReason) { + public void shutdown(final String inputSecret, final Long maxWaitTime, final String nullableReason) { Optional optionalReason; if (nullableReason == null) { optionalReason = Optional.absent(); } else { optionalReason = Optional.of(nullableReason); } - impl.shutdown(inputSecret, optionalReason); + impl.shutdown(inputSecret, maxWaitTime, optionalReason); } }