Guest User

shutdown

a guest
Jul 25th, 2016
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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 net.sf.l2j.gameserver;
  16.  
  17. import java.util.logging.Level;
  18. import java.util.logging.Logger;
  19.  
  20. import net.sf.l2j.Config;
  21. import net.sf.l2j.L2DatabaseFactory;
  22. import net.sf.l2j.commons.lang.StringUtil;
  23. import net.sf.l2j.gameserver.datatables.BufferTable;
  24. import net.sf.l2j.gameserver.datatables.OfflineTradersTable;
  25. import net.sf.l2j.gameserver.datatables.ServerMemo;
  26. import net.sf.l2j.gameserver.instancemanager.CastleManorManager;
  27. import net.sf.l2j.gameserver.instancemanager.FishingChampionshipManager;
  28. import net.sf.l2j.gameserver.instancemanager.FourSepulchersManager;
  29. import net.sf.l2j.gameserver.instancemanager.GrandBossManager;
  30. import net.sf.l2j.gameserver.instancemanager.RaidBossSpawnManager;
  31. import net.sf.l2j.gameserver.instancemanager.SevenSigns;
  32. import net.sf.l2j.gameserver.instancemanager.SevenSignsFestival;
  33. import net.sf.l2j.gameserver.model.L2World;
  34. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  35. import net.sf.l2j.gameserver.model.entity.Hero;
  36. import net.sf.l2j.gameserver.model.olympiad.Olympiad;
  37. import net.sf.l2j.gameserver.network.L2GameClient;
  38. import net.sf.l2j.gameserver.network.SystemMessageId;
  39. import net.sf.l2j.gameserver.network.gameserverpackets.ServerStatus;
  40. import net.sf.l2j.gameserver.network.serverpackets.ServerClose;
  41. import net.sf.l2j.gameserver.network.serverpackets.SystemMessage;
  42. import net.sf.l2j.gameserver.taskmanager.ItemsOnGroundTaskManager;
  43. import net.sf.l2j.gameserver.taskmanager.MovementTaskManager;
  44. import net.sf.l2j.gameserver.util.Broadcast;
  45.  
  46. /**
  47.  * This class provides functions for shutting down and restarting the server. It closes all client connections and saves data.
  48.  */
  49. public class Shutdown extends Thread
  50. {
  51.     private static Logger _log = Logger.getLogger(Shutdown.class.getName());
  52.     private static Shutdown _counterInstance = null;
  53.    
  54.     private int _secondsShut;
  55.     private int _shutdownMode;
  56.    
  57.     public static final int SIGTERM = 0;
  58.     public static final int GM_SHUTDOWN = 1;
  59.     public static final int GM_RESTART = 2;
  60.     public static final int ABORT = 3;
  61.     private static final String[] MODE_TEXT =
  62.     {
  63.         "SIGTERM",
  64.         "shutting down",
  65.         "restarting",
  66.         "aborting"
  67.     };
  68.    
  69.     private static void SendServerQuit(int seconds)
  70.     {
  71.         SystemMessage sysm = SystemMessage.getSystemMessage(SystemMessageId.THE_SERVER_WILL_BE_COMING_DOWN_IN_S1_SECONDS);
  72.         sysm.addNumber(seconds);
  73.         Broadcast.toAllOnlinePlayers(sysm);
  74.     }
  75.    
  76.     /**
  77.      * Default constucter is only used internal to create the shutdown-hook instance
  78.      */
  79.     protected Shutdown()
  80.     {
  81.         _secondsShut = -1;
  82.         _shutdownMode = SIGTERM;
  83.     }
  84.    
  85.     /**
  86.      * This creates a countdown instance of Shutdown.
  87.      * @param seconds how many seconds until shutdown
  88.      * @param restart true is the server shall restart after shutdown
  89.      */
  90.     public Shutdown(int seconds, boolean restart)
  91.     {
  92.         if (seconds < 0)
  93.             seconds = 0;
  94.        
  95.         _secondsShut = seconds;
  96.        
  97.         if (restart)
  98.             _shutdownMode = GM_RESTART;
  99.         else
  100.             _shutdownMode = GM_SHUTDOWN;
  101.     }
  102.    
  103.     /**
  104.      * this function is called, when a new thread starts if this thread is the thread of getInstance, then this is the shutdown hook and we save all data and disconnect all clients. after this thread ends, the server will completely exit if this is not the thread of getInstance, then this is a
  105.      * countdown thread. we start the countdown, and when we finished it, and it was not aborted, we tell the shutdown-hook why we call exit, and then call exit when the exit status of the server is 1, startServer.sh / startServer.bat will restart the server.
  106.      */
  107.     @Override
  108.     public void run()
  109.     {
  110.         if (this == SingletonHolder._instance)
  111.         {
  112.             StringUtil.printSection("Under " + MODE_TEXT[_shutdownMode] + " process");
  113.            
  114.                        try
  115.                        {
  116.                                if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS)
  117.                                {
  118.                                        OfflineTradersTable.getInstance().storeOffliners();
  119.                                        _log.info("Offline Traders Table: Offline shops stored.");
  120.                                }
  121.                        }
  122.                        catch (Throwable t)
  123.                        {
  124.                                _log.log(Level.WARNING, "Error saving offline shops.", t);
  125.                        }
  126.            
  127.             // disconnect players
  128.             try
  129.             {
  130.                 disconnectAllCharacters();
  131.                 _log.info("All players have been disconnected.");
  132.             }
  133.             catch (Throwable t)
  134.             {
  135.             }
  136.            
  137.             // ensure all services are stopped
  138.             try
  139.             {
  140.                 MovementTaskManager.getInstance().interrupt();
  141.             }
  142.             catch (Throwable t)
  143.             {
  144.             }
  145.            
  146.             // stop all threadpolls
  147.             try
  148.             {
  149.                 ThreadPoolManager.getInstance().shutdown();
  150.             }
  151.             catch (Throwable t)
  152.             {
  153.             }
  154.            
  155.             try
  156.             {
  157.                 LoginServerThread.getInstance().interrupt();
  158.             }
  159.             catch (Throwable t)
  160.             {
  161.             }
  162.            
  163.             // Seven Signs data is now saved along with Festival data.
  164.             if (!SevenSigns.getInstance().isSealValidationPeriod())
  165.                 SevenSignsFestival.getInstance().saveFestivalData(false);
  166.            
  167.             // Save Seven Signs data && status.
  168.             SevenSigns.getInstance().saveSevenSignsData();
  169.             SevenSigns.getInstance().saveSevenSignsStatus();
  170.             _log.info("Seven Signs Festival, general data && status have been saved.");
  171.            
  172.             // Four Sepulchers, stop any working task.
  173.             FourSepulchersManager.getInstance().stop();
  174.            
  175.             // Save raidbosses status
  176.             RaidBossSpawnManager.getInstance().cleanUp();
  177.             _log.info("Raid Bosses data has been saved.");
  178.            
  179.             // Save grandbosses status
  180.             GrandBossManager.getInstance().cleanUp();
  181.             _log.info("World Bosses data has been saved.");
  182.            
  183.             // Save olympiads
  184.             Olympiad.getInstance().saveOlympiadStatus();
  185.             _log.info("Olympiad data has been saved.");
  186.            
  187.             // Save Hero data
  188.             Hero.getInstance().shutdown();
  189.             _log.info("Hero data has been saved.");
  190.            
  191.             // Save all manor data
  192.             CastleManorManager.getInstance().save();
  193.             _log.info("Manors data has been saved.");
  194.            
  195.             // Save Fishing tournament data
  196.             FishingChampionshipManager.getInstance().shutdown();
  197.             _log.info("Fishing Championship data has been saved.");
  198.            
  199.             // Schemes save.
  200.             BufferTable.getInstance().saveSchemes();
  201.             _log.info("BufferTable data has been saved.");
  202.            
  203.             // Save server memos.
  204.             ServerMemo.getInstance().storeMe();
  205.             _log.info("ServerMemo data has been saved.");
  206.            
  207.             // Save items on ground before closing
  208.             ItemsOnGroundTaskManager.getInstance().save();
  209.            
  210.             try
  211.             {
  212.                 Thread.sleep(5000);
  213.             }
  214.             catch (InterruptedException e)
  215.             {
  216.             }
  217.            
  218.             try
  219.             {
  220.                 GameServer.gameServer.getSelectorThread().shutdown();
  221.             }
  222.             catch (Throwable t)
  223.             {
  224.             }
  225.            
  226.             try
  227.             {
  228.                 L2DatabaseFactory.getInstance().shutdown();
  229.             }
  230.             catch (Throwable t)
  231.             {
  232.             }
  233.            
  234.             // server will quit, when this function ends.
  235.             if (SingletonHolder._instance._shutdownMode == GM_RESTART)
  236.                 Runtime.getRuntime().halt(2);
  237.             else
  238.                 Runtime.getRuntime().halt(0);
  239.         }
  240.         else
  241.         {
  242.             // shutdown: send warnings and then call exit to start shutdown sequence
  243.             countdown();
  244.            
  245.             switch (_shutdownMode)
  246.             {
  247.                 case GM_SHUTDOWN:
  248.                     SingletonHolder._instance.setMode(GM_SHUTDOWN);
  249.                     SingletonHolder._instance.run();
  250.                     System.exit(0);
  251.                     break;
  252.                 case GM_RESTART:
  253.                     SingletonHolder._instance.setMode(GM_RESTART);
  254.                     SingletonHolder._instance.run();
  255.                     System.exit(2);
  256.                     break;
  257.             }
  258.         }
  259.     }
  260.    
  261.     /**
  262.      * This functions starts a shutdown countdown.<br>
  263.      * A choice must be made between activeChar or ghostEntity.
  264.      * @param activeChar GM who issued the shutdown command
  265.      * @param ghostEntity the entity who issued the shutdown command
  266.      * @param seconds seconds until shutdown
  267.      * @param restart true if the server will restart after shutdown
  268.      */
  269.     public void startShutdown(L2PcInstance activeChar, String ghostEntity, int seconds, boolean restart)
  270.     {
  271.         if (restart)
  272.             _shutdownMode = GM_RESTART;
  273.         else
  274.             _shutdownMode = GM_SHUTDOWN;
  275.        
  276.         if (activeChar != null)
  277.             _log.warning("GM: " + activeChar.getName() + " (" + activeChar.getObjectId() + ") issued shutdown command, " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds.");
  278.         else if (!ghostEntity.isEmpty())
  279.             _log.warning("Entity: " + ghostEntity + " issued shutdown command, " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds.");
  280.        
  281.         if (_shutdownMode > 0)
  282.         {
  283.             switch (seconds)
  284.             {
  285.                 case 540:
  286.                 case 480:
  287.                 case 420:
  288.                 case 360:
  289.                 case 300:
  290.                 case 240:
  291.                 case 180:
  292.                 case 120:
  293.                 case 60:
  294.                 case 30:
  295.                 case 10:
  296.                 case 5:
  297.                 case 4:
  298.                 case 3:
  299.                 case 2:
  300.                 case 1:
  301.                     break;
  302.                 default:
  303.                     SendServerQuit(seconds);
  304.             }
  305.         }
  306.        
  307.         if (_counterInstance != null)
  308.             _counterInstance._abort();
  309.        
  310.         // the main instance should only run for shutdown hook, so we start a new instance
  311.         _counterInstance = new Shutdown(seconds, restart);
  312.         _counterInstance.start();
  313.     }
  314.    
  315.     /**
  316.      * This function aborts a running countdown
  317.      * @param activeChar GM who issued the abort command
  318.      */
  319.     public void abort(L2PcInstance activeChar)
  320.     {
  321.         if (_counterInstance != null)
  322.         {
  323.             _log.warning("GM: " + activeChar.getName() + " (" + activeChar.getObjectId() + ") issued shutdown abort, " + MODE_TEXT[_shutdownMode] + " has been stopped.");
  324.             _counterInstance._abort();
  325.            
  326.             Broadcast.announceToOnlinePlayers("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation.");
  327.         }
  328.     }
  329.    
  330.     /**
  331.      * set the shutdown mode
  332.      * @param mode what mode shall be set
  333.      */
  334.     private void setMode(int mode)
  335.     {
  336.         _shutdownMode = mode;
  337.     }
  338.    
  339.     /**
  340.      * set shutdown mode to ABORT
  341.      */
  342.     private void _abort()
  343.     {
  344.         _shutdownMode = ABORT;
  345.     }
  346.    
  347.     /**
  348.      * this counts the countdown and reports it to all players countdown is aborted if mode changes to ABORT
  349.      */
  350.     private void countdown()
  351.     {
  352.         try
  353.         {
  354.             while (_secondsShut > 0)
  355.             {
  356.                 switch (_secondsShut)
  357.                 {
  358.                     case 540:
  359.                         SendServerQuit(540);
  360.                         break;
  361.                     case 480:
  362.                         SendServerQuit(480);
  363.                         break;
  364.                     case 420:
  365.                         SendServerQuit(420);
  366.                         break;
  367.                     case 360:
  368.                         SendServerQuit(360);
  369.                         break;
  370.                     case 300:
  371.                         SendServerQuit(300);
  372.                         break;
  373.                     case 240:
  374.                         SendServerQuit(240);
  375.                         break;
  376.                     case 180:
  377.                         SendServerQuit(180);
  378.                         break;
  379.                     case 120:
  380.                         SendServerQuit(120);
  381.                         break;
  382.                     case 60:
  383.                         // avoids new players from logging in
  384.                         LoginServerThread.getInstance().setServerStatus(ServerStatus.STATUS_DOWN);
  385.                         SendServerQuit(60);
  386.                         break;
  387.                     case 30:
  388.                         SendServerQuit(30);
  389.                         break;
  390.                     case 10:
  391.                         SendServerQuit(10);
  392.                         break;
  393.                     case 5:
  394.                         SendServerQuit(5);
  395.                         break;
  396.                     case 4:
  397.                         SendServerQuit(4);
  398.                         break;
  399.                     case 3:
  400.                         SendServerQuit(3);
  401.                         break;
  402.                     case 2:
  403.                         SendServerQuit(2);
  404.                         break;
  405.                     case 1:
  406.                         SendServerQuit(1);
  407.                         break;
  408.                 }
  409.                
  410.                 _secondsShut--;
  411.                
  412.                 Thread.sleep(1000);
  413.                
  414.                 if (_shutdownMode == ABORT)
  415.                 {
  416.                     // Rehabilitate previous server status if shutdown is aborted.
  417.                     if (LoginServerThread.getInstance().getServerStatus() == ServerStatus.STATUS_DOWN)
  418.                         LoginServerThread.getInstance().setServerStatus((Config.SERVER_GMONLY) ? ServerStatus.STATUS_GM_ONLY : ServerStatus.STATUS_AUTO);
  419.                    
  420.                     break;
  421.                 }
  422.             }
  423.         }
  424.         catch (InterruptedException e)
  425.         {
  426.         }
  427.     }
  428.    
  429.     /**
  430.      * Disconnects all clients from the server
  431.      */
  432.     private static void disconnectAllCharacters()
  433.     {
  434.         for (L2PcInstance player : L2World.getInstance().getPlayers())
  435.         {
  436.             try
  437.             {
  438.                 L2GameClient client = player.getClient();
  439.                 if (client != null && !client.isDetached())
  440.                 {
  441.                     client.close(ServerClose.STATIC_PACKET);
  442.                     client.setActiveChar(null);
  443.                     player.setClient(null);
  444.                 }
  445.                 player.deleteMe();
  446.             }
  447.             catch (Throwable t)
  448.             {
  449.                 _log.log(Level.WARNING, "Failed to logout chararacter: " + player, t);
  450.             }
  451.         }
  452.     }
  453.    
  454.     /**
  455.      * get the shutdown-hook instance the shutdown-hook instance is created by the first call of this function, but it has to be registrered externaly.
  456.      * @return instance of Shutdown, to be used as shutdown hook
  457.      */
  458.     public static Shutdown getInstance()
  459.     {
  460.         return SingletonHolder._instance;
  461.     }
  462.    
  463.     private static class SingletonHolder
  464.     {
  465.         protected static final Shutdown _instance = new Shutdown();
  466.     }
  467. }
Advertisement
Add Comment
Please, Sign In to add comment