package er.quartzscheduler.foundation;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.InterruptableJob;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.UnableToInterruptJobException;
import com.webobjects.eoaccess.EOUtilities;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.eocontrol.EOGlobalID;
import com.webobjects.foundation.NSTimestamp;
@DisallowConcurrentExecution
public abstract class ERQSJob extends ERQSAbstractJob implements InterruptableJob
{
public static final String ENTERPRISE_OBJECT_KEY = "eoJobKey";
public static final String NOT_PERSISTENT_OBJECT_KEY = "jobKey";
private ERQSJobDescription jobDescription;
private boolean jobInterrupted = false;
/**
* Implementation of Job interface.
* Called by the Scheduler when a Trigger associated with the job is fired.<br>
* getJobContext() returns the jobContext after execute() is called.<p>
* To be sure that any exception will be catched, _execute() call in surround by a try/catch block.
*
* @param jobexecutioncontext passed by the scheduler
* @see <a href="http://quartz-scheduler.org/documentation/best-practices">http://quartz-scheduler.org/documentation/best-practices</a>
*/
@Override
public final void execute(final JobExecutionContext jobexecutioncontext) throws JobExecutionException
{
super.execute(jobexecutioncontext);
try
{
_execute();
} catch (Exception e)
{
log.error("method: execute: " + e.getMessage(), e);
}
}
/**
* _execute() is called by execute(). Put your code here and everything will be set up for you.
*
* @throws JobExecutionException
*
*/
protected abstract void _execute() throws JobExecutionException;
/**
* It's a good place to put code that will be executed before job description deletion.<p>
* Nothing is done automatically, you have to call this method manually if you want to give a chance to the job to
* use its own logic.
*
* @param aJobDescription
*/
public abstract void willDelete(ERQSJobDescription aJobDescription);
/**
* It's a good place to put code that will be executed before job description save.<p>
* Nothing is done automatically, you have to call this method manually if you want to give a chance to the job to
* use its own logic.
*
* @param aJobDescription
*/
public abstract void willSave(ERQSJobDescription aJobDescription);
/**
* It's a good place to put code that will check if the job description can be saved or not.<p>
* Nothing is done automatically, you have to call this method manually if you want to give a chance to the job to
* use its own logic.
*
* @param aJobDescription
*/
public abstract void validateForSave(ERQSJobDescription aJobDescription);
/**
* It's a good place to put code that will check if the job description can be deleted or not.<p>
* Nothing is done automatically, you have to call this method manually if you want to give a chance to the job to
* use its own logic.
*
* @param aJobDescription
*/
public abstract void validateForDelete(ERQSJobDescription aJobDescription);
/**
* Send back the ERQSJobDescription Object attach to the job.
*
* @param ec editingContext (can be null if the NOScheduler object has been already defaulted)
* @return the NOScheduler Object.
* @throws IllegalStateException if there is no EOGlobalID in the JobDataMap or if ec is null and ERQSJobDescription object isn't already defaulted
*/
public ERQSJobDescription getJobDescription(final EOEditingContext ec)
{
if (jobDescription == null && ec == null)
throw new IllegalStateException("method: getJobDescription: jobDescription is null and ec as parameter is null too.");
ERQSJobDescription aJobDescription;
if (jobDescription == null)
{
JobExecutionContext context = getJobContext();
if (context.getMergedJobDataMap() != null)
{
EOGlobalID id = (EOGlobalID) context.getMergedJobDataMap().get(ENTERPRISE_OBJECT_KEY);
if (id != null)
jobDescription = (ERQSJobDescription) ec.faultForGlobalID(id, ec);
else
jobDescription = (ERQSJobDescription) context.getMergedJobDataMap().get(NOT_PERSISTENT_OBJECT_KEY);
if (jobDescription == null)
throw new IllegalStateException("method: getJobDescription: unknown jobDescription.");
}
else
{
throw new IllegalStateException("method: getJobDescription: no job detail or job data map. The jobDescription is still null.");
}
aJobDescription = jobDescription;
}
else
{
aJobDescription = jobDescription;
// if ec is not null, we make a local instance
if (aJobDescription.isEnterpriseObject() && ec != null)
aJobDescription = (ERQSJobDescription) EOUtilities.localInstanceOfObject(ec, (EOEnterpriseObject)aJobDescription);
}
if (log.isDebugEnabled())
log.debug("method: getNOScheduler: noScheduler: " + jobDescription);
return aJobDescription;
}
public ERQSJobDescription getJobDescription()
{
return getJobDescription(null);
}
public NSTimestamp getLastExecutionDate()
{
return getJobDescription().lastExecutionDate();
}
/**
* Called by the <code>{@link Scheduler}</code> when a user interrupts the <code>Job</code>.
* return void (nothing) if job interrupt is successful.
*
* @throws JobExecutionException
* if there is an exception while interrupting the job.
*/
public void interrupt() throws UnableToInterruptJobException
{
log.info("method: interrupt has been called for the job: " + getJobDescription());
jobInterrupted = true;
}
protected boolean isJobInterrupted()
{
return jobInterrupted;
}
}