So far we've written a nice job that run's without errors - but what happens if something goes wrong?
Oddjob will catch all Throwables during job execution and set the job state to Exception. Let see with an example.
package org.oddjob.devguide;
public class NaughtyJob implements Runnable {
    public void run() {
        throw new RuntimeException("I won't run. I won't!");
    }
}
		And run it...
				
		You can try resetting the job and re-running it however this job will not start behaving! The import thing is that it's naughtiness is contained.
Oddjob will also recognise the result property and use it to either set a job complete or not complete. If the result is 0 the job is state is complete, any other value and it's not complete.
package org.oddjob.devguide;
public class NotCompleteJob implements Runnable {
    public int getResult() {
        return 1;
    }
    
    public void run() {
    }
}
		And run it...
						
	To stop a job Oddjob will interrupt the thread it's running. Long running jobs should be written to cope with this.
Here's an example.
package org.oddjob.devguide;
public class StoppingJob implements Runnable {
    public void run() {
        synchronized(this) {
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("OK - I'll stop.");
            }
        }
    }
}
		
		Oddjob uses log4j. If
		you also use Log4j, any logging in your job's run() method
		will be captured by Oddjob and displayed in the log panel of Oddjob 
		Explorer.
		
Sometimes you don't want a job to run and complete, but to keep running in the background, probably providing some kind of service, such as Scheduling.
		Oddjob will recognise the method signature of 
		public void start() and public void stop() and
		treat that object as a service. When you run the job, the start
		method will be called, but when it returns the state will still
		be seen as executing. The service will be stopped when you
		stop the job.
		
Here's an example.
package org.oddjob.devguide;
import java.util.concurrent.CountDownLatch;
public class SimpleService {
    private volatile boolean stop;
    private volatile Thread thread;
    
    public void start() throws InterruptedException {
        
        final CountDownLatch serviceStarted = new CountDownLatch(1);
        
        thread = new Thread(new Runnable() {
            public void run() {
                while (!stop) {
                    System.out.println("I could be useful.");
                    synchronized (SimpleService.this) {
                        serviceStarted.countDown();
                        try {
                            SimpleService.this.wait();
                        } catch (InterruptedException e) {
                            break;
                        }
                    }
                }
                System.out.println("Service Stopping.");
            }});
        thread.start();
        
        serviceStarted.await();
    }
    public void stop() throws InterruptedException {
        synchronized(this) {
            stop = true;
            notifyAll();
        }
        if (thread != null) {
            thread.join();
        }
    }
}
		A service has the advantage that when used in a sequential job, jobs after the service will run once the service has started, and can then use that service for something.
Because the job that runs immediately after the service may
		consume that service, the writer of the service we must ensure
		that the service is guaranteed to be available once the 
		start method
		completes (or an Exception is thrown). In our example we ensure 
		this is case by using a 
		CountDownLatch.
		
		
The observant reader may be wondering what happens if the thread executing start has been interrupted? Won't the service be started but an Exception also thrown? Oddjob will ensure that the interrupted flag is cleared before it enters the start method so you don't need to check.
Ensuring that a service is stopped before the stop
		method completes isn't as important. It depends on the nature of
		the service. What happens if a service is stopped and started 
		quickly for instance? In our example it could be argued that it 
		wouldn't matter that a new thread was created before the previous 
		one had completed - however if we wished to write a unit test that
		relied on the order of output (which you can find in the source 
		distribution) we need to guarantee the behaviour of stop which we 
		do by using
		thread.join().
		 
Here's a configuration that uses this service.
<oddjob>
    <job>
      <sequential>
      <jobs>
        <bean id="service" class="org.oddjob.devguide.SimpleService"/>
        <echo>Service Has Started.</echo>
        <stop job="${service}"/>
        <echo>Service Has Stopped.</echo>
      </jobs>
      </sequential>
    </job>
</oddjob>
	First the service is started, next an echo tells us the service has started, then the service is stopped, and finally another echo tells us the service has stopped. Here's the result of running this configuration with Oddjob.
I could be useful. Service Has Started. Service Stopping. Service Has Stopped.
Because of the way we wrote our service this order is guaranteed.
	To summarise: You need to guarantee a service is started in 
	start() but you can
	use your discretion as to whether it's really stopped by 
	stop().
If your job implements java.io.Serializable and Oddjob is
		running with a persister then Oddjob will serialise the state of your
		job when it completes. When Oddjob next runs, it re-creates the 
		job from the serialised form.
After your job is restored, Oddjob will continue to configure your job from the configuration file. Thus any serialised properties that appear in the configuration will be overwritten.