KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > events > AutoBuildJob


1 /*******************************************************************************
2  * Copyright (c) 2003, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM - Initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.events;
12
13 import org.eclipse.core.internal.resources.ResourceException;
14 import org.eclipse.core.internal.resources.Workspace;
15 import org.eclipse.core.internal.utils.Messages;
16 import org.eclipse.core.internal.utils.Policy;
17 import org.eclipse.core.resources.*;
18 import org.eclipse.core.runtime.*;
19 import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
20 import org.eclipse.core.runtime.jobs.ISchedulingRule;
21 import org.eclipse.core.runtime.jobs.Job;
22 import org.osgi.framework.Bundle;
23
24 /**
25  * The job for performing workspace auto-builds, and pre- and post- autobuild
26  * notification. This job is run whenever the workspace changes regardless
27  * of whether autobuild is on or off.
28  */

29 class AutoBuildJob extends Job implements Preferences.IPropertyChangeListener {
30     private boolean avoidBuild = false;
31     private boolean buildNeeded = false;
32     private boolean forceBuild = false;
33     /**
34      * Indicates that another thread tried to modify the workspace during
35      * the autobuild. The autobuild should be immediately rescheduled
36      * so that it will run as soon as the next workspace modification completes.
37      */

38     private boolean interrupted = false;
39     private boolean isAutoBuilding = false;
40     private long lastBuild = 0L;
41     private Preferences preferences = ResourcesPlugin.getPlugin().getPluginPreferences();
42     private final Bundle systemBundle = Platform.getBundle("org.eclipse.osgi"); //$NON-NLS-1$
43
private Workspace workspace;
44
45     AutoBuildJob(Workspace workspace) {
46         super(Messages.events_building_0);
47         setRule(workspace.getRoot());
48         setPriority(BUILD);
49         isAutoBuilding = workspace.isAutoBuilding();
50         this.workspace = workspace;
51         this.preferences.addPropertyChangeListener(this);
52     }
53
54     /**
55      * Used to prevent auto-builds at the end of operations that contain
56      * explicit builds
57      */

58     synchronized void avoidBuild() {
59         avoidBuild = true;
60     }
61
62     public boolean belongsTo(Object JavaDoc family) {
63         return family == ResourcesPlugin.FAMILY_AUTO_BUILD;
64     }
65
66     /**
67      * Instructs the build job that a build is required. Ensure the build
68      * job is scheduled to run.
69      * @param needsBuild Whether a build is required, either due to
70      * workspace change or other factor that invalidates the built state.
71      */

72     synchronized void build(boolean needsBuild) {
73         buildNeeded |= needsBuild;
74         long delay = computeScheduleDelay();
75         int state = getState();
76         if (Policy.DEBUG_BUILD_NEEDED)
77             Policy.debug("Build requested, needsBuild: " + needsBuild + " state: " + state + " delay: " + delay); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
78
if (needsBuild && Policy.DEBUG_BUILD_NEEDED_STACK && state != Job.RUNNING)
79             new RuntimeException JavaDoc("Build Needed").printStackTrace(); //$NON-NLS-1$
80
//don't mess with the interrupt flag if the job is still running
81
if (state != Job.RUNNING)
82             setInterrupted(false);
83         switch (state) {
84             case Job.SLEEPING :
85                 wakeUp(delay);
86                 break;
87             case NONE :
88                 setSystem(!isAutoBuilding);
89                 schedule(delay);
90                 break;
91         }
92     }
93
94     /**
95      * Computes the delay time that autobuild should be scheduled with. The
96      * value will be in the range (MIN_BUILD_DELAY, MAX_BUILD_DELAY).
97      */

98     private long computeScheduleDelay() {
99         return Math.max(Policy.MIN_BUILD_DELAY, Policy.MAX_BUILD_DELAY + lastBuild - System.currentTimeMillis());
100     }
101
102     /**
103      * The autobuild job has been canceled. There are two flavours of
104      * cancel, explicit user cancelation, and implicit interruption due to another
105      * thread trying to modify the workspace. In the latter case, we must
106      * make sure the build is immediately rescheduled if it was interrupted
107      * by another thread, so that clients waiting to join autobuild will properly
108      * continue waiting
109      * @return a status with severity <code>CANCEL</code>
110      */

111     private synchronized IStatus canceled() {
112         //regardless of the form of cancelation, the build state is not happy
113
buildNeeded = true;
114         //schedule a rebuild immediately if build was implicitly canceled
115
if (interrupted) {
116             if (Policy.DEBUG_BUILD_INTERRUPT)
117                 System.out.println("Scheduling rebuild due to interruption"); //$NON-NLS-1$
118
setInterrupted(false);
119             schedule(computeScheduleDelay());
120         }
121         return Status.CANCEL_STATUS;
122     }
123
124     private void doBuild(IProgressMonitor monitor) throws CoreException, OperationCanceledException {
125         monitor = Policy.monitorFor(monitor);
126         try {
127             monitor.beginTask("", Policy.opWork); //$NON-NLS-1$
128
final ISchedulingRule rule = workspace.getRuleFactory().buildRule();
129             try {
130                 workspace.prepareOperation(rule, monitor);
131                 workspace.beginOperation(true);
132                 final int trigger = IncrementalProjectBuilder.AUTO_BUILD;
133                 workspace.broadcastBuildEvent(workspace, IResourceChangeEvent.PRE_BUILD, trigger);
134                 IStatus result = Status.OK_STATUS;
135                 try {
136                     if (shouldBuild())
137                         result = workspace.getBuildManager().build(trigger, Policy.subMonitorFor(monitor, Policy.opWork));
138                 } finally {
139                     //always send POST_BUILD if there has been a PRE_BUILD
140
workspace.broadcastBuildEvent(workspace, IResourceChangeEvent.POST_BUILD, trigger);
141                 }
142                 if (!result.isOK())
143                     throw new ResourceException(result);
144                 buildNeeded = false;
145             } finally {
146                 //building may close the tree, but we are still inside an
147
// operation so open it
148
if (workspace.getElementTree().isImmutable())
149                     workspace.newWorkingTree();
150                 workspace.endOperation(rule, false, Policy.subMonitorFor(monitor, Policy.endOpWork));
151             }
152         } finally {
153             monitor.done();
154         }
155     }
156     
157     /**
158      * Forces an autobuild to occur, even if nothing has changed since the last
159      * build. This is used to force a build after a clean.
160      */

161     public void forceBuild() {
162         forceBuild = true;
163     }
164
165     /**
166      * Another thread is attempting to modify the workspace. Flag the auto-build
167      * as interrupted so that it will cancel and reschedule itself
168      */

169     synchronized void interrupt() {
170         //if already interrupted, do nothing
171
if (interrupted)
172             return;
173         switch (getState()) {
174             case NONE :
175                 return;
176             case WAITING :
177                 //put the job to sleep if it is waiting to run
178
setInterrupted(!sleep());
179                 break;
180             case RUNNING :
181                 //make sure autobuild doesn't interrupt itself
182
if (Job.getJobManager().currentJob() == this)
183                     return;
184                 setInterrupted(true);
185                 if (interrupted && Policy.DEBUG_BUILD_INTERRUPT) {
186                     System.out.println("Autobuild was interrupted:"); //$NON-NLS-1$
187
new Exception JavaDoc().fillInStackTrace().printStackTrace();
188                 }
189                 break;
190         }
191         //clear the autobuild avoidance flag if we were interrupted
192
if (interrupted)
193             avoidBuild = false;
194     }
195
196     synchronized boolean isInterrupted() {
197         if (interrupted)
198             return true;
199         //check if another job is blocked by the build job
200
if (isBlocking())
201             setInterrupted(true);
202         return interrupted;
203     }
204
205     /* (non-Javadoc)
206      * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent)
207      */

208     public void propertyChange(PropertyChangeEvent event) {
209         if (!event.getProperty().equals(ResourcesPlugin.PREF_AUTO_BUILDING))
210             return;
211         // get the new value of auto-build directly from the preferences
212
boolean wasAutoBuilding = isAutoBuilding;
213         isAutoBuilding = preferences.getBoolean(ResourcesPlugin.PREF_AUTO_BUILDING);
214         //force a build if autobuild has been turned on
215
if (!forceBuild && !wasAutoBuilding && isAutoBuilding) {
216             forceBuild = true;
217             build(false);
218         }
219     }
220
221     /* (non-Javadoc)
222      * @see org.eclipse.core.internal.jobs.InternalJob#run(org.eclipse.core.runtime.IProgressMonitor)
223      */

224     public IStatus run(IProgressMonitor monitor) {
225         //synchronized in case build starts during checkCancel
226
synchronized (this) {
227             if (monitor.isCanceled()) {
228                 return canceled();
229             }
230         }
231         //if the system is shutting down, don't build
232
if (systemBundle.getState() == Bundle.STOPPING)
233             return Status.OK_STATUS;
234         try {
235             doBuild(monitor);
236             lastBuild = System.currentTimeMillis();
237             //if the build was successful then it should not be recorded as interrupted
238
setInterrupted(false);
239             return Status.OK_STATUS;
240         } catch (OperationCanceledException e) {
241             return canceled();
242         } catch (CoreException sig) {
243             return sig.getStatus();
244         }
245     }
246
247     /**
248      * Sets or clears the interrupted flag.
249      */

250     private synchronized void setInterrupted(boolean value) {
251         interrupted = value;
252     }
253
254     /**
255      * Returns true if a build is actually needed, and false otherwise.
256      */

257     private synchronized boolean shouldBuild() {
258         try {
259             //if auto-build is off then we never run
260
if (!workspace.isAutoBuilding())
261                 return false;
262             //build if the workspace requires a build (description changes)
263
if (forceBuild)
264                 return true;
265             if (avoidBuild)
266                 return false;
267             //return whether there have been any changes to the workspace tree.
268
return buildNeeded;
269         } finally {
270             //regardless of the result, clear the build flags for next time
271
forceBuild = avoidBuild = buildNeeded = false;
272         }
273     }
274 }
275
Popular Tags