2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.config.yang.shutdown.impl;
10 import com.google.common.base.Optional;
11 import org.opendaylight.controller.config.shutdown.ShutdownService;
12 import org.osgi.framework.Bundle;
13 import org.osgi.framework.BundleException;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
17 import java.lang.management.ManagementFactory;
18 import java.lang.management.ThreadInfo;
20 public class ShutdownServiceImpl implements ShutdownService, AutoCloseable {
21 private final ShutdownService impl;
22 private final ShutdownRuntimeRegistration registration;
24 public ShutdownServiceImpl(String secret, Bundle systemBundle,
25 ShutdownRuntimeRegistrator rootRuntimeBeanRegistratorWrapper) {
27 throw new IllegalArgumentException("Secret cannot be null");
29 impl = new Impl(secret, systemBundle);
30 registration = rootRuntimeBeanRegistratorWrapper.register(new MXBeanImpl(impl));
34 public void shutdown(String inputSecret, Long maxWaitTime, Optional<String> reason) {
35 impl.shutdown(inputSecret, maxWaitTime, reason);
44 class Impl implements ShutdownService {
45 private static final Logger logger = LoggerFactory.getLogger(Impl.class);
46 private final String secret;
47 private final Bundle systemBundle;
49 Impl(String secret, Bundle systemBundle) {
51 this.systemBundle = systemBundle;
55 public void shutdown(String inputSecret, Long maxWaitTime, Optional<String> reason) {
56 logger.warn("Shutdown issued with secret {} and reason {}", inputSecret, reason);
58 Thread.sleep(1000); // prevent brute force attack
59 } catch (InterruptedException e) {
60 Thread.currentThread().interrupt();
61 logger.warn("Shutdown process interrupted", e);
63 if (this.secret.equals(inputSecret)) {
64 logger.info("Server is shutting down");
67 Thread stopSystemBundleThread = new StopSystemBundleThread(systemBundle);
68 stopSystemBundleThread.start();
69 if (maxWaitTime != null && maxWaitTime > 0) {
70 Thread systemExitThread = new CallSystemExitThread(maxWaitTime);
71 logger.debug("Scheduling {}", systemExitThread);
72 systemExitThread.start();
76 logger.warn("Unauthorized attempt to shut down server");
77 throw new IllegalArgumentException("Invalid secret");
83 class StopSystemBundleThread extends Thread {
84 private static final Logger logger = LoggerFactory.getLogger(StopSystemBundleThread.class);
85 public static final String CONFIG_MANAGER_SYMBOLIC_NAME = "org.opendaylight.controller.config-manager";
86 private final Bundle systemBundle;
88 StopSystemBundleThread(Bundle systemBundle) {
89 super("stop-system-bundle");
90 this.systemBundle = systemBundle;
96 // wait so that JMX response is received
98 // first try to stop config-manager
99 Bundle configManager = findConfigManager();
100 if (configManager != null){
101 logger.debug("Stopping config-manager");
102 configManager.stop();
105 logger.debug("Stopping system bundle");
107 } catch (BundleException e) {
108 logger.warn("Can not stop OSGi server", e);
109 } catch (InterruptedException e) {
110 logger.warn("Shutdown process interrupted", e);
114 private Bundle findConfigManager() {
115 for(Bundle bundle: systemBundle.getBundleContext().getBundles()){
116 if (CONFIG_MANAGER_SYMBOLIC_NAME.equals(bundle.getSymbolicName())) {
125 class CallSystemExitThread extends Thread {
126 private static final Logger logger = LoggerFactory.getLogger(CallSystemExitThread.class);
127 private final long maxWaitTime;
128 CallSystemExitThread(long maxWaitTime) {
129 super("call-system-exit-daemon");
131 if (maxWaitTime <= 0){
132 throw new IllegalArgumentException("Cannot schedule to zero or negative time:" + maxWaitTime);
134 this.maxWaitTime = maxWaitTime;
138 public String toString() {
139 return "CallSystemExitThread{" +
140 "maxWaitTime=" + maxWaitTime +
147 // wait specified time
148 Thread.sleep(maxWaitTime);
149 logger.error("Since some threads are still running, server is going to shut down via System.exit(1) !");
151 ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true);
152 StringBuffer sb = new StringBuffer();
153 for(ThreadInfo info : threads) {
157 logger.warn("Thread dump:{}", sb);
159 } catch (InterruptedException e) {
160 logger.warn("Interrupted, not going to call System.exit(1)");
166 class MXBeanImpl implements ShutdownRuntimeMXBean {
167 private final ShutdownService impl;
169 MXBeanImpl(ShutdownService impl) {
174 public void shutdown(String inputSecret, Long maxWaitTime, String nullableReason) {
175 Optional<String> optionalReason;
176 if (nullableReason == null) {
177 optionalReason = Optional.absent();
179 optionalReason = Optional.of(nullableReason);
181 impl.shutdown(inputSecret, maxWaitTime, optionalReason);