Commit 080fa60a authored by Alex Wenckus's avatar Alex Wenckus Committed by alex

1) Centralized control of http bind and admin console server(s)

2) Added plugin listening/events, for creation and destruction of plugins

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/branches@5747 b35dd754-fafc-0310-a699-88a17e54d16e
parent 7719a088
......@@ -12,7 +12,6 @@
package org.jivesoftware.wildfire;
import org.jivesoftware.wildfire.net.SocketReader;
import org.mortbay.jetty.Server;
import java.io.IOException;
import java.net.Socket;
......@@ -42,6 +41,8 @@ public interface ConnectionManager {
* @param serverPort holds information about the port on which the server is listening for
* connections.
* @param useBlockingMode true means that the server will use a thread per connection.
* @return the created socket reader.
* @throws java.io.IOException when there is an error creating the socket reader.
*/
public SocketReader createSocketReader(Socket socket, boolean isSecure, ServerPort serverPort,
boolean useBlockingMode) throws IOException;
......@@ -209,13 +210,4 @@ public interface ConnectionManager {
* @return the port to use for connection managers.
*/
public int getConnectionManagerListenerPort();
/**
* Returns the jetty server.
*
* @return the jetty server.
*/
Server getHttpServer();
void setHttpServer(Server server);
}
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2006 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.wildfire.net.SSLConfig;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.security.SslSocketConnector;
import javax.net.ssl.SSLServerSocketFactory;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
/**
* Manages the instances of Jetty which provide the admin console funtionality and the http binding
* functionality.
*
* @author Alexander Wenckus
*/
public class HttpServerManager {
private static final HttpServerManager instance = new HttpServerManager();
public static final String ADMIN_CONSOLE_PORT = "adminConsole.port";
public static final String ADMIN_CONOSLE_SECURE_PORT = "adminConsole.securePort";
public static final String HTTP_BIND_PORT = "httpbind.port.plain";
public static final String HTTP_BIND_SECURE_PORT = "httpbind.port.secure";
public static HttpServerManager getInstance() {
return instance;
}
private int port;
private int securePort;
private Server adminServer;
private Server httpBindServer;
private Handler adminConsoleContext;
private Handler httpBindContext;
private HttpServerManager() {
}
public void setAdminConsoleContext(Handler context) {
this.adminConsoleContext = context;
}
public void setHttpBindContext(Handler context) {
this.httpBindContext = context;
}
private void createHttpBindServer(Handler context) {
port = JiveGlobals.getIntProperty(HTTP_BIND_PORT, 9090);
securePort = JiveGlobals.getIntProperty(HTTP_BIND_SECURE_PORT, 9091);
httpBindServer = new Server();
Collection<Connector> connectors = createAdminConsoleConnectors(port, securePort);
if(connectors.size() == 0) {
httpBindServer = null;
return;
}
for (Connector connector : connectors) {
httpBindServer.addConnector(connector);
}
httpBindServer.addHandler(context);
}
private void createAdminConsoleServer(Handler context) {
int port = JiveGlobals.getXMLProperty(ADMIN_CONSOLE_PORT, 9090);
int securePort = JiveGlobals.getXMLProperty(ADMIN_CONOSLE_SECURE_PORT, 9091);
boolean loadConnectors = true;
if(httpBindServer != null) {
if(port == this.port && securePort == this.securePort) {
adminServer = httpBindServer;
loadConnectors = false;
}
else if(port == this.port || port == this.securePort
|| securePort == this.port || securePort == this.securePort) {
Log.warn("Http bind ports must be either the same or distinct from admin console" +
" ports.");
httpBindServer = null;
httpBindServer = new Server();
httpBindServer.addHandler(httpBindContext);
adminServer = httpBindServer;
}
else {
adminServer = new Server();
}
}
else {
adminServer = new Server();
}
if (loadConnectors) {
Collection<Connector> connectors = createAdminConsoleConnectors(port, securePort);
if(connectors.size() == 0) {
adminServer = null;
return;
}
for (Connector connector : connectors) {
adminServer.addConnector(connector);
}
}
adminServer.addHandler(context);
}
public void startup() {
if(httpBindContext != null) {
createHttpBindServer(httpBindContext);
}
if(adminConsoleContext != null) {
createAdminConsoleServer(adminConsoleContext);
}
if(httpBindServer != null) {
try {
httpBindServer.start();
}
catch (Exception e) {
Log.error("Could not start http bind server", e);
}
}
if(adminServer != null && adminServer != httpBindServer) {
try {
adminServer.start();
}
catch (Exception e) {
Log.error("Could not start admin conosle server", e);
}
}
}
public void shutdown() {
if(httpBindServer != null) {
try {
httpBindServer.stop();
}
catch (Exception e) {
Log.error("Error stopping http bind server", e);
}
httpBindServer = null;
}
if(adminServer != null && adminServer != httpBindServer) {
try {
adminServer.stop();
}
catch (Exception e) {
Log.error("Error stopping admin console server", e);
}
adminServer = null;
}
}
private Collection<Connector> createAdminConsoleConnectors(int port, int securePort) {
List<Connector> connectorList = new ArrayList<Connector>();
if (port > 0) {
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(port);
connectorList.add(connector);
}
try {
if (securePort > 0) {
SslSocketConnector sslConnector = new JiveSslConnector();
sslConnector.setPort(securePort);
sslConnector.setTrustPassword(SSLConfig.getTrustPassword());
sslConnector.setTruststoreType(SSLConfig.getStoreType());
sslConnector.setTruststore(SSLConfig.getTruststoreLocation());
sslConnector.setNeedClientAuth(false);
sslConnector.setWantClientAuth(false);
sslConnector.setKeyPassword(SSLConfig.getKeyPassword());
sslConnector.setKeystoreType(SSLConfig.getStoreType());
sslConnector.setKeystore(SSLConfig.getKeystoreLocation());
connectorList.add(sslConnector);
}
}
catch (Exception e) {
Log.error(e);
}
return connectorList;
}
private class JiveSslConnector extends SslSocketConnector {
@Override
protected SSLServerSocketFactory createFactory() throws Exception {
return SSLConfig.getServerSocketFactory();
}
}
}
......@@ -22,9 +22,10 @@ import org.jivesoftware.wildfire.audit.AuditManager;
import org.jivesoftware.wildfire.audit.spi.AuditManagerImpl;
import org.jivesoftware.wildfire.commands.AdHocCommandHandler;
import org.jivesoftware.wildfire.component.InternalComponentManager;
import org.jivesoftware.wildfire.container.AdminConsolePlugin;
import org.jivesoftware.wildfire.container.Module;
import org.jivesoftware.wildfire.container.PluginManager;
import org.jivesoftware.wildfire.container.PluginListener;
import org.jivesoftware.wildfire.container.Plugin;
import org.jivesoftware.wildfire.disco.IQDiscoInfoHandler;
import org.jivesoftware.wildfire.disco.IQDiscoItemsHandler;
import org.jivesoftware.wildfire.disco.ServerFeaturesProvider;
......@@ -125,6 +126,7 @@ public class XMPPServer {
"org.jivesoftware.wildfire.starter.ServerStarter";
private static final String WRAPPER_CLASSNAME =
"org.tanukisoftware.wrapper.WrapperManager";
private HttpServerManager httpServerManager;
/**
* Returns a singleton instance of XMPPServer.
......@@ -199,10 +201,8 @@ public class XMPPServer {
* @return true if the given address matches a component service JID.
*/
public boolean matchesComponent(JID jid) {
if (jid != null) {
return !name.equals(jid.getDomain()) && componentManager.getComponent(jid) != null;
}
return false;
return jid != null && !name.equals(jid.getDomain()) &&
componentManager.getComponent(jid) != null;
}
/**
......@@ -297,6 +297,7 @@ public class XMPPServer {
loader = Thread.currentThread().getContextClassLoader();
componentManager = InternalComponentManager.getInstance();
httpServerManager = HttpServerManager.getInstance();
initialized = true;
}
......@@ -329,8 +330,8 @@ public class XMPPServer {
// Otherwise, the page that requested the setup finish won't
// render properly!
Thread.sleep(1000);
((AdminConsolePlugin) pluginManager.getPlugin("admin"))
.restartListeners();
httpServerManager.shutdown();
httpServerManager.startup();
}
}
......@@ -383,6 +384,19 @@ public class XMPPServer {
// Load plugins (when in setup mode only the admin console will be loaded)
File pluginDir = new File(wildfireHome, "plugins");
pluginManager = new PluginManager(pluginDir);
pluginManager.addPluginListener(new PluginListener() {
public void pluginCreated(String pluginName, Plugin plugin) {
if("admin".equals(pluginName)) {
httpServerManager.startup();
}
}
public void pluginDestroyed(String pluginName, Plugin plugin) {
if ("admin".equals(pluginName)) {
httpServerManager.shutdown();
}
}
});
pluginManager.start();
// Log that the server has been started
......
......@@ -13,16 +13,8 @@ package org.jivesoftware.wildfire.container;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.ConnectionManager;
import org.jivesoftware.wildfire.net.SSLConfig;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.security.SslSocketConnector;
import org.jivesoftware.wildfire.HttpServerManager;
import org.mortbay.jetty.webapp.WebAppContext;
import javax.net.ssl.SSLServerSocketFactory;
import java.io.File;
/**
......@@ -33,96 +25,14 @@ import java.io.File;
*/
public class AdminConsolePlugin implements Plugin {
private static Server server = null;
private int port;
private int securePort;
private File pluginDir;
private WebAppContext context = null;
private Connector plainListener = null;
private Connector secureListener = null;
private HttpServerManager serverManager;
/**
* Create a jetty module.
*/
public AdminConsolePlugin() {
ConnectionManager manager = XMPPServer.getInstance().getConnectionManager();
if(manager != null) {
server = manager.getHttpServer();
}
if(server == null) {
server = new Server();
if(manager != null) {
manager.setHttpServer(server);
}
}
}
public void restartListeners() {
try {
String restarting = LocaleUtils.getLocalizedString("admin.console.restarting");
System.out.println(restarting);
Log.info(restarting);
server.stop();
if (plainListener != null) {
server.removeConnector(plainListener);
plainListener = null;
}
if (secureListener != null) {
server.removeConnector(secureListener);
secureListener = null;
}
server.removeHandler(context);
loadListeners();
context = createWebAppContext();
server.addHandler(context);
server.start();
printListenerMessages();
}
catch (Exception e) {
Log.error(e);
}
}
private void loadListeners() throws Exception {
// Configure HTTP socket listener. Setting the interface property to a
// non null value will imply that the Jetty server will only
// accept connect requests to that IP address.
// String interfaceName = JiveGlobals.getXMLProperty("network.interface");
port = JiveGlobals.getXMLProperty("adminConsole.port", 9090);
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(port);
// InetAddrPort address = new InetAddrPort(interfaceName, port);
if (port > 0) {
plainListener = connector;
server.addConnector(connector);
}
try {
securePort = JiveGlobals.getXMLProperty("adminConsole.securePort", 9091);
if (securePort > 0) {
SslSocketConnector secureConnector = new JiveSslConnector();
secureConnector.setPort(securePort);
secureConnector.setTrustPassword(SSLConfig.getTrustPassword());
secureConnector.setTruststoreType(SSLConfig.getStoreType());
secureConnector.setTruststore(SSLConfig.getTruststoreLocation());
secureConnector.setNeedClientAuth(false);
secureConnector.setWantClientAuth(false);
secureConnector.setKeyPassword(SSLConfig.getKeyPassword());
secureConnector.setKeystoreType(SSLConfig.getStoreType());
secureConnector.setKeystore(SSLConfig.getKeystoreLocation());
secureListener = secureConnector;
server.addConnector(secureListener);
}
}
catch (Exception e) {
Log.error(e);
}
serverManager = HttpServerManager.getInstance();
}
public void initializePlugin(PluginManager manager, File pluginDir) {
......@@ -145,30 +55,8 @@ public class AdminConsolePlugin implements Plugin {
if (!logDir.exists()) {
logDir.mkdirs();
}
// File logFile = new File(logDir, "admin-console.log");
// OutputStreamLogSink logSink = new OutputStreamLogSink(logFile.toString());
// logSink.start();
// // In some cases, commons-logging settings can be stomped by other
// // libraries in the classpath. Make sure that hasn't happened before
// // setting configuration.
// Logger log = (Logger) LogFactory.getFactory().getInstance("");
// // Ignore INFO logs unless debugging turned on.
// if (Log.isDebugEnabled() &&
// JiveGlobals.getBooleanProperty("jetty.debug.enabled", true)) {
// log.setVerbose(1);
// }
// else {
// log.setVerbose(-1);
// }
// log.add(logSink);
loadListeners();
context = createWebAppContext();
server.addHandler(context);
server.start();
printListenerMessages();
serverManager.setAdminConsoleContext(createWebAppContext());
}
catch (Exception e) {
System.err.println("Error starting admin console: " + e.getMessage());
......@@ -195,66 +83,5 @@ public class AdminConsolePlugin implements Plugin {
}
public void destroyPlugin() {
plainListener = null;
secureListener = null;
try {
if (server != null) {
server.stop();
server = null;
}
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
/**
* Returns the Jetty instance started by this plugin.
*
* @return the Jetty server instance.
*/
public static Server getJettyServer() {
return server;
}
/**
* Writes out startup messages for the listeners.
*/
private void printListenerMessages() {
String warning = LocaleUtils.getLocalizedString("admin.console.warning");
String listening = LocaleUtils.getLocalizedString("admin.console.listening");
if (plainListener == null && secureListener == null) {
Log.info(warning);
System.out.println(warning);
}
else if (plainListener == null) {
Log.info(listening + " https://" +
XMPPServer.getInstance().getServerInfo().getName() + ":" + securePort);
System.out.println(listening + " https://" +
XMPPServer.getInstance().getServerInfo().getName() + ":" + securePort);
}
else if (secureListener == null) {
Log.info(listening + " http://" +
XMPPServer.getInstance().getServerInfo().getName() + ":" + port);
System.out.println(listening + " http://" +
XMPPServer.getInstance().getServerInfo().getName() + ":" + port);
}
else {
String msg = listening + ":" + System.getProperty("line.separator") +
" http://" + XMPPServer.getInstance().getServerInfo().getName() + ":" +
port + System.getProperty("line.separator") +
" https://" + XMPPServer.getInstance().getServerInfo().getName() + ":" +
securePort;
Log.info(msg);
System.out.println(msg);
}
}
public class JiveSslConnector extends SslSocketConnector {
@Override
protected SSLServerSocketFactory createFactory() throws Exception {
return SSLConfig.getServerSocketFactory();
}
}
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2006 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.container;
/**
* Allows for notifications that a plugin has been either created or destroyed.
*
* @author Alexander Wenckus
*/
public interface PluginListener {
/**
* Called when a plugin has been created.
*
* @param pluginName the name of the created plugin.
* @param plugin the plugin that was created.
*/
void pluginCreated(String pluginName, Plugin plugin);
/**
* Called when a plugin has been destroyed.
*
* @param pluginName the name of the destroyed plugin.
* @param plugin the plugin that was destroyed.
*/
void pluginDestroyed(String pluginName, Plugin plugin);
}
......@@ -58,6 +58,7 @@ public class PluginManager {
private Map<Plugin, String> childPluginMap;
private Set<String> devPlugins;
private PluginMonitor pluginMonitor;
private Set<PluginListener> pluginListeners = new HashSet<PluginListener>();
/**
* Constructs a new plugin manager.
......@@ -457,6 +458,7 @@ public class PluginManager {
AdminConsole.addModel(pluginName, adminElement);
}
firePluginCreatedEvent(pluginDir.getName(), plugin);
}
else {
Log.warn("Plugin " + pluginDir + " could not be loaded: no plugin.xml file found");
......@@ -467,6 +469,14 @@ public class PluginManager {
}
}
private void firePluginCreatedEvent(String name, Plugin plugin) {
Collection<PluginListener> pluginListeners
= new ArrayList<PluginListener>(this.pluginListeners);
for(PluginListener listener : pluginListeners) {
listener.pluginCreated(name, plugin);
}
}
/**
* Unloads a plugin. The {@link Plugin#destroyPlugin()} method will be called and then
* any resources will be released. The name should be the name of the plugin directory
......@@ -537,6 +547,15 @@ public class PluginManager {
unloadPlugin(childPluginMap.get(plugin));
}
childPluginMap.remove(plugin);
firePluginDestroyedEvent(pluginName, plugin);
}
private void firePluginDestroyedEvent(String name, Plugin plugin) {
Collection<PluginListener> pluginListeners
= new ArrayList<PluginListener>(this.pluginListeners);
for (PluginListener listener : pluginListeners) {
listener.pluginDestroyed(name, plugin);
}
}
/**
......@@ -1052,4 +1071,12 @@ public class PluginManager {
return dir.delete();
}
}
public void addPluginListener(PluginListener listener) {
pluginListeners.add(listener);
}
public void removePluginListener(PluginListener listener) {
pluginListeners.remove(listener);
}
}
\ No newline at end of file
......@@ -326,7 +326,7 @@ public class HttpSession extends ClientSession {
}
/**
* A virtual server connection relates to a virtual session which its self can relate to many
* A virtual server connection relates to a http session which its self can relate to many
* http connections.
*/
public static class HttpVirtualConnection extends VirtualConnection {
......
......@@ -18,10 +18,8 @@ import org.jivesoftware.wildfire.*;
import org.jivesoftware.wildfire.http.HttpSessionManager;
import org.jivesoftware.wildfire.http.HttpBindServlet;
import org.jivesoftware.wildfire.container.BasicModule;
import org.jivesoftware.wildfire.container.AdminConsolePlugin;
import org.jivesoftware.wildfire.multiplex.MultiplexerPacketDeliverer;
import org.jivesoftware.wildfire.net.*;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.servlet.ServletHolder;
import org.mortbay.jetty.servlet.ServletHandler;
......@@ -54,12 +52,12 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
private boolean isStarted = false;
// Used to know if the sockets have been started
private boolean isSocketStarted = false;
private Server jettyServer;
private HttpServerManager serverManager;
public ConnectionManagerImpl() {
super("Connection Manager");
ports = new ArrayList<ServerPort>(4);
jettyServer = new Server();
serverManager = HttpServerManager.getInstance();
}
private void createSocket() {
......@@ -293,14 +291,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
}
private void startHTTPBindListeners() {
if(jettyServer == null) {
jettyServer = AdminConsolePlugin.getJettyServer();
if(jettyServer == null) {
return;
}
}
jettyServer.addHandler(createServletHandler());
serverManager.setHttpBindContext(createServletHandler());
}
private Handler createServletHandler() {
......@@ -520,14 +511,6 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
SocketAcceptThread.DEFAULT_MULTIPLEX_PORT);
}
public Server getHttpServer() {
return jettyServer;
}
public void setHttpServer(Server server) {
this.jettyServer = server;
}
// #####################################################################
// Module management
// #####################################################################
......
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