KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > refresh > PollingMonitor


1 /*******************************************************************************
2  * Copyright (c) 2004, 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.refresh;
12
13 import java.util.ArrayList JavaDoc;
14 import org.eclipse.core.internal.resources.Resource;
15 import org.eclipse.core.internal.utils.Messages;
16 import org.eclipse.core.resources.*;
17 import org.eclipse.core.resources.refresh.IRefreshMonitor;
18 import org.eclipse.core.runtime.*;
19 import org.eclipse.core.runtime.jobs.Job;
20 import org.osgi.framework.Bundle;
21
22 /**
23  * The <code>PollingMonitor</code> is an <code>IRefreshMonitor</code> that
24  * polls the file system rather than registering natively for call-backs.
25  *
26  * The polling monitor operates in iterations that span multiple invocations
27  * of the job's run method. At the beginning of an iteration, a set of
28  * all resource roots is collected. Each time the job runs, it removes items
29  * from the set and searches for changes for a fixed period of time.
30  * This ensures that the refresh job is broken into very small discrete
31  * operations that do not interrupt the user's main-line activity.
32  *
33  * @since 3.0
34  */

35 public class PollingMonitor extends Job implements IRefreshMonitor {
36     /**
37      * The maximum duration of a single polling iteration
38      */

39     private static final long MAX_DURATION = 250;
40     /**
41      * The amount of time that a changed root should remain hot.
42      */

43     private static final long HOT_ROOT_DECAY = 90000;
44     /**
45      * The minimum delay between executions of the polling monitor
46      */

47     private static final long MIN_FREQUENCY = 4000;
48     /**
49      * The roots of resources which should be polled
50      */

51     private final ArrayList JavaDoc resourceRoots;
52     /**
53      * The resources remaining to be refreshed in this iteration
54      */

55     private final ArrayList JavaDoc toRefresh;
56     /**
57      * The root that has most recently been out of sync
58      */

59     private IResource hotRoot;
60     /**
61      * The time the hot root was last refreshed
62      */

63     private long hotRootTime;
64
65     private final RefreshManager refreshManager;
66     /**
67      * True if this job has never been run. False otherwise.
68      */

69     private boolean firstRun = true;
70
71     /**
72      * Creates a new polling monitor.
73      */

74     public PollingMonitor(RefreshManager manager) {
75         super(Messages.refresh_pollJob);
76         this.refreshManager = manager;
77         setPriority(Job.DECORATE);
78         setSystem(true);
79         resourceRoots = new ArrayList JavaDoc();
80         toRefresh = new ArrayList JavaDoc();
81     }
82
83     /**
84      * Add the given root to the list of roots that need to be polled.
85      */

86     public synchronized void monitor(IResource root) {
87         resourceRoots.add(root);
88         schedule(MIN_FREQUENCY);
89     }
90
91     /**
92      * Polls the file system under the root containers for changes.
93      */

94     protected IStatus run(IProgressMonitor monitor) {
95         //sleep until resources plugin has finished starting
96
if (firstRun) {
97             firstRun = false;
98             Bundle bundle = Platform.getBundle(ResourcesPlugin.PI_RESOURCES);
99             long waitStart = System.currentTimeMillis();
100             while (bundle.getState() == Bundle.STARTING) {
101                 try {
102                     Thread.sleep(10000);
103                 } catch (InterruptedException JavaDoc e) {
104                     //ignore
105
}
106                 //don't wait forever
107
if ((System.currentTimeMillis() - waitStart) > 90000)
108                     break;
109             }
110         }
111         long time = System.currentTimeMillis();
112         //check to see if we need to start an iteration
113
if (toRefresh.isEmpty()) {
114             beginIteration();
115             if (RefreshManager.DEBUG)
116                 System.out.println(RefreshManager.DEBUG_PREFIX + "New polling iteration on " + toRefresh.size() + " roots"); //$NON-NLS-1$ //$NON-NLS-2$
117
}
118         final int oldSize = toRefresh.size();
119         if (RefreshManager.DEBUG)
120             System.out.println(RefreshManager.DEBUG_PREFIX + "started polling"); //$NON-NLS-1$
121
//refresh the hot root if applicable
122
if (time - hotRootTime > HOT_ROOT_DECAY)
123             hotRoot = null;
124         else if (hotRoot != null && !monitor.isCanceled())
125             poll(hotRoot);
126         //process roots that have not yet been refreshed this iteration
127
final long loopStart = System.currentTimeMillis();
128         while (!toRefresh.isEmpty()) {
129             if (monitor.isCanceled())
130                 break;
131             poll((IResource) toRefresh.remove(toRefresh.size() - 1));
132             //stop the iteration if we have exceed maximum duration
133
if (System.currentTimeMillis() - loopStart > MAX_DURATION)
134                 break;
135         }
136         time = System.currentTimeMillis() - time;
137         if (RefreshManager.DEBUG)
138             System.out.println(RefreshManager.DEBUG_PREFIX + "polled " + (oldSize - toRefresh.size()) + " roots in " + time + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
139
//reschedule automatically - shouldRun will cancel if not needed
140
//make sure it doesn't run more than 5% of the time
141
long delay = Math.max(MIN_FREQUENCY, time * 20);
142         //back off even more if there are other jobs running
143
if (!getJobManager().isIdle())
144             delay *= 2;
145         if (RefreshManager.DEBUG)
146             System.out.println(RefreshManager.DEBUG_PREFIX + "rescheduling polling job in: " + delay / 1000 + " seconds"); //$NON-NLS-1$ //$NON-NLS-2$
147
//don't reschedule the job if the resources plugin has been shut down
148
if (Platform.getBundle(ResourcesPlugin.PI_RESOURCES).getState() == Bundle.ACTIVE)
149             schedule(delay);
150         return Status.OK_STATUS;
151     }
152
153     /**
154      * Instructs the polling job to do one complete iteration of all workspace roots, and
155      * then discard itself. This is used when
156      * the refresh manager is first turned on if there is a native monitor installed (which
157      * don't handle changes that occurred while the monitor was turned off).
158      */

159     void runOnce() {
160         synchronized (this) {
161             //add all roots to the refresh list, but not to the real set of roots
162
//this will cause the job to never run again once it has exhausted
163
//the set of roots to refresh
164
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
165             for (int i = 0; i < projects.length; i++)
166                 toRefresh.add(projects[i]);
167         }
168         schedule(MIN_FREQUENCY);
169     }
170
171     private void poll(IResource resource) {
172         if (resource.isSynchronized(IResource.DEPTH_INFINITE))
173             return;
174         //don't refresh links with no local content
175
if (resource.isLinked() && !((Resource) resource).getStore().fetchInfo().exists())
176             return;
177         //submit refresh request
178
refreshManager.refresh(resource);
179         hotRoot = resource;
180         hotRootTime = System.currentTimeMillis();
181         if (RefreshManager.DEBUG)
182             System.out.println(RefreshManager.DEBUG_PREFIX + "new hot root: " + resource); //$NON-NLS-1$
183
}
184
185     /* (non-Javadoc)
186      * @see Job#shouldRun
187      */

188     public boolean shouldRun() {
189         //only run if there is something to refresh
190
return !resourceRoots.isEmpty() || !toRefresh.isEmpty();
191     }
192
193     /**
194      * Copies the resources to be polled into the list of resources
195      * to refresh this iteration. This method is synchronized to
196      * guard against concurrent access to the resourceRoots field.
197      */

198     private synchronized void beginIteration() {
199         toRefresh.addAll(resourceRoots);
200         if (hotRoot != null)
201             toRefresh.remove(hotRoot);
202     }
203
204     /*
205      * @see org.eclipse.core.resources.refresh.IRefreshMonitor#unmonitor(IContainer)
206      */

207     public synchronized void unmonitor(IResource resource) {
208         if (resource == null)
209             resourceRoots.clear();
210         else
211             resourceRoots.remove(resource);
212         if (resourceRoots.isEmpty())
213             cancel();
214     }
215 }
216
Popular Tags