/*
* Carrot2 project.
*
* Copyright (C) 2002-2016, Dawid Weiss, Stanisław Osiński.
* All rights reserved.
*
* Refer to the full license file "carrot2.LICENSE"
* in the root folder of the repository checkout or at:
* http://www.carrot2.org/carrot2.LICENSE
*/
package org.carrot2.workbench.core.helpers;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
/**
* Superclass of jobs that can be dynamically <i>postponed</i> (their execution schedule
* can be dynamically changed).
* <p>
* This class is not a subclass of {@link Job} because scheduling methods in {@link Job}
* are final and this could be confusing. Instead, pass the job to be executed
* after a certain delay.
*/
public class PostponableJob
{
/** Internal synchronization lock. */
private final Object jobLock = new Object();
/** Postponable delay job. */
private Job job;
/** Actual job to execute. */
private final AtomicReference<Job> jobRef = new AtomicReference<>();
public PostponableJob(Job actualJob)
{
setJob(actualJob);
}
public PostponableJob() {
}
protected final void setJob(Job actualJob)
{
if (!this.jobRef.compareAndSet(null, actualJob))
{
throw new IllegalStateException("Can't set jobs twice.");
}
}
/**
* Schedule (or postpone) the job to execute after a given delay. Any previous
* pending job is canceled.
*/
public final void reschedule(int delay)
{
final Job actualJob = jobRef.get();
if (actualJob == null) {
throw new IllegalStateException("Job not set.");
}
final Job newJob = new Job(actualJob.getName() + " (Delayed)")
{
protected IStatus run(IProgressMonitor monitor)
{
synchronized (jobLock)
{
if (job == this)
{
actualJob.schedule();
return Status.OK_STATUS;
}
else
{
return Status.CANCEL_STATUS;
}
}
}
};
newJob.setPriority(Job.INTERACTIVE);
// System jobs are not visible in the GUI. I leave it for now, it's quite
// interesting to see auto update tasks in the jobs panel.
//
// newJob.setSystem(true);
synchronized (jobLock)
{
/*
* Cancel previous job, but start the new one regardless of the previous job's
* running state.
*/
if (job != null && job.getState() == Job.SLEEPING)
{
job.cancel();
}
job = newJob;
job.schedule(delay);
}
}
}