Commit 0db7ec7a authored by Tom Evans's avatar Tom Evans Committed by tevans

OF-668: Improve shutdown from launcher/console

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13654 b35dd754-fafc-0310-a699-88a17e54d16e
parent 35fb14fd
...@@ -20,10 +20,12 @@ ...@@ -20,10 +20,12 @@
package org.jivesoftware.openfire; package org.jivesoftware.openfire;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
...@@ -31,18 +33,17 @@ import java.security.KeyStore; ...@@ -31,18 +33,17 @@ import java.security.KeyStore;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.io.SAXReader; import org.dom4j.io.SAXReader;
import org.eclipse.jetty.util.log.Log;
import org.jivesoftware.database.DbConnectionManager; import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.openfire.admin.AdminManager; import org.jivesoftware.openfire.admin.AdminManager;
import org.jivesoftware.openfire.audit.AuditManager; import org.jivesoftware.openfire.audit.AuditManager;
...@@ -159,6 +160,8 @@ public class XMPPServer { ...@@ -159,6 +160,8 @@ public class XMPPServer {
private NodeID nodeID; private NodeID nodeID;
private static final NodeID DEFAULT_NODE_ID = NodeID.getInstance(new byte[0]); private static final NodeID DEFAULT_NODE_ID = NodeID.getInstance(new byte[0]);
public static final String EXIT = "exit";
/** /**
* All modules loaded by this server * All modules loaded by this server
*/ */
...@@ -364,6 +367,7 @@ public class XMPPServer { ...@@ -364,6 +367,7 @@ public class XMPPServer {
if (isStandAlone()) { if (isStandAlone()) {
Log.info("Registering shutdown hook (standalone mode)"); Log.info("Registering shutdown hook (standalone mode)");
Runtime.getRuntime().addShutdownHook(new ShutdownHookThread()); Runtime.getRuntime().addShutdownHook(new ShutdownHookThread());
TaskEngine.getInstance().schedule(new Terminator(), 1000, 1000);
} }
loader = Thread.currentThread().getContextClassLoader(); loader = Thread.currentThread().getContextClassLoader();
...@@ -883,6 +887,27 @@ public class XMPPServer { ...@@ -883,6 +887,27 @@ public class XMPPServer {
} }
} }
/**
* This timer task is used to monitor the System input stream
* for a "terminate" command from the launcher (or the console).
* This allows for a graceful shutdown when Openfire is started
* via the launcher, especially in Windows.
*/
private class Terminator extends TimerTask {
public void run() {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
try {
if (stdin.ready()) {
if (EXIT.equalsIgnoreCase(stdin.readLine())) {
System.exit(0); // invokes shutdown hook(s)
}
}
} catch (IOException ioe) {
Log.error("Error reading console input", ioe);
}
}
}
/** /**
* <p>A thread to ensure the server shuts down no matter what.</p> * <p>A thread to ensure the server shuts down no matter what.</p>
* <p>Spawned when stop() is called in standalone mode, we wait a few * <p>Spawned when stop() is called in standalone mode, we wait a few
......
...@@ -20,24 +20,55 @@ ...@@ -20,24 +20,55 @@
package org.jivesoftware.openfire.launcher; package org.jivesoftware.openfire.launcher;
import org.jdesktop.jdic.tray.SystemTray; import java.awt.BorderLayout;
import org.jdesktop.jdic.tray.TrayIcon; import java.awt.CardLayout;
import org.w3c.dom.Document; import java.awt.Color;
import org.w3c.dom.Element; import java.awt.Cursor;
import java.awt.Dimension;
import javax.swing.*; import java.awt.Frame;
import javax.swing.text.BadLocationException; import java.awt.Graphics;
import javax.swing.text.SimpleAttributeSet; import java.awt.GridBagConstraints;
import javax.swing.text.StyleConstants; import java.awt.GridBagLayout;
import javax.xml.parsers.DocumentBuilderFactory; import java.awt.Insets;
import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.io.*; import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL; import java.net.URL;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.UIManager;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import org.jdesktop.jdic.tray.SystemTray;
import org.jdesktop.jdic.tray.TrayIcon;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/** /**
* Graphical launcher for Openfire. * Graphical launcher for Openfire.
* *
...@@ -472,8 +503,31 @@ public class Launcher { ...@@ -472,8 +503,31 @@ public class Launcher {
private synchronized void stopApplication() { private synchronized void stopApplication() {
if (openfired != null) { if (openfired != null) {
try { try {
openfired.destroy(); // attempt to perform a graceful shutdown by sending
openfired.waitFor(); // an "exit" command to the process (via stdin)
Writer out = new OutputStreamWriter(
new BufferedOutputStream(openfired.getOutputStream()));
out.write("exit\n");
out.close();
final Thread waiting = Thread.currentThread();
Thread waiter = new Thread() {
public void run() {
try {
// wait for the openfire server to stop
openfired.waitFor();
waiting.interrupt();
}
catch (InterruptedException ie) { /* ignore */ }
}
};
waiter.start();
try {
// wait for a maximum of ten seconds
Thread.sleep(10000);
waiter.interrupt();
openfired.destroy();
}
catch (InterruptedException ie) { /* ignore */ }
cardLayout.show(cardPanel, "main"); cardLayout.show(cardPanel, "main");
} }
catch (Exception e) { catch (Exception e) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment