package org.oddjob.state; import java.io.Serializable; import java.util.Date; import org.oddjob.Stateful; import org.oddjob.util.IO; /** * An instance of this class is produced when a job state changes. It is * passed to all JobStateListeners. * <p> * * @author Rob Gordon */ public class StateEvent { public static final String REPLACEMENT_EXCEPTION_TEXT = "Exception is not serializable, message is: "; /** The source. Note that the source in {@link java.util.EventObject} is * not final and so safe publication to other threads is not * guaranteed. */ private final Stateful source; /** The state */ private final State state; /** The time the state changed. */ private final Date time; /** Any exception that caused an exception state. */ private final Throwable exception; /** * Constructor. * * @param source The source of the event. * @param state The state. * @param time the Time of the event. * @param exception The exception if applicable, or null otherwise. */ public StateEvent(Stateful source, State state, Date time, Throwable exception) { if (state == null) { throw new NullPointerException("JobState can not be null!"); } this.source = source; this.state = state; this.time = time; this.exception = exception; } /** * Constructor. * * @param job The source of the event. * @param jobState The state. * @param exception The exception if applicable, or null otherwise. */ public StateEvent(Stateful job, State jobState, Throwable exception) { this(job, jobState, new Date(), exception); } /** * Constructor. * * @param job The source of the event. * @param jobState The state. */ public StateEvent(Stateful job, State jobState) { this(job, jobState, null); } public Stateful getSource() { return source; } /** * Get the job state. * * @return The job state. */ public State getState() { return state; } /** * Get the exception if applicable, null otherwise. * * @return The exception of null. */ public Throwable getException() { return exception; } /** * Get the time of the event.. * * @return The time. */ public Date getTime() { return time; } /** * Provide something that can be serialised. Note the we do not use * {@code writeReplace} because there the corresponding * {@code readResolve} * * @return */ public SerializableNoSource serializable() { return new SerializableNoSource(getState(), getTime(), getException()); } /** * Override toString. */ public String toString() { return "JobStateEvent, source=" + getSource() + ", " + state; } /** * Used to replace a non serializable exception. * */ static class ExceptionReplacement extends Exception { private static final long serialVersionUID = 20051217; public ExceptionReplacement(Throwable replacing) { super(REPLACEMENT_EXCEPTION_TEXT + replacing.getMessage()); super.setStackTrace(replacing.getStackTrace()); } } /** * Used to persist the event. There is no {@code ReadResolve} method * because it is not possible to resolve without the Stateful source. * <p> * */ public static class SerializableNoSource implements Serializable { private static final long serialVersionUID = 2014050700L; private final State state; private final Date time; private final Throwable exception; public SerializableNoSource(State state, Date date, Throwable exception) { this.state = state; this.time = date; if (IO.canSerialize(exception)) { this.exception = exception; } else { this.exception = new ExceptionReplacement(exception); } } public State getState() { return state; } public Date getTime() { return time; } public Throwable getException() { return exception; } } }