296765 JMX Connector Server and ShutdownThread

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@1140 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Greg Wilkins 2009-12-10 23:21:06 +00:00
parent 9825a4282b
commit 3fea82d8a4
6 changed files with 374 additions and 228 deletions

View File

@ -1,6 +1,7 @@
jetty-7.0.2-SNAPSHOT
+ JSON parses NaN as null
+ 290765 Reset input for HttpExchange retry.
+ 296765 JMX Connector Server and ShutdownThread
+ 297421 Hide server/system classes from WebAppClassLoader.getResources
jetty-7.0.1.v20091125 25 November 2009

View File

@ -9,51 +9,62 @@
<!-- =============================================================== -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Initialize an mbean server -->
<!-- =========================================================== -->
<Call id="MBeanServer" class="java.lang.management.ManagementFactory" name="getPlatformMBeanServer"/>
<!-- =========================================================== -->
<!-- Initialize an mbean server -->
<!-- =========================================================== -->
<Call id="MBeanServer" class="java.lang.management.ManagementFactory"
name="getPlatformMBeanServer" />
<!-- =========================================================== -->
<!-- Initialize the Jetty MBean container -->
<!-- =========================================================== -->
<New id="MBeanContainer" class="org.eclipse.jetty.jmx.MBeanContainer">
<Arg><Ref id="MBeanServer"/></Arg>
</New>
<!-- =========================================================== -->
<!-- Initialize the Jetty MBean container -->
<!-- =========================================================== -->
<New id="MBeanContainer" class="org.eclipse.jetty.jmx.MBeanContainer">
<Arg>
<Ref id="MBeanServer" />
</Arg>
</New>
<!-- Add to the Server to listen for object events -->
<Get id="Container" name="container">
<Call name="addEventListener">
<Arg><Ref id="MBeanContainer"/></Arg>
</Call>
</Get>
<!-- Add to the Server as a lifecycle -->
<!-- Only do this if you know you will only have a single jetty server -->
<Call name="addBean">
<Arg><Ref id="MBeanContainer"/></Arg>
</Call>
<!-- Add the static log -->
<Get id="Logger" class="org.eclipse.jetty.util.log.Log" name="log"/>
<Ref id="MBeanContainer">
<Call name="addBean">
<Arg><Ref id="Logger"/></Arg>
</Call>
</Ref>
<!-- optionally add a remote JMX connector
<Call id="jmxConnector" class="javax.management.remote.JMXConnectorServerFactory" name="newJMXConnectorServer">
<!-- Add to the Server to listen for object events -->
<Get id="Container" name="container">
<Call name="addEventListener">
<Arg>
<New class="javax.management.remote.JMXServiceURL">
<Arg>service:jmx:rmi:///jndi/rmi:///jettymbeanserver</Arg>
</New>
<Ref id="MBeanContainer" />
</Arg>
<Arg/>
<Arg><Ref id="MBeanServer"/></Arg>
<Call name="start"/>
</Call>
-->
</Get>
<!-- Add to the Server as a lifecycle -->
<!-- Only do this if you know you will only have a single jetty server -->
<Call name="addBean">
<Arg>
<Ref id="MBeanContainer" />
</Arg>
</Call>
<!-- Add the static log -->
<Get id="Logger" class="org.eclipse.jetty.util.log.Log" name="log" />
<Ref id="MBeanContainer">
<Call name="addBean">
<Arg>
<Ref id="Logger" />
</Arg>
</Call>
</Ref>
<!-- optionally add a remote JMX connector
<New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
<Arg>
<New class="javax.management.remote.JMXServiceURL">
<Arg type="java.lang.String">rmi</Arg>
<Arg type="java.lang.String" />
<Arg type="java.lang.Integer">0</Arg>
<Arg type="java.lang.String">/jndi/rmi://localhost:1099/jettyjmx</Arg>
</New>
</Arg>
<Arg>org.eclipse.jetty:name=rmiconnectorserver</Arg>
<Call name="start" />
</New>
-->
</Configure>

View File

@ -0,0 +1,101 @@
// ========================================================================
// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.jmx;
import java.lang.management.ManagementFactory;
import java.util.Map;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.thread.ShutdownThread;
/* ------------------------------------------------------------ */
/**
* AbstractLifeCycle wrapper for JMXConnector Server
*/
public class ConnectorServer extends AbstractLifeCycle
{
JMXConnectorServer _connectorServer;
/* ------------------------------------------------------------ */
/**
* Constructs connector server
*
* @param serviceURL the address of the new connector server.
* The actual address of the new connector server, as returned
* by its getAddress method, will not necessarily be exactly the same.
* @param name object name string to be assigned to connector server bean
* @throws Exception
*/
public ConnectorServer(JMXServiceURL serviceURL, String name)
throws Exception
{
this(serviceURL, null, name);
}
/* ------------------------------------------------------------ */
/**
* Constructs connector server
*
* @param serviceURL the address of the new connector server.
* The actual address of the new connector server, as returned
* by its getAddress method, will not necessarily be exactly the same.
* @param environment a set of attributes to control the new connector
* server's behavior. This parameter can be null. Keys in this map must
* be Strings. The appropriate type of each associated value depends on
* the attribute. The contents of environment are not changed by this call.
* @param name object name string to be assigned to connector server bean
* @throws Exception
*/
public ConnectorServer(JMXServiceURL serviceURL, Map<String,?> environment, String name)
throws Exception
{
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
_connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serviceURL, environment, mbeanServer);
mbeanServer.registerMBean(_connectorServer,new ObjectName(name));
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
*/
@Override
public void doStart()
throws Exception
{
_connectorServer.start();
ShutdownThread.register(0, this);
Log.info("JMX Remote URL: {}", _connectorServer.getAddress().toString());
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
*/
@Override
public void doStop()
throws Exception
{
ShutdownThread.deregister(this);
_connectorServer.stop();
}
}

View File

@ -15,9 +15,10 @@ package org.eclipse.jetty.jmx;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import javax.management.MBeanServer;
@ -30,27 +31,45 @@ import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.component.Container;
import org.eclipse.jetty.util.component.Container.Relationship;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.thread.ShutdownThread;
/* ------------------------------------------------------------ */
/**
* Container class for the MBean instances
*/
public class MBeanContainer extends AbstractLifeCycle implements Container.Listener
{
private final MBeanServer _server;
private final WeakHashMap _beans = new WeakHashMap();
private final HashMap _unique = new HashMap();
private final WeakHashMap<Object, ObjectName> _beans = new WeakHashMap<Object, ObjectName>();
private final HashMap<String, Integer> _unique = new HashMap<String, Integer>();
private final MultiMap<ObjectName> _relations = new MultiMap<ObjectName>();
private String _domain = null;
private MultiMap _relations = new MultiMap();
/* ------------------------------------------------------------ */
/**
* Lookup an object name by instance
*
* @param object instance for which object name is looked up
* @return object name associated with specified instance, or null if not found
*/
public synchronized ObjectName findMBean(Object object)
{
ObjectName bean = (ObjectName)_beans.get(object);
return bean==null?null:bean;
}
/* ------------------------------------------------------------ */
/**
* Lookup an instance by object name
*
* @param oname object name of instance
* @return instance associated with specified object name, or null if not found
*/
public synchronized Object findBean(ObjectName oname)
{
for (Iterator iter = _beans.entrySet().iterator(); iter.hasNext();)
for (Map.Entry<Object, ObjectName> entry : _beans.entrySet())
{
Map.Entry entry = (Map.Entry) iter.next();
ObjectName bean = (ObjectName)entry.getValue();
if (bean.equals(oname))
return entry.getKey();
@ -58,30 +77,65 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste
return null;
}
/* ------------------------------------------------------------ */
/**
* Constructs MBeanContainer
*
* @param server instance of MBeanServer for use by container
*/
public MBeanContainer(MBeanServer server)
{
this._server = server;
_server = server;
try
{
start();
}
catch (Exception e)
{
Log.ignore(e);
}
}
/* ------------------------------------------------------------ */
/**
* Retrieve instance of MBeanServer used by container
*
* @return instance of MBeanServer
*/
public MBeanServer getMBeanServer()
{
return _server;
}
/* ------------------------------------------------------------ */
/**
* Set domain to be used to add MBeans
*
* @param domain domain name
*/
public void setDomain (String domain)
{
_domain =domain;
_domain = domain;
}
/* ------------------------------------------------------------ */
/**
* Retrieve domain name used to add MBeans
*
* @return domain name
*/
public String getDomain()
{
return _domain;
}
public void doStart()
{
}
/* ------------------------------------------------------------ */
/**
* Implementation of Container.Listener interface
*
* @see org.eclipse.jetty.util.component.Container.Listener#add(org.eclipse.jetty.util.component.Container.Relationship)
*/
public synchronized void add(Relationship relationship)
{
ObjectName parent=(ObjectName)_beans.get(relationship.getParent());
@ -100,10 +154,14 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste
if (parent!=null && child!=null)
_relations.add(parent,relationship);
}
/* ------------------------------------------------------------ */
/**
* Implementation of Container.Listener interface
*
* @see org.eclipse.jetty.util.component.Container.Listener#remove(org.eclipse.jetty.util.component.Container.Relationship)
*/
public synchronized void remove(Relationship relationship)
{
ObjectName parent=(ObjectName)_beans.get(relationship.getParent());
@ -112,21 +170,26 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste
_relations.removeValue(parent,relationship);
}
/* ------------------------------------------------------------ */
/**
* Implementation of Container.Listener interface
*
* @see org.eclipse.jetty.util.component.Container.Listener#removeBean(java.lang.Object)
*/
public synchronized void removeBean(Object obj)
{
ObjectName bean=(ObjectName)_beans.remove(obj);
if (bean!=null)
{
List r=_relations.getValues(bean);
if (r!=null && r.size()>0)
List<Relationship> beanRelations = _relations.getValues(bean);
if (beanRelations!=null && beanRelations.size()>0)
{
Log.debug("Unregister {}", r);
Iterator iter = new ArrayList(r).iterator();
while (iter.hasNext())
Log.debug("Unregister {}", beanRelations);
List<Relationship> removeList = new ArrayList<Relationship>(beanRelations);
for (Relationship relation : removeList)
{
Relationship rel = (Relationship)iter.next();
rel.getContainer().update(rel.getParent(),rel.getChild(),null,rel.getRelationship(),true);
relation.getContainer().update(relation.getParent(),relation.getChild(),null,relation.getRelationship(),true);
}
}
@ -146,6 +209,12 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste
}
}
/* ------------------------------------------------------------ */
/**
* Implementation of Container.Listener interface
*
* @see org.eclipse.jetty.util.component.Container.Listener#addBean(java.lang.Object)
*/
public synchronized void addBean(Object obj)
{
try
@ -218,57 +287,29 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste
}
}
/* ------------------------------------------------------------ */
/**
* Perform actions needed to start lifecycle
*
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
*/
public void doStart()
{
ShutdownThread.register(this);
}
/* ------------------------------------------------------------ */
/**
* Perform actions needed to stop lifecycle
*
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
*/
public void doStop()
{
while (_beans.size()>0)
removeBean(_beans.keySet().iterator().next());
}
private class ShutdownHook extends Thread
{
private final ObjectName mletName;
private final ObjectName adaptorName;
private final ObjectName processorName;
public ShutdownHook(ObjectName mletName, ObjectName adaptorName, ObjectName processorName)
Set<Object> removeSet = new HashSet<Object>(_beans.keySet());
for (Object removeObj : removeSet)
{
this.mletName = mletName;
this.adaptorName = adaptorName;
this.processorName = processorName;
}
public void run()
{
halt();
unregister(processorName);
unregister(adaptorName);
unregister(mletName);
}
private void halt()
{
try
{
_server.invoke(adaptorName, "stop", null, null);
}
catch (Exception e)
{
Log.warn(e);
}
}
private void unregister(ObjectName objectName)
{
try
{
_server.unregisterMBean(objectName);
Log.debug("Unregistered " + objectName);
}
catch (Exception e)
{
Log.warn(e);
}
removeBean(removeObj);
}
}
}

View File

@ -41,6 +41,7 @@ import org.eclipse.jetty.util.component.Container;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ShutdownThread;
import org.eclipse.jetty.util.thread.ThreadPool;
/* ------------------------------------------------------------ */
@ -54,7 +55,6 @@ import org.eclipse.jetty.util.thread.ThreadPool;
*/
public class Server extends HandlerWrapper implements Attributes
{
private static final ShutdownHookThread hookThread = new ShutdownHookThread();
private static final String _version;
static
{
@ -120,7 +120,9 @@ public class Server extends HandlerWrapper implements Attributes
{
_stopAtShutdown=stop;
if (stop)
hookThread.add(this);
ShutdownThread.register(this);
else
ShutdownThread.deregister(this);
}
/* ------------------------------------------------------------ */
@ -189,7 +191,7 @@ public class Server extends HandlerWrapper implements Attributes
protected void doStart() throws Exception
{
if (getStopAtShutdown())
hookThread.add(this);
ShutdownThread.register(this);
Log.info("jetty-"+_version);
HttpGenerator.setServerVersion(_version);
@ -309,7 +311,7 @@ public class Server extends HandlerWrapper implements Attributes
}
mex.ifExceptionThrow();
hookThread.remove(this);
ShutdownThread.deregister(this);
}
/* ------------------------------------------------------------ */
@ -518,119 +520,6 @@ public class Server extends HandlerWrapper implements Attributes
_container.removeBean(o);
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/**
* ShutdownHook thread for stopping all servers.
*
* Thread is hooked first time list of servers is changed.
*/
private static class ShutdownHookThread extends Thread
{
private boolean _hooked = false;
private final Set<Server> _servers = new CopyOnWriteArraySet<Server>();
/**
* Hooks this thread for shutdown.
*
* @see java.lang.Runtime#addShutdownHook(java.lang.Thread)
*/
private void createShutdownHook()
{
if (!_hooked)
{
try
{
Method shutdownHook = java.lang.Runtime.class.getMethod("addShutdownHook", Thread.class);
shutdownHook.invoke(Runtime.getRuntime(), this);
_hooked = true;
}
catch (Exception e)
{
if (Log.isDebugEnabled())
Log.debug("No shutdown hook in JVM ", e);
}
}
}
/**
* Add Server to servers list.
*/
public void add(Server server)
{
_servers.add(server);
if (server.getStopAtShutdown())
createShutdownHook();
}
/**
* Contains Server in servers list?
*/
public boolean contains(Server server)
{
return _servers.contains(server);
}
public Iterable<Server> getServers()
{
return _servers;
}
/**
* Clear list of Servers.
*/
public void clear()
{
_servers.clear();
}
/**
* Remove Server from list.
*/
public boolean remove(Server server)
{
createShutdownHook();
return _servers.remove(server);
}
/**
* Stop all Servers in list.
*/
@Override
public void run()
{
setName("Shutdown");
Log.info("Shutdown hook executing");
for (Server svr : _servers)
{
if (svr == null || !svr.getStopAtShutdown() || !svr.isRunning())
continue;
try
{
svr.stop();
}
catch (Exception e)
{
Log.warn(e);
}
Log.info("Shutdown hook complete");
// Try to avoid JVM crash
try
{
Thread.sleep(1000);
}
catch (Exception e)
{
Log.warn(e);
}
}
}
}
/* ------------------------------------------------------------ */
/*
* @see org.eclipse.util.AttributesMap#clearAttributes()

View File

@ -0,0 +1,103 @@
// ========================================================================
// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.util.thread;
import java.io.ObjectStreamException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
/* ------------------------------------------------------------ */
/**
* ShutdownThread is a shutdown hook thread implemented as
* singleton that maintains a list of lifecycle instances
* that are registered with it and provides ability to stop
* these lifecycles upon shutdown of the Java Virtual Machine
*/
public class ShutdownThread extends Thread
{
private static final ShutdownThread _thread = new ShutdownThread();
private final List<LifeCycle> _lifeCycles = new CopyOnWriteArrayList<LifeCycle>();
/* ------------------------------------------------------------ */
/**
* Default constructor for the singleton
*
* Registers the instance as shutdown hook with the Java Runtime
*/
private ShutdownThread()
{
Runtime.getRuntime().addShutdownHook(this);
}
/* ------------------------------------------------------------ */
/**
* Returns the instance of the singleton
*
* @return
*/
public static ShutdownThread getInstance()
{
return _thread;
}
/* ------------------------------------------------------------ */
public static synchronized void register(LifeCycle... lifeCycles)
{
_thread._lifeCycles.addAll(Arrays.asList(lifeCycles));
}
/* ------------------------------------------------------------ */
public static synchronized void register(int index, LifeCycle... lifeCycles)
{
_thread._lifeCycles.addAll(index,Arrays.asList(lifeCycles));
}
/* ------------------------------------------------------------ */
public static synchronized void deregister(LifeCycle lifeCycle)
{
_thread._lifeCycles.remove(lifeCycle);
}
/* ------------------------------------------------------------ */
public void run()
{
for (LifeCycle lifeCycle : _thread._lifeCycles)
{
try
{
lifeCycle.stop();
Log.debug("Stopped " + lifeCycle);
}
catch (Exception ex)
{
Log.debug(ex);
}
}
}
/* ------------------------------------------------------------ */
protected Object readResolve()
throws ObjectStreamException
{
return _thread;
}
}