Merge "BUG 1839 - HTTP delete of non existing data"
[controller.git] / opendaylight / config / shutdown-impl / src / main / java / org / opendaylight / controller / config / yang / shutdown / impl / ShutdownServiceImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.config.yang.shutdown.impl;
9
10 import com.google.common.base.Optional;
11 import java.lang.management.ManagementFactory;
12 import java.lang.management.ThreadInfo;
13 import org.opendaylight.controller.config.shutdown.ShutdownService;
14 import org.osgi.framework.Bundle;
15 import org.osgi.framework.BundleException;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 public class ShutdownServiceImpl implements ShutdownService, AutoCloseable {
20     private final ShutdownService impl;
21     private final ShutdownRuntimeRegistration registration;
22
23     public ShutdownServiceImpl(String secret, Bundle systemBundle,
24                                ShutdownRuntimeRegistrator rootRuntimeBeanRegistratorWrapper) {
25         if (secret == null) {
26             throw new IllegalArgumentException("Secret cannot be null");
27         }
28         impl = new Impl(secret, systemBundle);
29         registration = rootRuntimeBeanRegistratorWrapper.register(new MXBeanImpl(impl));
30     }
31
32     @Override
33     public void shutdown(String inputSecret, Long maxWaitTime, Optional<String> reason) {
34         impl.shutdown(inputSecret, maxWaitTime, reason);
35     }
36
37     @Override
38     public void close() {
39         registration.close();
40     }
41 }
42
43 class Impl implements ShutdownService {
44     private static final Logger LOG = LoggerFactory.getLogger(Impl.class);
45     private final String secret;
46     private final Bundle systemBundle;
47
48     Impl(String secret, Bundle systemBundle) {
49         this.secret = secret;
50         this.systemBundle = systemBundle;
51     }
52
53     @Override
54     public void shutdown(String inputSecret, Long maxWaitTime, Optional<String> reason) {
55         LOG.warn("Shutdown issued with secret {} and reason {}", inputSecret, reason);
56         try {
57             Thread.sleep(1000); // prevent brute force attack
58         } catch (InterruptedException e) {
59             Thread.currentThread().interrupt();
60             LOG.warn("Shutdown process interrupted", e);
61         }
62         if (this.secret.equals(inputSecret)) {
63             LOG.info("Server is shutting down");
64
65             // actual work:
66             Thread stopSystemBundleThread = new StopSystemBundleThread(systemBundle);
67             stopSystemBundleThread.start();
68             if (maxWaitTime != null && maxWaitTime > 0) {
69                 Thread systemExitThread = new CallSystemExitThread(maxWaitTime);
70                 LOG.debug("Scheduling {}", systemExitThread);
71                 systemExitThread.start();
72             }
73             // end
74         } else {
75             LOG.warn("Unauthorized attempt to shut down server");
76             throw new IllegalArgumentException("Invalid secret");
77         }
78     }
79
80 }
81
82 class StopSystemBundleThread extends Thread {
83     private static final Logger LOG = LoggerFactory.getLogger(StopSystemBundleThread.class);
84     private final Bundle systemBundle;
85
86     StopSystemBundleThread(Bundle systemBundle) {
87         super("stop-system-bundle");
88         this.systemBundle = systemBundle;
89     }
90
91     @Override
92     public void run() {
93         try {
94             // wait so that JMX response is received
95             Thread.sleep(1000);
96             LOG.debug("Stopping system bundle");
97             systemBundle.stop();
98         } catch (BundleException e) {
99             LOG.warn("Can not stop OSGi server", e);
100         } catch (InterruptedException e) {
101             LOG.warn("Shutdown process interrupted", e);
102         }
103     }
104 }
105
106 class CallSystemExitThread extends Thread {
107     private static final Logger LOG = LoggerFactory.getLogger(CallSystemExitThread.class);
108     private final long maxWaitTime;
109     CallSystemExitThread(long maxWaitTime) {
110         super("call-system-exit-daemon");
111         setDaemon(true);
112         if (maxWaitTime <= 0){
113             throw new IllegalArgumentException("Cannot schedule to zero or negative time:" + maxWaitTime);
114         }
115         this.maxWaitTime = maxWaitTime;
116     }
117
118     @Override
119     public String toString() {
120         return "CallSystemExitThread{" +
121                 "maxWaitTime=" + maxWaitTime +
122                 '}';
123     }
124
125     @Override
126     public void run() {
127         try {
128             // wait specified time
129             Thread.sleep(maxWaitTime);
130             LOG.error("Since some threads are still running, server is going to shut down via System.exit(1) !");
131             // do a thread dump
132             ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true);
133             StringBuffer sb = new StringBuffer();
134             for(ThreadInfo info : threads) {
135                 sb.append(info);
136                 sb.append("\n");
137             }
138             LOG.warn("Thread dump:{}", sb);
139             System.exit(1);
140         } catch (InterruptedException e) {
141             LOG.warn("Interrupted, not going to call System.exit(1)");
142         }
143     }
144 }
145
146
147 class MXBeanImpl implements ShutdownRuntimeMXBean {
148     private final ShutdownService impl;
149
150     MXBeanImpl(ShutdownService impl) {
151         this.impl = impl;
152     }
153
154     @Override
155     public void shutdown(String inputSecret, Long maxWaitTime, String nullableReason) {
156         Optional<String> optionalReason;
157         if (nullableReason == null) {
158             optionalReason = Optional.absent();
159         } else {
160             optionalReason = Optional.of(nullableReason);
161         }
162         impl.shutdown(inputSecret, maxWaitTime, optionalReason);
163     }
164 }