package org.oddjob.jobs.job; import org.oddjob.FailedToStopException; import org.oddjob.Stoppable; import org.oddjob.arooa.deploy.annotations.ArooaAttribute; import org.oddjob.framework.SerializableJob; import org.oddjob.jmx.JMXClientJob; /** * @oddjob.description A job which stops another job. * <p> * Normally The stop job will not complete until the job it is * stopping is in a not executing state. Therefore if the * stop job is attempting to stop a parent job of itself the stop * job could block indefinitely. This case is detected and the job * enters an Exception state. * * @oddjob.example * * Examples elsewhere. * <ul> * <li>{@link JMXClientJob} has an example where the stop * job is used to stop a client once the connection is no * longer needed.</li> * </ul> * * @author Rob Gordon */ public class StopJob extends SerializableJob implements Stoppable { private static final long serialVersionUID = 20050806; /** * @oddjob.property * @oddjob.description Job to stop * @oddjob.required Yes. */ private transient Stoppable job; /** Used to check we're not stopping ourself. */ private transient volatile Thread thread; /** * Set the stop node directly. * * @param node The node to stop. */ @ArooaAttribute public void setJob(Stoppable node) { this.job = node; } /** * Get the node to stop. * * @return The node. */ public Stoppable getJob() { return this.job; } /* * (non-Javadoc) * @see org.oddjob.jobs.AbstractJob#execute() */ protected int execute() throws Exception { if (job == null) { throw new NullPointerException("No Job to Stop"); } logger().info("Stopping [" + job + "]"); thread = Thread.currentThread(); try { job.stop(); } finally { thread = null; } return 0; } @Override protected void onStop() throws FailedToStopException { if (thread == Thread.currentThread()) { throw new FailedToStopException(this, "Can't stop ourself. " + "Maybe use a trigger to stop asynchronously."); } } }