//
// ========================================================================
// 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();
}
}
}