| /********************************************************************** |
| * Copyright (c) 2003, 2004 IBM Corporation and others. All rights reserved. This |
| * program and the accompanying materials are made available under the terms of |
| * the Common Public License v1.0 which accompanies this distribution, and is |
| * available at http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| **********************************************************************/ |
| package org.eclipse.core.internal.jobs; |
| |
| import java.util.*; |
| import org.eclipse.core.internal.runtime.Assert; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.core.runtime.jobs.*; |
| |
| /** |
| * Internal implementation class for jobs. |
| */ |
| public abstract class InternalJob extends PlatformObject implements Comparable { |
| |
| /** |
| * Job state code (value 8) indicating that a job is blocked by another currently |
| * running job. From an API point of view, this is the same as WAITING. |
| */ |
| public static final int BLOCKED = 0x08; |
| /** |
| * Job state code (value 16) indicating that a job has been removed from |
| * the wait queue and is about to start running. From an API point of view, |
| * this is the same as RUNNING. |
| */ |
| public static final int ABOUT_TO_RUN = 0x10; |
| |
| /** |
| * Start time constant indicating a job should be started at |
| * a time in the infinite future, causing it to sleep forever. |
| */ |
| protected static final long T_INFINITE = Long.MAX_VALUE; |
| /** |
| * Start time constant indicating that the job has no start time. |
| */ |
| protected static final long T_NONE = -1; |
| |
| |
| //flag mask bits |
| private static final int M_STATE = 0xFF; |
| private static final int M_SYSTEM = 0x0100; |
| private static final int M_USER = 0x0200; |
| |
| private static final JobManager manager = JobManager.getInstance(); |
| private static int nextJobNumber = 0; |
| |
| private volatile int flags = Job.NONE; |
| private final int jobNumber = nextJobNumber++; |
| private List listeners; |
| private IProgressMonitor monitor; |
| private String name; |
| /** |
| * The job ahead of me in a queue or list. |
| */ |
| private InternalJob next; |
| /** |
| * The job behind me in a queue or list. |
| */ |
| private InternalJob previous; |
| private int priority = Job.LONG; |
| private IStatus result; |
| private ISchedulingRule schedulingRule; |
| /** |
| * If the job is waiting, this represents the time the job should start by. |
| * If this job is sleeping, this represents the time the job should wake up. |
| * If this job is running, this represents the delay automatic rescheduling, |
| * or -1 if the job should not be rescheduled. |
| */ |
| private long startTime; |
| /* |
| * The thread that is currently running this job |
| */ |
| private Thread thread = null; |
| |
| protected InternalJob(String name) { |
| Assert.isNotNull(name); |
| this.name = name; |
| } |
| /* (non-Javadoc) |
| * @see Job#addJobListener(IJobChangeListener) |
| */ |
| protected void addJobChangeListener(IJobChangeListener listener) { |
| if (listeners == null) |
| listeners = Collections.synchronizedList(new ArrayList(2)); |
| listeners.add(listener); |
| } |
| /** |
| * Adds an entry at the end of the list of which this item is the head. |
| */ |
| final void addLast(InternalJob entry) { |
| if (previous == null) { |
| previous = entry; |
| entry.next = this; |
| entry.previous = null; |
| } else { |
| Assert.isTrue(previous.next() == this); |
| previous.addLast(entry); |
| } |
| } |
| protected boolean belongsTo(Object family) { |
| return false; |
| } |
| protected boolean cancel() { |
| return manager.cancel(this); |
| } |
| public final int compareTo(Object otherJob) { |
| return (int) (((InternalJob) otherJob).startTime - startTime); |
| } |
| protected void done(IStatus result) { |
| manager.endJob(this, result, true); |
| } |
| /** |
| * Returns the job listeners that are only listening to this job. Returns null |
| * if this job has no listeners. |
| */ |
| final List getListeners() { |
| return listeners; |
| } |
| protected String getName() { |
| return name; |
| } |
| protected int getPriority() { |
| return priority; |
| } |
| final IProgressMonitor getProgressMonitor() { |
| return monitor; |
| } |
| protected IStatus getResult() { |
| return result; |
| } |
| protected ISchedulingRule getRule() { |
| return schedulingRule; |
| } |
| /*package*/ |
| final long getStartTime() { |
| return startTime; |
| } |
| protected int getState() { |
| int state = flags & M_STATE; |
| switch (state) { |
| //blocked state is equivalent to waiting state for clients |
| case BLOCKED: |
| return Job.WAITING; |
| case ABOUT_TO_RUN: |
| return Job.RUNNING; |
| default: |
| return state; |
| } |
| } |
| /* (non-javadoc) |
| * @see Job.getThread |
| */ |
| protected Thread getThread() { |
| return thread; |
| } |
| final int internalGetState() { |
| return flags & M_STATE; |
| } |
| /* |
| * Must be called from JobManager#setPriority |
| */ |
| final void internalSetPriority(int newPriority) { |
| this.priority = newPriority; |
| } |
| |
| /* |
| * Must be called from JobManager#setRule |
| */ |
| final void internalSetRule(ISchedulingRule rule) { |
| this.schedulingRule = rule; |
| } |
| /* |
| * Must be called from JobManager#changeState |
| */ |
| final void internalSetState(int i) { |
| flags = (flags & ~M_STATE) | i; |
| } |
| /** |
| * Returns true if this job conflicts with the given job, and false otherwise. |
| */ |
| final boolean isConflicting(InternalJob otherJob) { |
| ISchedulingRule otherRule = otherJob.getRule(); |
| if (schedulingRule == null || otherRule == null) |
| return false; |
| //if one of the rules is a compound rule, it must be asked the question. |
| if (schedulingRule.getClass() == MultiRule.class) |
| return schedulingRule.isConflicting(otherRule); |
| else |
| return otherRule.isConflicting(schedulingRule); |
| } |
| /* (non-javadoc) |
| * @see Job.isSystem |
| */ |
| protected boolean isSystem() { |
| return (flags & M_SYSTEM) != 0; |
| } |
| /* (non-javadoc) |
| * @see Job.isUser |
| */ |
| protected boolean isUser() { |
| return (flags & M_USER) != 0; |
| } |
| protected void join() throws InterruptedException { |
| manager.join(this); |
| } |
| /** |
| * Returns the next entry (ahead of this one) in the list, or null if there is no next entry |
| */ |
| final InternalJob next() { |
| return next; |
| } |
| /** |
| * Returns the previous entry (behind this one) in the list, or null if there is no previous entry |
| */ |
| final InternalJob previous() { |
| return previous; |
| } |
| /** |
| * Removes this entry from any list it belongs to. Returns the receiver. |
| */ |
| final InternalJob remove() { |
| if (next != null) |
| next.setPrevious(previous); |
| if (previous != null) |
| previous.setNext(next); |
| next = previous = null; |
| return this; |
| } |
| /* (non-Javadoc) |
| * @see Job#removeJobListener(IJobChangeListener) |
| */ |
| protected void removeJobChangeListener(IJobChangeListener listener) { |
| if (listeners != null) |
| listeners.remove(listener); |
| if (listeners.isEmpty()) |
| listeners = null; |
| } |
| protected abstract IStatus run(IProgressMonitor monitor); |
| protected void schedule(long delay) { |
| manager.schedule(this, delay); |
| } |
| protected void setName(String name) { |
| Assert.isNotNull(name); |
| this.name = name; |
| } |
| final void setNext(InternalJob entry) { |
| this.next = entry; |
| } |
| final void setPrevious(InternalJob entry) { |
| this.previous = entry; |
| } |
| protected void setPriority(int newPriority) { |
| switch (newPriority) { |
| case Job.INTERACTIVE : |
| case Job.SHORT : |
| case Job.LONG : |
| case Job.BUILD : |
| case Job.DECORATE : |
| manager.setPriority(this, newPriority); |
| break; |
| default : |
| throw new IllegalArgumentException(String.valueOf(newPriority)); |
| } |
| } |
| protected void setProgressGroup(IProgressMonitor group, int ticks) { |
| Assert.isNotNull(group); |
| IProgressMonitor result = manager.createMonitor(this, group, ticks); |
| if (result != null) |
| setProgressMonitor(result); |
| } |
| final void setProgressMonitor(IProgressMonitor monitor) { |
| this.monitor = monitor; |
| } |
| final void setResult(IStatus result) { |
| this.result = result; |
| } |
| protected void setRule(ISchedulingRule rule) { |
| manager.setRule(this, rule); |
| } |
| final void setStartTime(long time) { |
| startTime = time; |
| } |
| /* (non-javadoc) |
| * @see Job.setSystem |
| */ |
| protected void setSystem(boolean value) { |
| flags = value ? flags | M_SYSTEM : flags & ~M_SYSTEM; |
| } |
| /* (non-javadoc) |
| * @see Job.setUser |
| */ |
| protected void setUser(boolean value) { |
| flags = value ? flags | M_USER : flags & ~M_USER; |
| } |
| /* (non-javadoc) |
| * @see Job.setThread |
| */ |
| protected void setThread(Thread thread) { |
| this.thread = thread; |
| } |
| /* (Non-javadoc) |
| * @see Job#shouldSchedule |
| */ |
| protected boolean shouldSchedule() { |
| return true; |
| } |
| protected boolean sleep() { |
| return manager.sleep(this); |
| } |
| public String toString() { |
| return getName() + "(" + jobNumber + ")"; //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| protected void wakeUp(long delay) { |
| manager.wakeUp(this, delay); |
| } |
| } |