package org.oddjob.beanbus.mega;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import junit.framework.TestCase;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.oddjob.Iconic;
import org.oddjob.Oddjob;
import org.oddjob.OddjobLookup;
import org.oddjob.OddjobSessionFactory;
import org.oddjob.Resetable;
import org.oddjob.arooa.ArooaDescriptor;
import org.oddjob.arooa.ArooaParseException;
import org.oddjob.arooa.ArooaSession;
import org.oddjob.arooa.ArooaType;
import org.oddjob.arooa.convert.ArooaConversionException;
import org.oddjob.arooa.life.InstantiationContext;
import org.oddjob.arooa.parsing.ArooaElement;
import org.oddjob.arooa.parsing.ConfigurationOwner;
import org.oddjob.arooa.parsing.ConfigurationSession;
import org.oddjob.arooa.parsing.DragPoint;
import org.oddjob.arooa.parsing.DragTransaction;
import org.oddjob.arooa.reflect.ArooaClass;
import org.oddjob.arooa.reflect.ArooaPropertyException;
import org.oddjob.arooa.registry.ChangeHow;
import org.oddjob.arooa.types.ArooaObject;
import org.oddjob.arooa.xml.XMLConfiguration;
import org.oddjob.beanbus.AbstractDestination;
import org.oddjob.beanbus.BusConductor;
import org.oddjob.beanbus.BusCrashException;
import org.oddjob.beanbus.BusEvent;
import org.oddjob.beanbus.Destination;
import org.oddjob.beanbus.TrackingBusListener;
import org.oddjob.beanbus.drivers.IterableBusDriver;
import org.oddjob.logging.LogEnabled;
import org.oddjob.logging.LogEvent;
import org.oddjob.logging.LogLevel;
import org.oddjob.logging.LogListener;
import org.oddjob.logging.log4j.Log4jArchiver;
import org.oddjob.state.ParentState;
import org.oddjob.tools.IconSteps;
public class MegaBeanBusTest extends TestCase {
private static Logger logger = Logger.getLogger(MegaBeanBusTest.class);
public void testSimpleLifecycle() {
ArooaSession session = new OddjobSessionFactory().createSession();
List<String> destination = new ArrayList<String>();
IterableBusDriver<String> driver = new IterableBusDriver<String>();
driver.setBeans(Arrays.asList("apple", "pear", "banana"));
driver.setTo(destination);
MegaBeanBus test = new MegaBeanBus();
test.setArooaSession(session);
test.setParts(0, driver);
test.setParts(1, destination);
test.run();
assertEquals(ParentState.COMPLETE,
test.lastStateEvent().getState());
}
public void testExample() throws ArooaPropertyException, ArooaConversionException {
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/beanbus/mega/MegaBeanBusExample.xml",
getClass().getClassLoader()));
oddjob.run();
assertEquals(ParentState.COMPLETE,
oddjob.lastStateEvent().getState());
OddjobLookup lookup = new OddjobLookup(oddjob);
@SuppressWarnings("unchecked")
List<String> results = lookup.lookup("list.beans", List.class);
assertEquals("Apple", results.get(0));
assertEquals("Orange", results.get(1));
assertEquals("Pear", results.get(2));
assertEquals(3, results.size());
oddjob.destroy();
}
public void testConfigurationSession() throws URISyntaxException {
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/beanbus/mega/MegaBeanBusExample.xml",
getClass().getClassLoader()));
oddjob.setExport("beans", new ArooaObject(
Collections.EMPTY_LIST));
oddjob.run();
assertEquals(ParentState.COMPLETE,
oddjob.lastStateEvent().getState());
OddjobLookup lookup = new OddjobLookup(oddjob);
ConfigurationOwner test = (ConfigurationOwner) lookup.lookup("bus");
ConfigurationSession session = test.provideConfigurationSession();
ArooaDescriptor descriptor = session.getArooaDescriptor();
ArooaClass cl = descriptor.getElementMappings().mappingFor(
new ArooaElement(new URI("oddjob:beanbus"), "bean-copy"),
new InstantiationContext(ArooaType.COMPONENT, null));
assertNotNull(cl);
oddjob.destroy();
}
public static class NumberGenerator implements Runnable {
private Collection<? super Integer> to;
@Override
public void run() {
for (int i = 0; i < 100; ++i) {
to.add(new Integer(i));
}
}
public void setTo(Collection<? super Integer> to) {
this.to = to;
}
}
public static class OurDestination extends AbstractDestination<Integer> {
int total;
boolean started;
boolean stopped;
final TrackingBusListener busListener = new TrackingBusListener() {
@Override
public void busStarting(BusEvent event) throws BusCrashException {
started = true;
total = 0;
}
@Override
public void busStopping(BusEvent event) throws BusCrashException {
stopped = true;
}
};
@Override
public boolean add(Integer e) {
total = total + e.intValue();
return true;
}
@Inject
public void setBusConductor(BusConductor busConductor) {
busListener.setBusConductor(busConductor);
}
public int getTotal() {
return total;
}
public boolean isStarted() {
return started;
}
public boolean isStopped() {
return stopped;
}
}
public void testWithNoBusConductor() throws ArooaPropertyException, ArooaConversionException {
String xml =
"<oddjob>" +
" <job>" +
" <bean-bus id='test'>" +
" <parts>" +
" <bean class='" + NumberGenerator.class.getName() + "'>" +
" <to><value value='${results}'/></to>" +
" </bean>" +
" <bean class='" + OurDestination.class.getName() + "' " +
" id='results'/>" +
" </parts>" +
" </bean-bus>" +
" </job>" +
"</oddjob>";
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration("XML", xml));
oddjob.load();
OddjobLookup lookup = new OddjobLookup(oddjob);
Iconic results = (Iconic) lookup.lookup("results");
IconSteps icons = new IconSteps(results);
icons.startCheck(CollectionWrapper.INACTIVE,
CollectionWrapper.ACTIVE, CollectionWrapper.INACTIVE);
oddjob.run();
assertEquals(ParentState.COMPLETE,
oddjob.lastStateEvent().getState());
icons.checkNow();
assertEquals(new Integer(4950), lookup.lookup(
"results.total", Integer.class));
assertEquals(Boolean.TRUE, lookup.lookup(
"results.started", boolean.class));
assertEquals(Boolean.TRUE, lookup.lookup(
"results.stopped", boolean.class));
Object test = lookup.lookup("test");
((Resetable) test).hardReset();
((Runnable) test).run();
assertEquals(new Integer(4950), lookup.lookup(
"results.total", Integer.class));
oddjob.destroy();
}
public static class OurSliperyDestination extends AbstractDestination<Integer> {
int crashed;
int terminated;
final TrackingBusListener busListener = new TrackingBusListener() {
@Override
public void busStarting(BusEvent event) throws BusCrashException {
throw new BusCrashException("Slippery Destination!");
}
@Override
public void busCrashed(BusEvent event) {
++crashed;
}
@Override
public void busTerminated(BusEvent event) {
++terminated;
}
};
@Override
public boolean add(Integer e) {
throw new RuntimeException("Unexpected.");
}
@Inject
public void setBusConductor(BusConductor busConductor) {
busListener.setBusConductor(busConductor);
}
public int getCrashed() {
return crashed;
}
public int getTerminated() {
return terminated;
}
}
public void testWithBadBusPart() throws ArooaPropertyException, ArooaConversionException {
String xml =
"<oddjob>" +
" <job>" +
" <bean-bus id='test'>" +
" <parts>" +
" <bean class='" + NumberGenerator.class.getName() + "'>" +
" <to><value value='${results}'/></to>" +
" </bean>" +
" <bean class='" + OurSliperyDestination.class.getName() + "' " +
" id='results'/>" +
" </parts>" +
" </bean-bus>" +
" </job>" +
"</oddjob>";
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration("XML", xml));
oddjob.load();
OddjobLookup lookup = new OddjobLookup(oddjob);
Iconic results = (Iconic) lookup.lookup("results");
IconSteps icons = new IconSteps(results);
icons.startCheck(CollectionWrapper.INACTIVE,
CollectionWrapper.ACTIVE, CollectionWrapper.INACTIVE);
oddjob.run();
assertEquals(ParentState.EXCEPTION,
oddjob.lastStateEvent().getState());
icons.checkNow();
assertEquals(new Integer(1), lookup.lookup(
"results.crashed", Integer.class));
assertEquals(new Integer(1), lookup.lookup(
"results.terminated", Integer.class));
Object test = lookup.lookup("test");
((Resetable) test).hardReset();
((Runnable) test).run();
assertEquals(new Integer(2), lookup.lookup(
"results.crashed", Integer.class));
assertEquals(new Integer(2), lookup.lookup(
"results.terminated", Integer.class));
oddjob.destroy();
}
public static class OutboundCapture extends AbstractDestination<String> {
private List<Collection<String>> outbounds =
new ArrayList<Collection<String>>();
@Override
public boolean add(String e) {
outbounds.get(outbounds.size() - 1).add(e);
return true;
}
@Destination
public void setOutbound(Collection<String> outbound) {
this.outbounds.add(outbound);
}
public List<Collection<String>> getOutbounds() {
return outbounds;
}
}
@SuppressWarnings("unchecked")
public void testNoAutoLink() throws ArooaPropertyException, ArooaConversionException {
List<String> ourList = new ArrayList<String>();
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/beanbus/mega/MegaBeanBusNoAutoLink.xml",
getClass().getClassLoader()));
oddjob.setExport("our-list", new ArooaObject(ourList));
oddjob.run();
assertEquals(ParentState.COMPLETE,
oddjob.lastStateEvent().getState());
OddjobLookup lookup = new OddjobLookup(oddjob);
List<List<String>> outbounds = lookup.lookup("capture.outbounds", List.class);
assertEquals(1, outbounds.size());
List<String> results = outbounds.get(0);
assertSame(ourList, results);
assertEquals("Apple", results.get(0));
assertEquals("Orange", results.get(1));
assertEquals("Pear", results.get(2));
assertEquals(3, results.size());
List<String> outboundList = lookup.lookup("list.beans", List.class);
assertEquals(0, outboundList.size());
Object bus = lookup.lookup("bus");
((Resetable) bus).hardReset();
((Runnable) bus).run();
outbounds = lookup.lookup("capture.outbounds", List.class);
assertEquals(3, outbounds.size());
results = outbounds.get(2);
assertSame(ourList, results);
oddjob.destroy();
}
public static class ThingWithOutbound {
private Collection<String> outbound;
public Collection<String> getOutbound() {
return outbound;
}
public void setOutbound(Collection<String> outbound) {
this.outbound = outbound;
}
}
public static class ComplicatedOutbound extends AbstractDestination<String> {
private ThingWithOutbound thing;
@Override
public boolean add(String e) {
thing.outbound.add(e);
return true;
}
public ThingWithOutbound getThing() {
return thing;
}
public void setThing(ThingWithOutbound thing) {
this.thing = thing;
}
@Destination
public void acceptOutbound(Collection<String> outbound) {
this.thing.setOutbound(outbound);
}
}
/**
* Need to ensure the order of configuration and auto linking is OK.
*/
public void testWithComplicatedOutbound() throws ArooaPropertyException, ArooaConversionException {
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/beanbus/mega/MegaBeanBusComplexOutbound.xml",
getClass().getClassLoader()));
oddjob.run();
assertEquals(ParentState.COMPLETE,
oddjob.lastStateEvent().getState());
OddjobLookup lookup = new OddjobLookup(oddjob);
@SuppressWarnings("unchecked")
List<String> results = lookup.lookup("list.beans", List.class);
assertEquals("Apple", results.get(0));
assertEquals("Orange", results.get(1));
assertEquals("Pear", results.get(2));
assertEquals(3, results.size());
@SuppressWarnings("unchecked")
Collection<String> outbound = lookup.lookup(
"capture.thing.outbound", Collection.class);
@SuppressWarnings("unchecked")
Collection<String> beanCapture = lookup.lookup(
"list", Collection.class);
assertSame(beanCapture, outbound);
oddjob.destroy();
}
public static class DestinationWithLogger extends AbstractDestination<String> {
final TrackingBusListener busListener = new TrackingBusListener() {
@Override
public void busStarting(BusEvent event) throws BusCrashException {
logger.info("The Bus is Starting.");
}
public void tripBeginning(BusEvent event) throws BusCrashException {
logger.info("A Trip is Beginning.");
}
public void tripEnding(BusEvent event) throws BusCrashException {
logger.info("A Trip is Ending.");
}
public void busStopRequested(BusEvent event) {
logger.info("A Bus Stop is Requested.");
}
@Override
public void busStopping(BusEvent event) throws BusCrashException {
logger.info("The Bus is Stopping.");
}
public void busCrashed(BusEvent event) {
logger.info("The Bus has Crashed.");
};
public void busTerminated(BusEvent event) {
logger.info("The Bus has terminated.");
}
};
@Override
public boolean add(String e) {
logger.info("We have received " + e + ".");
if ("crash-the-bus".equals(e)) {
throw new IllegalArgumentException(e);
}
else {
busListener.getBusConductor().requestBusStop();
}
return true;
}
@Inject
public void setBusConductor(BusConductor busConductor) {
busListener.setBusConductor(busConductor);
}
}
/**
* Test logging. Note that this test is fragile with respect to change
* in the logging properties.
*
* @throws Exception
*/
public void testDefaultLogger() throws Exception {
final List<String> messages = new ArrayList<String>();
class MyLogListener implements LogListener {
public void logEvent(LogEvent logEvent) {
messages.add(logEvent.getMessage().trim());
}
}
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/beanbus/mega/MegaLoggerTest.xml",
getClass().getClassLoader()));
oddjob.load();
assertEquals(ParentState.READY,
oddjob.lastStateEvent().getState());
OddjobLookup lookup = new OddjobLookup(oddjob);
Object thingWithLogging = lookup.lookup("thing-with-logging");
String loggerName = ((LogEnabled) thingWithLogging).loggerName();
assertEquals(DestinationWithLogger.class.getName(),
loggerName.substring(0, DestinationWithLogger.class.getName().length()));
Logger.getLogger(loggerName).setLevel(Level.INFO);
Log4jArchiver archiver = new Log4jArchiver(thingWithLogging, "%m%n");
MyLogListener ll = new MyLogListener();
archiver.addLogListener(ll, thingWithLogging, LogLevel.DEBUG, 0, 1000);
oddjob.run();
assertEquals(ParentState.COMPLETE,
oddjob.lastStateEvent().getState());
assertEquals("The Bus is Starting.", messages.get(1));
assertEquals("A Trip is Beginning.", messages.get(2));
assertEquals("We have received Apples.", messages.get(3));
assertEquals("A Bus Stop is Requested.", messages.get(4));
assertEquals("A Trip is Ending.", messages.get(5));
assertEquals("The Bus is Stopping.", messages.get(6));
assertEquals("The Bus has terminated.", messages.get(7));
assertEquals(8, messages.size());
Object secondBus = lookup.lookup("second-bus");
((Resetable) secondBus).hardReset();
oddjob.run();
assertEquals(ParentState.EXCEPTION,
oddjob.lastStateEvent().getState());
assertEquals("The Bus is Starting.", messages.get(9));
assertEquals("A Trip is Beginning.", messages.get(10));
assertEquals("We have received crash-the-bus.", messages.get(11));
assertEquals("The Bus has Crashed.", messages.get(12));
assertEquals("The Bus has terminated.", messages.get(13));
oddjob.destroy();
}
public void testCutPasteBusPartInvalidatesBus() throws ArooaParseException {
Oddjob oddjob = new Oddjob();
oddjob.setConfiguration(new XMLConfiguration(
"org/oddjob/beanbus/mega/MegaBusCutTest.xml",
getClass().getClassLoader()));
oddjob.run();
assertEquals(ParentState.COMPLETE,
oddjob.lastStateEvent().getState());
Object busPart = new OddjobLookup(
oddjob).lookup("bus-part");
DragPoint busPartPoint = oddjob.provideConfigurationSession().dragPointFor(
busPart);
DragTransaction trn = busPartPoint.beginChange(ChangeHow.FRESH);
String copy = busPartPoint.copy();
busPartPoint.cut();
trn.commit();
Object bus = new OddjobLookup(
oddjob).lookup("bus");
DragPoint busPoint = oddjob.provideConfigurationSession().dragPointFor(
bus);
trn = busPoint.beginChange(ChangeHow.FRESH);
busPoint.paste(-1, copy);
trn.commit();
Object driver = new OddjobLookup(
oddjob).lookup("driver");
((Resetable) driver).hardReset();
((Runnable) driver).run();
assertEquals(ParentState.EXCEPTION,
oddjob.lastStateEvent().getState());
oddjob.destroy();
}
}