/* * Copyright (c) 2005, Rob Gordon. */ package org.oddjob; import java.io.File; import java.util.ArrayList; import java.util.List; import junit.framework.TestCase; import org.oddjob.arooa.ArooaException; import org.oddjob.arooa.ArooaParseException; import org.oddjob.arooa.ArooaSession; import org.oddjob.arooa.ComponentTrinity; import org.oddjob.arooa.convert.ArooaConversionException; import org.oddjob.arooa.parsing.MockArooaContext; import org.oddjob.arooa.registry.BeanDirectory; import org.oddjob.arooa.registry.ComponentPool; import org.oddjob.arooa.runtime.MockRuntimeConfiguration; import org.oddjob.arooa.runtime.RuntimeConfiguration; import org.oddjob.arooa.types.XMLConfigurationType; import org.oddjob.arooa.xml.XMLConfiguration; import org.oddjob.framework.SimpleJob; import org.oddjob.state.JobState; import org.oddjob.state.ParentState; import org.oddjob.state.StateListener; import org.oddjob.state.State; import org.oddjob.state.StateEvent; import org.oddjob.structural.StructuralEvent; import org.oddjob.structural.StructuralListener; import org.oddjob.tools.OddjobTestHelper; import org.oddjob.tools.OurDirs; import org.oddjob.util.URLClassLoaderType; /** * Mainly the same tests as OddjobTest but only for load(), not run(). * * @author Rob Gordon. */ public class OddjobLoadTest extends TestCase { /** * Test resetting Oddjob * */ public void testReset() { class MyL implements StructuralListener { int count; public void childAdded(StructuralEvent event) { count++; } public void childRemoved(StructuralEvent event) { count--; } } class MySL implements StateListener { List<State> states = new ArrayList<State>(); public void jobStateChange(StateEvent event) { states.add(event.getState()); } } String xml = "<oddjob xmlns:state='http://rgordon.co.uk/oddjob/state'>" + " <job>" + " <state:flag id='flag' state='COMPLETE'/>" + " </job>" + "</oddjob>"; Oddjob oj = new Oddjob(); oj.setConfiguration(new XMLConfiguration("XML", xml)); MyL childListener = new MyL(); oj.addStructuralListener(childListener); assertEquals(0, childListener.count); oj.load(); Stateful flag = (Stateful) new OddjobLookup(oj).lookup("flag"); MySL stateListener = new MySL(); flag.addStateListener(stateListener); assertEquals(1, stateListener.states.size()); assertEquals(JobState.READY, stateListener.states.get(0)); assertEquals(1, childListener.count); oj.hardReset(); assertEquals(2, stateListener.states.size()); assertEquals(JobState.DESTROYED, stateListener.states.get(1)); assertEquals(0, childListener.count); oj.load(); // new job. assertEquals(2, stateListener.states.size()); assertEquals(1, childListener.count); oj.hardReset(); assertEquals(0, childListener.count); oj.load(); assertEquals(1, childListener.count); oj.destroy(); } /** * Test reseting Oddjob * */ public void testSoftReset() { class MyL implements StructuralListener { int count; public void childAdded(StructuralEvent event) { count++; } public void childRemoved(StructuralEvent event) { count--; } } String xml = "<oddjob xmlns:state='http://rgordon.co.uk/oddjob/state'>" + " <job>" + " <state:flag state='INCOMPLETE'/>" + " </job>" + "</oddjob>"; Oddjob oj = new Oddjob(); oj.setConfiguration(new XMLConfiguration("XML", xml)); MyL l = new MyL(); oj.addStructuralListener(l); assertEquals(0, l.count); oj.load(); assertEquals(1, l.count); assertEquals(ParentState.READY, oj.lastStateEvent().getState()); oj.softReset(); assertEquals(1, l.count); assertEquals(ParentState.READY, oj.lastStateEvent().getState()); oj.load(); assertEquals(1, l.count); assertEquals(ParentState.READY, oj.lastStateEvent().getState()); oj.softReset(); assertEquals(1, l.count); assertEquals(ParentState.READY, oj.lastStateEvent().getState()); oj.load(); assertEquals(1, l.count); assertEquals(ParentState.READY, oj.lastStateEvent().getState()); oj.destroy(); } /** * Test Oddjob can be rerun after a configuration * failure using a soft reset. * */ public void testSoftResetOnFailure() { String xml = "<oddjob>" + " <job>" + " <idontexist/>" + " </job>" + "</oddjob>"; Oddjob oj = new Oddjob(); oj.setConfiguration(new XMLConfiguration("XML", xml)); oj.run(); assertEquals(ParentState.EXCEPTION, oj.lastStateEvent().getState()); String xml2 = "<oddjob xmlns:state='http://rgordon.co.uk/oddjob/state'>" + " <job>" + " <state:flag state='COMPLETE'/>" + " </job>" + "</oddjob>"; oj.setConfiguration(new XMLConfiguration("XML", xml2)); oj.load(); assertEquals(ParentState.EXCEPTION, oj.lastStateEvent().getState()); oj.softReset(); assertEquals(ParentState.READY, oj.lastStateEvent().getState()); oj.run(); assertEquals(ParentState.COMPLETE, oj.lastStateEvent().getState()); oj.destroy(); } /** * Test loading an Oddjob without a child. * @throws ArooaParseException * */ public void testLoadNoChild() throws ArooaParseException { String config = "<oddjob id='this'/>"; Oddjob test = new Oddjob(); test.setConfiguration(new XMLConfiguration("XML", config)); test.load(); Object root = new OddjobLookup(test).lookup("this"); assertEquals(Oddjob.OddjobRoot.class, root.getClass()); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.hardReset(); test.load(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.destroy(); } public void testLoadNoFile() { OurDirs ourDirs = new OurDirs(); File file = ourDirs.relative("work/oddjob-test.xml"); file.delete(); Oddjob test = new Oddjob(); test.setFile(file); test.load(); assertEquals(ParentState.READY, OddjobTestHelper.getJobState(test)); assertTrue(file.exists()); test.destroy(); } /** * Test a nested Oddjob. * @throws ArooaParseException * */ public void testLoadNestedOddjob() throws ArooaParseException { String config = "<oddjob>" + " <job>" + " <oddjob id='nested' " + " xmlns:arooa='http://rgordon.co.uk/oddjob/arooa'>" + " <configuration>" + " <xml>" + " <oddjob/>" + " </xml>" + " </configuration>" + " </oddjob>" + " </job>" + "</oddjob>"; Oddjob oj = new Oddjob(); oj.setConfiguration(new XMLConfiguration("XML", config)); oj.load(); assertEquals(ParentState.READY, oj.lastStateEvent().getState()); Oddjob test = (Oddjob) new OddjobLookup(oj).lookup("nested"); assertNotNull("Nested oddjob", test); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.hardReset(); test.load(); assertEquals(ParentState.READY, test.lastStateEvent().getState()); oj.destroy(); } public void testLoadOddjobClassloader() throws ArooaConversionException { String config = "<oddjob>" + " <job>" + " <oddjob id='nested'>" + " <classLoader>" + " <bean class='" + URLClassLoaderType.class.getName() + "'>" + " <files>" + " <files files='build/*.jar'/>" + " </files>" + " </bean>" + " </classLoader>" + " </oddjob>" + " </job>" + "</oddjob>"; Oddjob oj = new Oddjob(); oj.setConfiguration(new XMLConfiguration("XML", config)); oj.load(); String nestedConf = "<oddjob/>"; Oddjob test = new OddjobLookup(oj).lookup("nested", Oddjob.class); test.setConfiguration(new XMLConfiguration("TEST", nestedConf)); test.load(); assertNotNull("Nested classloader", test.getClassLoader()); oj.destroy(); } /** * Test a nested lookup. * @throws Exception */ public void testLookup() throws Exception { String nested = "<oddjob>" + " <job>" + " <echo id='fruits'>apple</echo>" + " </job>" + "</oddjob>"; String config = "<oddjob id='this'>" + " <job>" + " <oddjob id='nested'>" + " <configuration>" + " <value value='${inner-config}'/>" + " </configuration>" + " </oddjob>" + " </job>" + "</oddjob>"; Oddjob oj = new Oddjob(); oj.setConfiguration(new XMLConfiguration("XML", config)); XMLConfigurationType configType = new XMLConfigurationType(); configType.setXml(nested); oj.setExport("inner-config", configType); assertTrue(oj.isLoadable()); oj.load(); assertFalse(oj.isLoadable()); Loadable loadable = (Loadable) new OddjobLookup(oj).lookup("nested"); loadable.load(); String fruit = new OddjobLookup(oj).lookup( "nested/fruits.text", String.class); assertEquals("apple", fruit); oj.destroy(); // Wrong! assertTrue(oj.isLoadable()); } public void testArgs() throws Exception { String config = "<oddjob id='this'>" + " <job>" + " <variables id='fruits'>" + " <fruit>" + " <value value='${this.args[0]}'/>" + " </fruit>" + " </variables>" + " </job>" + "</oddjob>"; Oddjob oj = new Oddjob(); oj.setConfiguration(new XMLConfiguration("XML", config)); oj.setArgs(new String[] { "apple" }); oj.load(); Runnable variables = (Runnable) new OddjobLookup(oj).lookup("fruits"); variables.run(); String fruit = new OddjobLookup(oj).lookup("fruits.fruit", String.class); assertEquals("apple", fruit); oj.destroy(); } public void testSetArgs() { String config = "<oddjob>" + " <job>" + " <oddjob id='nested'>" + " <args>" + " <list>" + " <values>" + " <value value='apple'/>" + " </values>" + " </list>" + " </args>" + " <configuration>" + " <xml>" + " <oddjob/>" + " </xml>" + " </configuration>" + " </oddjob>" + " </job>" + "</oddjob>"; Oddjob oj = new Oddjob(); oj.setConfiguration(new XMLConfiguration("XML", config)); oj.load(); Loadable loadable = (Loadable) new OddjobLookup(oj).lookup("nested"); assertTrue(loadable.isLoadable()); loadable.load(); assertFalse(loadable.isLoadable()); assertEquals("apple", new OddjobLookup(oj).lookup("nested.args[0]")); oj.destroy(); } public void testExport() throws Exception { String config = "<oddjob>" + " <job>" + " <oddjob id='nested'>" + " <export>" + " <value key='fruit' value='apple'/>" + " </export>" + " <configuration>" + " <xml>" + "<oddjob>" + " <job>" + " <variables id='fruits'>" + " <fruit>" + " <value value='${fruit}'/>" + " </fruit>" + " </variables>" + " </job>" + "</oddjob>" + " </xml>" + " </configuration>" + " </oddjob>" + " </job>" + "</oddjob>"; Oddjob oj = new Oddjob(); oj.setConfiguration(new XMLConfiguration("XML", config)); oj.load(); Loadable loadable = (Loadable) new OddjobLookup(oj).lookup("nested"); loadable.load(); Runnable runnable = (Runnable) new OddjobLookup(oj).lookup("nested/fruits"); runnable.run(); String fruit = new OddjobLookup(oj).lookup( "nested/fruits.fruit", String.class); assertEquals("apple", fruit); oj.destroy(); } /** * Test Component Registry management. Test Oddjob * adds and clears up it's children OK. * @throws ArooaParseException * */ public void testRegistryManagement() throws ArooaParseException { final ArooaSession session = new OddjobSessionFactory().createSession(); class OurContext extends MockArooaContext { @Override public ArooaSession getSession() { return session; } @Override public RuntimeConfiguration getRuntime() { return new MockRuntimeConfiguration() { @Override public void configure() throws ArooaException { } }; } } Oddjob oj = new Oddjob(); oj.setArooaSession(session); ComponentPool pool = session.getComponentPool(); pool.registerComponent( new ComponentTrinity( oj, oj, new OurContext()) , "oj"); String xml = "<oddjob>" + " <job>" + " <echo id='echo'>Hello</echo>" + " </job>" + "</oddjob>"; oj.setConfiguration(new XMLConfiguration("XML", xml)); BeanDirectory dir = session.getBeanRegistry(); assertEquals(null, dir.lookup("oj/echo")); oj.load(); assertNotNull(dir.lookup("oj/echo")); oj.hardReset(); assertEquals(null, dir.lookup("oj/echo")); oj.load(); assertNotNull(dir.lookup("oj/echo")); oj.destroy(); } public static class ReluctantToDie extends SimpleJob { boolean die; @Override protected int execute() throws Throwable { return 0; } @Override public void onDestroy() { super.onDestroy(); if (!die) { die = true; throw new IllegalStateException("I'm not ready to die."); } } } public void testFailedDestroy() { String xml = "<oddjob>" + " <job>" + " <bean class='" + ReluctantToDie.class.getName() + "'/>" + " </job>" + "</oddjob>"; Oddjob test = new Oddjob(); test.setConfiguration(new XMLConfiguration("XML", xml)); test.load(); try { test.destroy(); fail("Exception expected."); } catch (IllegalStateException e) { // expected. } assertFalse(test.isLoadable()); assertEquals(ParentState.READY, test.lastStateEvent().getState()); test.destroy(); assertEquals(ParentState.DESTROYED, test.lastStateEvent().getState()); } }