package org.oddjob.scheduling; import java.beans.PropertyVetoException; import java.text.ParseException; import java.util.Date; import junit.framework.TestCase; import org.apache.log4j.Logger; import org.oddjob.FailedToStopException; import org.oddjob.Oddjob; import org.oddjob.OddjobLookup; import org.oddjob.Resetable; import org.oddjob.Stateful; import org.oddjob.arooa.convert.ArooaConversionException; import org.oddjob.arooa.reflect.ArooaPropertyException; import org.oddjob.arooa.types.ArooaObject; import org.oddjob.arooa.utils.DateHelper; import org.oddjob.arooa.xml.XMLConfiguration; import org.oddjob.framework.SerializableJob; import org.oddjob.persist.ArchiveBrowserJob; import org.oddjob.persist.MapPersister; import org.oddjob.scheduling.state.TimerState; import org.oddjob.state.JobState; import org.oddjob.state.ParentState; import org.oddjob.tools.ManualClock; import org.oddjob.tools.OddjobTestHelper; import org.oddjob.tools.StateSteps; import org.oddjob.util.Clock; /** * Timer and Retry will often be used in combination. Here's some * examples. * * @author rob * */ public class TimerRetryCombinationTest extends TestCase { private static final Logger logger = Logger.getLogger(TimerRetryCombinationTest.class); @Override protected void setUp() throws Exception { super.setUp(); logger.info("--------------------- " + getName() + " --------------"); } public static class Results extends SerializableJob { private static final long serialVersionUID = 2009081400L; private volatile int soft; private volatile int hard; private volatile int executions; private volatile int result; @Override protected int execute() throws Throwable { logger.info("RUNNING!!!"); ++executions; return result; } @Override public boolean hardReset() { if (super.hardReset()) { logger.info("HARD RESET"); synchronized (this) { hard++; } return true; } return false; } @Override public boolean softReset() { if (super.softReset()) { logger.info("SOFT RESET"); synchronized (this) { soft++; } return true; } return false; } public synchronized int getSoft() { return soft; } public synchronized int getHard() { return hard; } public int getExecutions() { return executions; } public int getResult() { return result; } public void setResult(int result) { this.result = result; } } public void testContextReset() throws ArooaConversionException, PropertyVetoException, InterruptedException { XMLConfiguration config = new XMLConfiguration( "org/oddjob/scheduling/TimerRetryCombinationTest1.xml", getClass().getClassLoader()); DefaultExecutors services = new DefaultExecutors(); MapPersister persister = new MapPersister(); persister.setPath("testContextReset"); Oddjob oddjob1 = new Oddjob(); oddjob1.setOddjobExecutors(services); oddjob1.setConfiguration(config); oddjob1.setPersister(persister); // OddjobExplorer explorer = new OddjobExplorer(); // explorer.setOddjob(oddjob1); // explorer.setArooaSession(new StandardArooaSession()); // explorer.run(); logger.info("First Oddjob, starting first run."); StateSteps oddjob1State = new StateSteps(oddjob1); oddjob1State.startCheck(ParentState.READY, ParentState.EXECUTING, ParentState.ACTIVE, ParentState.INCOMPLETE); oddjob1.run(); oddjob1State.checkWait(); OddjobLookup lookup1 = new OddjobLookup(oddjob1); int hards1 = lookup1.lookup("results.hard", Integer.TYPE); int softs1 = lookup1.lookup("results.soft", Integer.TYPE); int executions = lookup1.lookup("results.executions", Integer.TYPE); assertEquals(4, hards1); assertEquals(8, softs1); assertEquals(8, executions); oddjob1.softReset(); hards1 = lookup1.lookup("results.hard", Integer.TYPE); softs1 = lookup1.lookup("results.soft", Integer.TYPE); executions = lookup1.lookup("results.executions", Integer.TYPE); assertEquals(4, hards1); assertEquals(9, softs1); assertEquals(8, executions); logger.info("First Oddjob, starting second run."); oddjob1State.startCheck(ParentState.READY, ParentState.EXECUTING, ParentState.ACTIVE, ParentState.INCOMPLETE); oddjob1.run(); oddjob1State.checkWait(); hards1 = lookup1.lookup("results.hard", Integer.TYPE); softs1 = lookup1.lookup("results.soft", Integer.TYPE); executions = lookup1.lookup("results.executions", Integer.TYPE); assertEquals(8, hards1); assertEquals(17, softs1); assertEquals(16, executions); Resetable timer = lookup1.lookup("timer", Resetable.class); timer.hardReset(); oddjob1.destroy(); Oddjob oddjob2 = new Oddjob(); oddjob2.setOddjobExecutors(services); oddjob2.setConfiguration(config); oddjob2.setPersister(persister); logger.info("Second Oddjob, starting first run."); StateSteps oddjob2State = new StateSteps(oddjob2); oddjob2State.startCheck(ParentState.READY, ParentState.EXECUTING, ParentState.ACTIVE, ParentState.INCOMPLETE); oddjob2.run(); oddjob2State.checkWait(); OddjobLookup lookup2 = new OddjobLookup(oddjob2); int hards2 = lookup2.lookup("results.hard", Integer.TYPE); int softs2 = lookup2.lookup("results.soft", Integer.TYPE); int executions2 = lookup2.lookup("results.executions", Integer.TYPE); assertEquals(12, hards2); assertEquals(25, softs2); assertEquals(24, executions2); oddjob2.destroy(); services.stop(); } public void testStateNotifications() throws FailedToStopException, InterruptedException { XMLConfiguration config = new XMLConfiguration( "org/oddjob/scheduling/TimerRetryCombinationTest1.xml", getClass().getClassLoader()); DefaultExecutors services = new DefaultExecutors(); Oddjob oddjob1 = new Oddjob(); oddjob1.setOddjobExecutors(services); oddjob1.setConfiguration(config); StateSteps ojStates = new StateSteps(oddjob1); oddjob1.load(); Timer timer = (Timer) new OddjobLookup(oddjob1).lookup("timer"); StateSteps timerStates = new StateSteps(timer); Retry retry = (Retry) new OddjobLookup(oddjob1).lookup("retry"); StateSteps retryStates = new StateSteps(retry); ojStates.startCheck(ParentState.READY, ParentState.EXECUTING, ParentState.ACTIVE, ParentState.INCOMPLETE); timerStates.startCheck(TimerState.STARTABLE, TimerState.STARTING, TimerState.ACTIVE, TimerState.INCOMPLETE); retryStates.startCheck(TimerState.STARTABLE, TimerState.STARTING, TimerState.ACTIVE, TimerState.INCOMPLETE, TimerState.STARTABLE, TimerState.STARTING, TimerState.ACTIVE, TimerState.INCOMPLETE, TimerState.STARTABLE, TimerState.STARTING, TimerState.ACTIVE, TimerState.INCOMPLETE, TimerState.STARTABLE, TimerState.STARTING, TimerState.ACTIVE, TimerState.INCOMPLETE); oddjob1.run(); ojStates.checkWait(); // Note we still need to wait because these state listeners maybe // notified after Oddjob has received the incomplete state. timerStates.checkWait(); retryStates.checkWait(); logger.info("Cleaning Up."); oddjob1.destroy(); services.stop(); } private class OurClock implements Clock { Date date; @Override public Date getDate() { return date; } } /** * Tracking down a bug where examples didn't run when catching up. * @throws ParseException * @throws InterruptedException */ public void testRetriesWithCatchup() throws ArooaConversionException, PropertyVetoException, ParseException, InterruptedException { XMLConfiguration config = new XMLConfiguration( "org/oddjob/scheduling/TimerRetryCombinationTest2.xml", getClass().getClassLoader()); MapPersister persister = new MapPersister(); persister.setPath("testContextReset"); OurClock clock = new OurClock(); clock.date = DateHelper.parseDateTime("2010-07-11 07:00"); Oddjob oddjob1 = new Oddjob(); oddjob1.setConfiguration(config); oddjob1.setPersister(persister); oddjob1.setExport("clock", new ArooaObject(clock)); StateSteps oddjob1States = new StateSteps(oddjob1); oddjob1States.startCheck(ParentState.READY, ParentState.EXECUTING, ParentState.ACTIVE, ParentState.STARTED); logger.info("** Starting First Oddjob. **"); oddjob1.run(); oddjob1States.checkWait(); // OddjobExplorer explorer = new OddjobExplorer(); // explorer.setOddjob(oddjob1); // explorer.setArooaSession(new StandardArooaSession()); // explorer.run(); final OddjobLookup lookup1 = new OddjobLookup(oddjob1); assertEquals(DateHelper.parseDateTime("2010-07-12 07:00"), lookup1.lookup("timer.nextDue", Date.class)); int hards1 = lookup1.lookup("results.hard", Integer.TYPE); int softs1 = lookup1.lookup("results.soft", Integer.TYPE); int executions1 = lookup1.lookup("results.executions", Integer.TYPE); assertEquals(1, hards1); assertEquals(1, softs1); assertEquals(1, executions1); // The archive state listener is added after oddjob child state // reflector so the archiver could still be archiving at this // point. This will ensure all listeners have fired before we // destroy. assertEquals(TimerState.COMPLETE, lookup1.lookup("retry", Stateful.class).lastStateEvent().getState()); oddjob1.destroy(); Oddjob oddjob2 = new Oddjob(); oddjob2.setConfiguration(config); oddjob2.setPersister(persister); oddjob2.setExport("clock", new ArooaObject(clock)); clock.date = DateHelper.parseDateTime("2010-07-15 07:00"); StateSteps oddjob2States = new StateSteps(oddjob2); oddjob2States.startCheck(ParentState.READY, ParentState.EXECUTING, ParentState.ACTIVE, ParentState.STARTED); logger.info("** Starting second Oddjob. **"); oddjob2.run(); oddjob2States.checkWait(); final OddjobLookup lookup2 = new OddjobLookup(oddjob2); assertEquals(DateHelper.parseDateTime("2010-07-16 07:00"), lookup2.lookup("timer.nextDue", Date.class)); int hards2 = lookup2.lookup("results.hard", Integer.TYPE); int softs2 = lookup2.lookup("results.soft", Integer.TYPE); int executions2 = lookup2.lookup("results.executions", Integer.TYPE); assertEquals(5, hards2); assertEquals(5, softs2); assertEquals(5, executions2); // Ensure archiver finished persisting. assertEquals(TimerState.COMPLETE, lookup2.lookup("retry", Stateful.class).lastStateEvent().getState()); ArchiveBrowserJob browser = new ArchiveBrowserJob(); browser.setArchiver(persister); browser.setArchiveName("the-archive"); logger.info("** Running Archive Browser. **"); browser.run(); Object[] children = OddjobTestHelper.getChildren(browser); assertEquals(5, children.length); assertEquals("20100711", children[0].toString()); assertEquals("20100712", children[1].toString()); assertEquals("20100713", children[2].toString()); assertEquals("20100714", children[3].toString()); assertEquals("20100715", children[4].toString()); oddjob2.destroy(); } public void testSimpleTimerRetryExample() throws ArooaPropertyException, ArooaConversionException, InterruptedException, ParseException, FailedToStopException { Oddjob oddjob = new Oddjob(); oddjob.setConfiguration(new XMLConfiguration( "org/oddjob/scheduling/SimpleTimerWithRetry.xml", getClass().getClassLoader())); oddjob.load(); assertEquals(ParentState.READY, oddjob.lastStateEvent().getState()); OddjobLookup lookup = new OddjobLookup(oddjob); Timer timer = lookup.lookup("timer", Timer.class); timer.setClock(new ManualClock("2011-09-30 12:00")); Stateful flagJob = lookup.lookup("flag-job", Stateful.class); StateSteps states = new StateSteps(flagJob); states.startCheck(JobState.READY, JobState.EXECUTING, JobState.EXCEPTION, JobState.READY, JobState.EXECUTING, JobState.EXCEPTION); oddjob.run(); states.checkWait(); assertEquals(DateHelper.parseDateTime("2011-10-01 08:00"), timer.getNextDue()); oddjob.stop(); assertEquals(ParentState.READY, oddjob.lastStateEvent().getState()); timer.setClock(new ManualClock("2011-10-01 07:59:59.990")); states.startCheck(JobState.EXCEPTION, JobState.READY, JobState.EXECUTING, JobState.EXCEPTION, JobState.READY, JobState.EXECUTING, JobState.EXCEPTION); oddjob.run(); states.checkWait(); assertEquals(DateHelper.parseDateTime("2011-10-02 08:00"), timer.getNextDue()); oddjob.destroy(); } }