diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java index c8de691a079..9bcfe62f6f2 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java @@ -32,6 +32,7 @@ import javax.management.ObjectName; import org.eclipse.jetty.util.component.Container; import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.component.Destroyable; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -39,7 +40,7 @@ import org.eclipse.jetty.util.log.Logger; /** * Container class for the MBean instances */ -public class MBeanContainer implements Container.InheritedListener, Dumpable +public class MBeanContainer implements Container.InheritedListener, Dumpable, Destroyable { private final static Logger LOG = Log.getLogger(MBeanContainer.class.getName()); private final static ConcurrentMap __unique = new ConcurrentHashMap<>(); @@ -254,6 +255,7 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable return ContainerLifeCycle.dump(this); } + @Override public void destroy() { _beans.values().stream() diff --git a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/MBeanContainerLifeCycleTest.java b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/MBeanContainerLifeCycleTest.java new file mode 100644 index 00000000000..59ebe7d98f8 --- /dev/null +++ b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/MBeanContainerLifeCycleTest.java @@ -0,0 +1,116 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.Set; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class MBeanContainerLifeCycleTest +{ + private ContainerLifeCycle container; + private MBeanServer mbeanServer; + + @Before + public void prepare() throws Exception + { + container = new ContainerLifeCycle(); + mbeanServer = ManagementFactory.getPlatformMBeanServer(); + MBeanContainer mbeanContainer = new MBeanContainer(mbeanServer); + container.addBean(mbeanContainer); + container.start(); + } + + @After + public void dispose() throws Exception + { + container.stop(); + } + + @Test + public void testAddBeanRegistersMBeanRemoveBeanUnregistersMBean() throws Exception + { + // Adding a bean to the container should register the MBean. + QueuedThreadPool bean = new QueuedThreadPool(); + container.addBean(bean); + + String pkg = bean.getClass().getPackage().getName(); + Set objectNames = mbeanServer.queryNames(ObjectName.getInstance(pkg + ":*"), null); + Assert.assertEquals(1, objectNames.size()); + + // Removing the bean should unregister the MBean. + container.removeBean(bean); + objectNames = mbeanServer.queryNames(ObjectName.getInstance(pkg + ":*"), null); + Assert.assertEquals(0, objectNames.size()); + } + + @Test + public void testStoppingContainerDoesNotUnregistersMBeans() throws Exception + { + QueuedThreadPool bean = new QueuedThreadPool(); + container.addBean(bean, true); + + String pkg = bean.getClass().getPackage().getName(); + Set objectNames = mbeanServer.queryNames(ObjectName.getInstance(pkg + ":*"), null); + Assert.assertEquals(1, objectNames.size()); + + container.stop(); + + objectNames = mbeanServer.queryNames(ObjectName.getInstance(pkg + ":*"), null); + Assert.assertEquals(1, objectNames.size()); + + // Remove the MBeans to start clean on the next test. + objectNames.forEach(objectName -> + { + try + { + mbeanServer.unregisterMBean(objectName); + } + catch (Throwable ignored) + { + } + }); + } + + @Test + public void testDestroyingContainerUnregistersMBeans() throws Exception + { + QueuedThreadPool bean = new QueuedThreadPool(); + container.addBean(bean, true); + + String pkg = bean.getClass().getPackage().getName(); + Set objectNames = mbeanServer.queryNames(ObjectName.getInstance(pkg + ":*"), null); + Assert.assertEquals(1, objectNames.size()); + + container.stop(); + container.destroy(); + + objectNames = mbeanServer.queryNames(ObjectName.getInstance(pkg + ":*"), null); + Assert.assertEquals(0, objectNames.size()); + } +}