// // ======================================================================== // Copyright (c) 1995-2017 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.component; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jetty.util.TypeUtil; import org.junit.Assert; import org.junit.Test; public class ContainerLifeCycleTest { @Test public void testStartStop() throws Exception { ContainerLifeCycle a0 = new ContainerLifeCycle(); TestContainerLifeCycle a1 = new TestContainerLifeCycle(); a0.addBean(a1); a0.start(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(0, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.start(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(0, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.stop(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(1, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.start(); Assert.assertEquals(2, a1.started.get()); Assert.assertEquals(1, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.stop(); Assert.assertEquals(2, a1.started.get()); Assert.assertEquals(2, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); } @Test public void testStartStopDestroy() throws Exception { ContainerLifeCycle a0 = new ContainerLifeCycle(); TestContainerLifeCycle a1 = new TestContainerLifeCycle(); a0.start(); Assert.assertEquals(0, a1.started.get()); Assert.assertEquals(0, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.addBean(a1); Assert.assertEquals(0, a1.started.get()); Assert.assertEquals(0, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); Assert.assertFalse(a0.isManaged(a1)); a0.start(); Assert.assertEquals(0, a1.started.get()); Assert.assertEquals(0, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a1.start(); a0.manage(a1); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(0, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.removeBean(a1); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(1, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.stop(); a0.destroy(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(1, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a1.stop(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(1, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a1.destroy(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(1, a1.stopped.get()); Assert.assertEquals(1, a1.destroyed.get()); } @Test(expected = IllegalStateException.class) public void testIllegalToStartAfterDestroy() throws Exception { ContainerLifeCycle container = new ContainerLifeCycle(); container.start(); container.stop(); container.destroy(); // Should throw IllegalStateException. container.start(); } @Test public void testDisJoint() throws Exception { ContainerLifeCycle a0 = new ContainerLifeCycle(); TestContainerLifeCycle a1 = new TestContainerLifeCycle(); // Start the a1 bean before adding, makes it auto disjoint a1.start(); // Now add it a0.addBean(a1); Assert.assertFalse(a0.isManaged(a1)); a0.start(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(0, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.start(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(0, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.stop(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(0, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a1.stop(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(1, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.start(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(1, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.manage(a1); Assert.assertTrue(a0.isManaged(a1)); a0.stop(); Assert.assertEquals(1, a1.started.get()); Assert.assertEquals(1, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.start(); Assert.assertEquals(2, a1.started.get()); Assert.assertEquals(1, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.stop(); Assert.assertEquals(2, a1.started.get()); Assert.assertEquals(2, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a0.unmanage(a1); Assert.assertFalse(a0.isManaged(a1)); a0.destroy(); Assert.assertEquals(2, a1.started.get()); Assert.assertEquals(2, a1.stopped.get()); Assert.assertEquals(0, a1.destroyed.get()); a1.destroy(); Assert.assertEquals(2, a1.started.get()); Assert.assertEquals(2, a1.stopped.get()); Assert.assertEquals(1, a1.destroyed.get()); } @Test public void testDumpable() throws Exception { ContainerLifeCycle a0 = new ContainerLifeCycle(); String dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); ContainerLifeCycle aa0 = new ContainerLifeCycle(); a0.addBean(aa0); dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); dump = check(dump, " +? org.eclipse.jetty.util.component.ContainerLife"); ContainerLifeCycle aa1 = new ContainerLifeCycle(); a0.addBean(aa1); dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); dump = check(dump, " +? org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " +? org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, ""); ContainerLifeCycle aa2 = new ContainerLifeCycle(); a0.addBean(aa2, false); dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); dump = check(dump, " +? org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " +? org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " +~ org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, ""); aa1.start(); a0.start(); dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " +~ org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " +~ org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, ""); a0.manage(aa1); a0.removeBean(aa2); dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, ""); ContainerLifeCycle aaa0 = new ContainerLifeCycle(); aa0.addBean(aaa0); dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, ""); ContainerLifeCycle aa10 = new ContainerLifeCycle(); aa1.addBean(aa10, true); dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " += org.eclipse.jetty.util.component.Container"); dump = check(dump, ""); final ContainerLifeCycle a1 = new ContainerLifeCycle(); final ContainerLifeCycle a2 = new ContainerLifeCycle(); final ContainerLifeCycle a3 = new ContainerLifeCycle(); final ContainerLifeCycle a4 = new ContainerLifeCycle(); ContainerLifeCycle aa = new ContainerLifeCycle() { @Override public void dump(Appendable out, String indent) throws IOException { out.append(this.toString()).append("\n"); dump(out, indent, TypeUtil.asList(new Object[]{a1, a2}), TypeUtil.asList(new Object[]{a3, a4})); } }; a0.addBean(aa, true); dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " | += org.eclipse.jetty.util.component.Container"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, ""); a2.addBean(aa0, true); dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " | += org.eclipse.jetty.util.component.Container"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, " | += org.eclipse.jetty.util.component.Conta"); dump = check(dump, " | +~ org.eclipse.jetty.util.component.C"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, ""); a2.unmanage(aa0); dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " | += org.eclipse.jetty.util.component.Container"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, " | +~ org.eclipse.jetty.util.component.Conta"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, " +- org.eclipse.jetty.util.component.Container"); dump = check(dump, ""); a0.unmanage(aa); dump = trim(a0.dump()); dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container"); dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, " | += org.eclipse.jetty.util.component.Container"); dump = check(dump, " +~ org.eclipse.jetty.util.component.ContainerLife"); dump = check(dump, ""); } @Test public void listenerTest() throws Exception { final Queue<String> handled = new ConcurrentLinkedQueue<>(); final Queue<String> operation = new ConcurrentLinkedQueue<>(); final Queue<Container> parent = new ConcurrentLinkedQueue<>(); final Queue<Object> child = new ConcurrentLinkedQueue<>(); Container.Listener listener = new Container.Listener() { @Override public void beanRemoved(Container p, Object c) { handled.add(toString()); operation.add("removed"); parent.add(p); child.add(c); } @Override public void beanAdded(Container p, Object c) { handled.add(toString()); operation.add("added"); parent.add(p); child.add(c); } public @Override String toString() { return "listener"; } }; ContainerLifeCycle c0 = new ContainerLifeCycle() { public @Override String toString() { return "c0"; } }; ContainerLifeCycle c00 = new ContainerLifeCycle() { public @Override String toString() { return "c00"; } }; c0.addBean(c00); String b000 = "b000"; c00.addBean(b000); c0.addBean(listener); Assert.assertEquals("listener", handled.poll()); Assert.assertEquals("added", operation.poll()); Assert.assertEquals(c0, parent.poll()); Assert.assertEquals(c00, child.poll()); Assert.assertEquals("listener", handled.poll()); Assert.assertEquals("added", operation.poll()); Assert.assertEquals(c0, parent.poll()); Assert.assertEquals(listener, child.poll()); Container.InheritedListener inherited = new Container.InheritedListener() { @Override public void beanRemoved(Container p, Object c) { handled.add(toString()); operation.add("removed"); parent.add(p); child.add(c); } @Override public void beanAdded(Container p, Object c) { handled.add(toString()); operation.add("added"); parent.add(p); child.add(c); } public @Override String toString() { return "inherited"; } }; c0.addBean(inherited); Assert.assertEquals("inherited", handled.poll()); Assert.assertEquals("added", operation.poll()); Assert.assertEquals(c0, parent.poll()); Assert.assertEquals(c00, child.poll()); Assert.assertEquals("inherited", handled.poll()); Assert.assertEquals("added", operation.poll()); Assert.assertEquals(c0, parent.poll()); Assert.assertEquals(listener, child.poll()); Assert.assertEquals("listener", handled.poll()); Assert.assertEquals("added", operation.poll()); Assert.assertEquals(c0, parent.poll()); Assert.assertEquals(inherited, child.poll()); Assert.assertEquals("inherited", handled.poll()); Assert.assertEquals("added", operation.poll()); Assert.assertEquals(c0, parent.poll()); Assert.assertEquals(inherited, child.poll()); c0.start(); Assert.assertEquals("inherited", handled.poll()); Assert.assertEquals("added", operation.poll()); Assert.assertEquals(c00, parent.poll()); Assert.assertEquals(b000, child.poll()); Assert.assertEquals("inherited", handled.poll()); Assert.assertEquals("added", operation.poll()); Assert.assertEquals(c00, parent.poll()); Assert.assertEquals(inherited, child.poll()); c0.removeBean(c00); Assert.assertEquals("inherited", handled.poll()); Assert.assertEquals("removed", operation.poll()); Assert.assertEquals(c00, parent.poll()); Assert.assertEquals(inherited, child.poll()); Assert.assertEquals("inherited", handled.poll()); Assert.assertEquals("removed", operation.poll()); Assert.assertEquals(c00, parent.poll()); Assert.assertEquals(b000, child.poll()); Assert.assertEquals("listener", handled.poll()); Assert.assertEquals("removed", operation.poll()); Assert.assertEquals(c0, parent.poll()); Assert.assertEquals(c00, child.poll()); Assert.assertEquals("inherited", handled.poll()); Assert.assertEquals("removed", operation.poll()); Assert.assertEquals(c0, parent.poll()); Assert.assertEquals(c00, child.poll()); } private final class InheritedListenerLifeCycle extends AbstractLifeCycle implements Container.InheritedListener { @Override public void beanRemoved(Container p, Object c) { } @Override public void beanAdded(Container p, Object c) { } @Override public String toString() { return "inherited"; } } @Test public void testInheritedListener() throws Exception { ContainerLifeCycle c0 = new ContainerLifeCycle() { public @Override String toString() { return "c0"; } }; ContainerLifeCycle c00 = new ContainerLifeCycle() { public @Override String toString() { return "c00"; } }; ContainerLifeCycle c01 = new ContainerLifeCycle() { public @Override String toString() { return "c01"; } }; Container.InheritedListener inherited = new InheritedListenerLifeCycle(); c0.addBean(c00); c0.start(); c0.addBean(inherited); c0.manage(inherited); c0.addBean(c01); c01.start(); c0.manage(c01); Assert.assertTrue(c0.isManaged(inherited)); Assert.assertFalse(c00.isManaged(inherited)); Assert.assertFalse(c01.isManaged(inherited)); } String trim(String s) throws IOException { StringBuilder b = new StringBuilder(); BufferedReader reader = new BufferedReader(new StringReader(s)); for (String line = reader.readLine(); line != null; line = reader.readLine()) { if (line.length() > 50) line = line.substring(0, 50); b.append(line).append('\n'); } return b.toString(); } String check(String s, String x) { String r = s; int nl = s.indexOf('\n'); if (nl > 0) { r = s.substring(nl + 1); s = s.substring(0, nl); } Assert.assertEquals(x, s); return r; } private static class TestContainerLifeCycle extends ContainerLifeCycle { private final AtomicInteger destroyed = new AtomicInteger(); private final AtomicInteger started = new AtomicInteger(); private final AtomicInteger stopped = new AtomicInteger(); @Override protected void doStart() throws Exception { started.incrementAndGet(); super.doStart(); } @Override protected void doStop() throws Exception { stopped.incrementAndGet(); super.doStop(); } @Override public void destroy() { destroyed.incrementAndGet(); super.destroy(); } } }