/******************************************************************************* * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved. * This program and the accompanying materials are made available under the terms * of the Eclipse Public License v1.0 which accompanies this distribution, and is * available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tm.te.core.async; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobManager; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.tm.te.core.async.interfaces.IAsyncExecutable; import org.eclipse.tm.te.runtime.callback.Callback; import org.eclipse.tm.te.runtime.interfaces.IConditionTester; import org.eclipse.tm.te.runtime.interfaces.callback.ICallback; import org.eclipse.tm.te.runtime.utils.ProgressHelper; /** * Abstract asynchronous executable job implementation. */ public abstract class AbstractAsyncExecutableJob extends Job implements IAsyncExecutable { /** * Job family id to identify jobs based on {@link AbstractAsyncExecutableJob}. * * @see IJobManager */ public final String ID = "jobfamily.jobs.asynchronous"; //$NON-NLS-1$ private int rescheduleDelay = -1; private boolean cancelable = true; protected boolean finished = false; private boolean statusHandled = false; private String jobFamily = null; private ICallback jobCallback = null; /** * Constructor. * * @param name The job name. * @param context The context to refresh. * @param mode The refresh mode. */ protected AbstractAsyncExecutableJob(String name) { super(name); setPriority(Job.INTERACTIVE); setJobFamily(ID); } /** * Set the delay if the job should be rescheduled. * @param seconds The reschedule delay or <code>-1</code> if job should not be rescheduled. */ public final void setRescheduleDelay(int seconds) { this.rescheduleDelay = seconds; } /** * Return the delay in seconds until the job should be rescheduled. */ public final int getRescheduleDelay() { return rescheduleDelay; } /** * Sets if the result status should be handled by the job manager. * @param handled <code>true</code> if the job manager should not handle the result status. */ protected void setStatusHandled(boolean handled) { this.statusHandled = handled; } /** * Set if the job can be canceled. * @param cancelable <code>true</code> if the job should be cancelable. */ public final void setCancelable(boolean cancelable) { this.cancelable = cancelable; } /** * Return <code>true</code> if the job can be canceled. */ public final boolean isCancelable() { return cancelable; } /** * Set the callback for the job. * @param callback The callback. */ public final void setJobCallback(ICallback callback) { this.jobCallback = callback; } /** * Return the job callback. */ public final ICallback getJobCallback() { return jobCallback; } /** * Return <code>true</code> if the job is finished. */ public final boolean isFinished() { return finished; } /** * Set the job family to identify a job using <code>belongsTo(Object family)</code>. * @param jobFamily The job family or <code>null</code>. */ public final void setJobFamily(String jobFamily) { this.jobFamily = jobFamily; } /** * Return the job family. */ public final String getJobFamily() { return jobFamily; } /* (non-Javadoc) * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object) */ @Override public boolean belongsTo(Object family) { if (family instanceof String && getJobFamily() != null && getJobFamily().startsWith(family.toString())) { return true; } return super.belongsTo(family); } /** * Number of ticks the job uses to show the progress. * * @return The number of progress ticks. */ protected abstract int getJobTicks(); /* (non-Javadoc) * @see org.eclipse.tm.te.core.async.interfaces.IAsyncExecutable#execute(org.eclipse.tm.te.runtime.interfaces.callback.ICallback) */ @Override public final void execute(ICallback callback) { execute(null, ProgressHelper.PROGRESS_NONE, callback); } /* (non-Javadoc) * @see org.eclipse.tm.te.core.async.interfaces.IAsyncExecutable#execute(org.eclipse.core.runtime.IProgressMonitor, int, org.eclipse.tm.te.runtime.interfaces.callback.ICallback) */ @Override public final void execute(IProgressMonitor progress, int ticksToUse, ICallback callback) { finished = false; progress = ProgressHelper.getProgressMonitor(progress, ticksToUse); int jobTicks = getJobTicks(); ProgressHelper.beginTask(progress, "", jobTicks); //$NON-NLS-1$ callback = new Callback(progress, ProgressHelper.PROGRESS_DONE, callback); if (getJobCallback() != null && getJobCallback() != callback) { callback.addParentCallback(getJobCallback()); } internalExecute(progress, new Callback(progress, ProgressHelper.PROGRESS_DONE, callback) { @Override protected void internalDone(Object caller, IStatus status) { finished = true; } }); } /** * The job itself. * * @param monitor The progress monitor (never <code>null</code>). * @param callback The callback. */ protected abstract void internalExecute(final IProgressMonitor monitor, final ICallback callback); /** * Hold the execution of {@link #run(IProgressMonitor)} until the asynchronous executable * has completed the execution and invoked the callback. * * @param timeout The timeout in milliseconds. <code>0</code> means wait forever. * @param conditionTester The condition tester which condition must be fulfilled until * the execution hold of {@link #run(IProgressMonitor)} can be released. */ protected abstract void waitAndExecute(long timeout, IConditionTester conditionTester); /* (non-Javadoc) * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) */ @Override protected final IStatus run(final IProgressMonitor monitor) { finished = false; int jobTicks = getJobTicks(); ProgressHelper.beginTask(monitor, "", jobTicks); //$NON-NLS-1$ final Callback callback = new Callback(monitor, ProgressHelper.PROGRESS_DONE, getJobCallback()); internalExecute(monitor, callback); waitAndExecute(0, callback.getDoneConditionTester(isCancelable() ? monitor : null)); finished = true; if (getRescheduleDelay() >= 0 && Platform.isRunning() && (!isCancelable() || !monitor.isCanceled())) { schedule(getRescheduleDelay() * 1000); } return statusHandled ? Status.OK_STATUS : callback.getStatus(); } }