2
0

Shutdown.java 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /*
  2. * This program is free software: you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation, either version 3 of the License, or (at your option) any later
  5. * version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU General Public License along with
  13. * this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package com.l2jserver.communityserver;
  16. import java.util.logging.Logger;
  17. import com.l2jserver.communityserver.L2DatabaseFactory;
  18. import com.l2jserver.communityserver.model.L2Player;
  19. /**
  20. *
  21. * This class provides the functions for shutting down and restarting the server
  22. * It closes all open clientconnections and saves all data.
  23. *
  24. * @version $Revision: 1.2.4.5 $ $Date: 2005/03/27 15:29:09 $
  25. */
  26. public class Shutdown extends Thread
  27. {
  28. private static Logger _log = Logger.getLogger(Shutdown.class.getName());
  29. private static Shutdown _instance;
  30. private static Shutdown _counterInstance = null;
  31. private int _secondsShut;
  32. private int _shutdownMode;
  33. public static final int SIGTERM = 0;
  34. public static final int GM_SHUTDOWN = 1;
  35. public static final int GM_RESTART = 2;
  36. public static final int ABORT = 3;
  37. private static final String[] MODE_TEXT =
  38. {
  39. "SIGTERM", "shutting down", "restarting", "aborting"
  40. };
  41. /**
  42. * This function starts a shutdown countdown from Telnet (Copied from Function startShutdown())
  43. *
  44. * @param ip IP Which Issued shutdown command
  45. * @param seconds seconds untill shutdown
  46. * @param restart true if the server will restart after shutdown
  47. */
  48. public void startTelnetShutdown(String IP, int seconds, boolean restart)
  49. {
  50. _log.warning("IP: " + IP + " issued shutdown command. " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds!");
  51. //_an.announceToAll("Server is " + _modeText[shutdownMode] + " in "+seconds+ " seconds!");
  52. if (restart)
  53. {
  54. _shutdownMode = GM_RESTART;
  55. }
  56. else
  57. {
  58. _shutdownMode = GM_SHUTDOWN;
  59. }
  60. if (_shutdownMode > 0)
  61. {
  62. switch (seconds)
  63. {
  64. case 540:
  65. case 480:
  66. case 420:
  67. case 360:
  68. case 300:
  69. case 240:
  70. case 180:
  71. case 120:
  72. case 60:
  73. case 30:
  74. case 10:
  75. case 5:
  76. case 4:
  77. case 3:
  78. case 2:
  79. case 1:
  80. break;
  81. default:
  82. }
  83. }
  84. if (_counterInstance != null)
  85. {
  86. _counterInstance._abort();
  87. }
  88. _counterInstance = new Shutdown(seconds, restart);
  89. _counterInstance.start();
  90. }
  91. /**
  92. * This function aborts a running countdown
  93. *
  94. * @param IP IP Which Issued shutdown command
  95. */
  96. public void telnetAbort(String IP)
  97. {
  98. _log.warning("IP: " + IP + " issued shutdown ABORT. " + MODE_TEXT[_shutdownMode] + " has been stopped!");
  99. if (_counterInstance != null)
  100. {
  101. _counterInstance._abort();
  102. }
  103. }
  104. /**
  105. * Default constucter is only used internal to create the shutdown-hook instance
  106. *
  107. */
  108. public Shutdown()
  109. {
  110. _secondsShut = -1;
  111. _shutdownMode = SIGTERM;
  112. }
  113. /**
  114. * This creates a countdown instance of Shutdown.
  115. *
  116. * @param seconds how many seconds until shutdown
  117. * @param restart true is the server shall restart after shutdown
  118. *
  119. */
  120. public Shutdown(int seconds, boolean restart)
  121. {
  122. if (seconds < 0)
  123. {
  124. seconds = 0;
  125. }
  126. _secondsShut = seconds;
  127. if (restart)
  128. {
  129. _shutdownMode = GM_RESTART;
  130. }
  131. else
  132. {
  133. _shutdownMode = GM_SHUTDOWN;
  134. }
  135. }
  136. /**
  137. * get the shutdown-hook instance
  138. * the shutdown-hook instance is created by the first call of this function,
  139. * but it has to be registrered externaly.
  140. *
  141. * @return instance of Shutdown, to be used as shutdown hook
  142. */
  143. public static Shutdown getInstance()
  144. {
  145. if (_instance == null)
  146. {
  147. _instance = new Shutdown();
  148. }
  149. return _instance;
  150. }
  151. /**
  152. * this function is called, when a new thread starts
  153. *
  154. * if this thread is the thread of getInstance, then this is the shutdown hook
  155. * and we save all data and disconnect all clients.
  156. *
  157. * after this thread ends, the server will completely exit
  158. *
  159. * if this is not the thread of getInstance, then this is a countdown thread.
  160. * we start the countdown, and when we finished it, and it was not aborted,
  161. * we tell the shutdown-hook why we call exit, and then call exit
  162. *
  163. * when the exit status of the server is 1, startServer.sh / startServer.bat
  164. * will restart the server.
  165. *
  166. */
  167. @Override
  168. public void run()
  169. {
  170. if (this == _instance)
  171. {
  172. // last byebye, save all data and quit this server
  173. // logging doesnt work here :(
  174. saveData();
  175. try
  176. {
  177. // LoginServerThread.getInstance().interrupt();
  178. }
  179. catch (Throwable t)
  180. {
  181. // ignore
  182. }
  183. // saveData sends messages to exit players, so sgutdown selector after it
  184. try
  185. {
  186. //GameServer.gameServer.getSelectorThread().shutdown();
  187. //GameServer.gameServer.getSelectorThread().setDaemon(true);
  188. }
  189. catch (Throwable t)
  190. {
  191. // ignore
  192. }
  193. // commit data, last chance
  194. try
  195. {
  196. L2DatabaseFactory.getInstance().shutdown();
  197. }
  198. catch (Throwable t)
  199. {
  200. }
  201. // server will quit, when this function ends.
  202. if (_instance._shutdownMode == GM_RESTART)
  203. {
  204. Runtime.getRuntime().halt(2);
  205. }
  206. else
  207. {
  208. Runtime.getRuntime().halt(0);
  209. }
  210. }
  211. else
  212. {
  213. // gm shutdown: send warnings and then call exit to start shutdown sequence
  214. countdown();
  215. // last point where logging is operational :(
  216. _log.warning("GM shutdown countdown is over. " + MODE_TEXT[_shutdownMode] + " NOW!");
  217. switch (_shutdownMode)
  218. {
  219. case GM_SHUTDOWN:
  220. _instance.setMode(GM_SHUTDOWN);
  221. System.exit(0);
  222. break;
  223. case GM_RESTART:
  224. _instance.setMode(GM_RESTART);
  225. System.exit(2);
  226. break;
  227. }
  228. }
  229. }
  230. /**
  231. * This functions starts a shutdown countdown
  232. *
  233. * @param activeChar GM who issued the shutdown command
  234. * @param seconds seconds until shutdown
  235. * @param restart true if the server will restart after shutdown
  236. */
  237. public void startShutdown(L2Player activeChar, int seconds, boolean restart)
  238. {
  239. _log.warning("GM: " + activeChar.getName() + "(" + activeChar.getObjId() + ") issued shutdown command. " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds!");
  240. if (restart)
  241. {
  242. _shutdownMode = GM_RESTART;
  243. }
  244. else
  245. {
  246. _shutdownMode = GM_SHUTDOWN;
  247. }
  248. if (_shutdownMode > 0)
  249. {
  250. switch (seconds)
  251. {
  252. case 540:
  253. case 480:
  254. case 420:
  255. case 360:
  256. case 300:
  257. case 240:
  258. case 180:
  259. case 120:
  260. case 60:
  261. case 30:
  262. case 10:
  263. case 5:
  264. case 4:
  265. case 3:
  266. case 2:
  267. case 1:
  268. break;
  269. default:
  270. }
  271. }
  272. if (_counterInstance != null)
  273. {
  274. _counterInstance.abort(activeChar);
  275. }
  276. // the main instance should only run for shutdown hook, so we start a new instance
  277. _counterInstance = new Shutdown(seconds, restart);
  278. _counterInstance.start();
  279. }
  280. /**
  281. * This function aborts a running countdown
  282. *
  283. * @param activeChar GM who issued the abort command
  284. */
  285. public void abort(L2Player activeChar)
  286. {
  287. _log.warning("GM: " + activeChar.getName() + "(" + activeChar.getObjId() + ") issued shutdown ABORT. " + MODE_TEXT[_shutdownMode] + " has been stopped!");
  288. if (_counterInstance != null)
  289. {
  290. _counterInstance._abort();
  291. }
  292. }
  293. /**
  294. * set the shutdown mode
  295. * @param mode what mode shall be set
  296. */
  297. private void setMode(int mode)
  298. {
  299. _shutdownMode = mode;
  300. }
  301. /**
  302. * set shutdown mode to ABORT
  303. *
  304. */
  305. private void _abort()
  306. {
  307. _shutdownMode = ABORT;
  308. }
  309. /**
  310. * this counts the countdown and reports it to all players
  311. * countdown is aborted if mode changes to ABORT
  312. */
  313. private void countdown()
  314. {
  315. try
  316. {
  317. while (_secondsShut > 0)
  318. {
  319. _secondsShut--;
  320. int delay = 1000; //milliseconds
  321. Thread.sleep(delay);
  322. if (_shutdownMode == ABORT)
  323. break;
  324. }
  325. }
  326. catch (InterruptedException e)
  327. {
  328. //this will never happen
  329. }
  330. }
  331. /**
  332. * this sends a last byebye, disconnects all players and saves data
  333. *
  334. */
  335. private void saveData()
  336. {
  337. switch (_shutdownMode)
  338. {
  339. case SIGTERM:
  340. System.err.println("SIGTERM received. Shutting down NOW!");
  341. break;
  342. case GM_SHUTDOWN:
  343. System.err.println("GM shutdown received. Shutting down NOW!");
  344. break;
  345. case GM_RESTART:
  346. System.err.println("GM restart received. Restarting NOW!");
  347. break;
  348. }
  349. try
  350. {
  351. int delay = 5000;
  352. Thread.sleep(delay);
  353. }
  354. catch (InterruptedException e)
  355. {
  356. //never happens :p
  357. }
  358. }
  359. }