1 11 package org.eclipse.team.internal.core; 12 13 import java.util.ArrayList ; 14 import java.util.List ; 15 16 import org.eclipse.core.resources.IResource; 17 import org.eclipse.core.resources.IWorkspaceRunnable; 18 import org.eclipse.core.runtime.*; 19 import org.eclipse.core.runtime.jobs.*; 20 import org.eclipse.team.core.TeamException; 21 22 54 public abstract class BackgroundEventHandler { 55 56 59 public static final int RUNNABLE_EVENT = 1000; 60 61 private List awaitingProcessing = new ArrayList (); 63 64 private Job eventHandlerJob; 66 67 private boolean shutdown; 69 70 private ExceptionCollector errors; 72 73 private long timeOfLastDispatch = 0L; 75 76 private int dispatchCount; 78 79 private static final long DISPATCH_DELAY = 1500; 81 82 private static final long LONG_DISPATCH_DELAY = 10000; 84 85 private static final int DISPATCH_THRESHOLD = 3; 87 88 private static final long WAIT_DELAY = 100; 90 91 private String jobName; 92 93 96 public static class Event { 97 private int type; 98 public Event(int type) { 99 this.type = type; 100 } 101 public int getType() { 102 return type; 103 } 104 public String toString() { 105 StringBuffer buffer = new StringBuffer (); 106 buffer.append("Background Event: "); buffer.append(getTypeString()); 108 return buffer.toString(); 109 } 110 public IResource getResource() { 111 return null; 112 } 113 protected String getTypeString() { 114 return String.valueOf(type); 115 } 116 } 117 118 121 public static class ResourceEvent extends Event { 122 private IResource resource; 123 private int depth; 124 public ResourceEvent(IResource resource, int type, int depth) { 125 super(type); 126 this.resource = resource; 127 this.depth = depth; 128 } 129 public int getDepth() { 130 return depth; 131 } 132 public IResource getResource() { 133 return resource; 134 } 135 public String toString() { 136 StringBuffer buffer = new StringBuffer (); 137 buffer.append("resource: "); buffer.append(resource.getFullPath()); 139 buffer.append(" type: "); buffer.append(getTypeString()); 141 buffer.append(" depth: "); buffer.append(getDepthString()); 143 return buffer.toString(); 144 } 145 protected String getDepthString() { 146 switch (depth) { 147 case IResource.DEPTH_ZERO : 148 return "DEPTH_ZERO"; case IResource.DEPTH_ONE : 150 return "DEPTH_ONE"; case IResource.DEPTH_INFINITE : 152 return "DEPTH_INFINITE"; default : 154 return "INVALID"; } 156 } 157 } 158 159 167 public static class RunnableEvent extends Event { 168 private IWorkspaceRunnable runnable; 169 private boolean preemtive; 170 public RunnableEvent(IWorkspaceRunnable runnable, boolean preemtive) { 171 super(RUNNABLE_EVENT); 172 this.runnable = runnable; 173 this.preemtive = preemtive; 174 } 175 public void run(IProgressMonitor monitor) throws CoreException { 176 runnable.run(monitor); 177 } 178 public boolean isPreemtive() { 179 return preemtive; 180 } 181 } 182 183 protected BackgroundEventHandler(String jobName, String errorTitle) { 184 this.jobName = jobName; 185 errors = 186 new ExceptionCollector( 187 errorTitle, 188 TeamPlugin.ID, 189 IStatus.ERROR, 190 null 191 ); 192 createEventHandlingJob(); 193 schedule(); 194 } 195 196 200 protected void createEventHandlingJob() { 201 eventHandlerJob = new Job(getName()) { 202 public IStatus run(IProgressMonitor monitor) { 203 return processEvents(monitor); 204 } 205 public boolean shouldRun() { 206 return ! isQueueEmpty(); 207 } 208 public boolean shouldSchedule() { 209 return ! isQueueEmpty(); 210 } 211 public boolean belongsTo(Object family) { 212 return BackgroundEventHandler.this.belongsTo(family); 213 } 214 }; 215 eventHandlerJob.addJobChangeListener(new JobChangeAdapter() { 216 public void done(IJobChangeEvent event) { 217 jobDone(event); 218 } 219 }); 220 eventHandlerJob.setSystem(true); 221 eventHandlerJob.setPriority(Job.SHORT); 222 } 223 224 230 protected boolean belongsTo(Object family) { 231 return getJobFamiliy() == family; 232 } 233 234 240 protected Object getJobFamiliy() { 241 return null; 242 } 243 244 249 protected void jobDone(IJobChangeEvent event) { 250 if (isShutdown()) { 251 synchronized(this) { 253 awaitingProcessing.clear(); 254 } 255 } else if (! isQueueEmpty()) { 256 schedule(); 258 } 259 } 260 261 264 protected void schedule() { 265 eventHandlerJob.schedule(); 266 } 267 268 272 public void shutdown() { 273 shutdown = true; 274 eventHandlerJob.cancel(); 275 } 276 277 281 public boolean isShutdown() { 282 return shutdown; 283 } 284 285 290 protected synchronized void queueEvent(Event event, boolean front) { 291 if (Policy.DEBUG_BACKGROUND_EVENTS) { 292 System.out.println("Event queued on " + getName() + ":" + event.toString()); } 294 if (front) { 295 awaitingProcessing.add(0, event); 296 } else { 297 awaitingProcessing.add(event); 298 } 299 if (!isShutdown() && eventHandlerJob != null) { 300 if(eventHandlerJob.getState() == Job.NONE) { 301 schedule(); 302 } else { 303 notify(); 304 } 305 } 306 } 307 308 312 protected String getName() { 313 return jobName; 314 } 315 316 320 protected synchronized Event nextElement() { 321 if (isShutdown() || isQueueEmpty()) { 322 return null; 323 } 324 return (Event) awaitingProcessing.remove(0); 325 } 326 327 protected synchronized Event peek() { 328 if (isShutdown() || isQueueEmpty()) { 329 return null; 330 } 331 return (Event) awaitingProcessing.get(0); 332 } 333 334 338 protected synchronized boolean isQueueEmpty() { 339 return awaitingProcessing.isEmpty(); 340 } 341 342 354 protected IStatus processEvents(IProgressMonitor monitor) { 355 errors.clear(); 356 try { 357 monitor.beginTask(null, IProgressMonitor.UNKNOWN); 361 IProgressMonitor subMonitor = Policy.infiniteSubMonitorFor(monitor, 90); 362 subMonitor.beginTask(null, 1024); 363 364 Event event; 365 timeOfLastDispatch = System.currentTimeMillis(); 366 dispatchCount = 1; 367 while ((event = nextElement()) != null && ! isShutdown()) { 368 try { 369 processEvent(event, subMonitor); 370 if (Policy.DEBUG_BACKGROUND_EVENTS) { 371 System.out.println("Event processed on " + getName() + ":" + event.toString()); } 373 if(isReadyForDispatch(true )) { 374 dispatchEvents(Policy.subMonitorFor(subMonitor, 1)); 375 } 376 } catch (CoreException e) { 377 handleException(e); 379 } 380 } 381 } finally { 382 monitor.done(); 383 } 384 return errors.getStatus(); 385 } 386 387 393 protected final void dispatchEvents(IProgressMonitor monitor) throws TeamException { 394 if (doDispatchEvents(monitor)) { 395 dispatchCount++; 397 } 398 timeOfLastDispatch = System.currentTimeMillis(); 399 } 400 401 408 protected abstract boolean doDispatchEvents(IProgressMonitor monitor) throws TeamException; 409 410 420 protected boolean isReadyForDispatch(boolean wait) { 421 if (isDispatchDelayExceeded()) 423 return true; 424 425 synchronized(this) { 426 if(! isQueueEmpty() || ! wait) { 428 return false; 429 } 430 try { 433 wait(getDispatchWaitDelay()); 434 } catch (InterruptedException e) { 435 } 437 } 438 return isQueueEmpty() || isDispatchDelayExceeded(); 439 } 440 441 private boolean isDispatchDelayExceeded() { 442 long duration = System.currentTimeMillis() - timeOfLastDispatch; 443 return ((dispatchCount < DISPATCH_THRESHOLD && duration >= getShortDispatchDelay()) || 444 duration >= getLongDispatchDelay()); 445 } 446 447 451 protected long getDispatchWaitDelay() { 452 return WAIT_DELAY; 453 } 454 455 462 protected long getShortDispatchDelay() { 463 return DISPATCH_DELAY; 464 } 465 466 472 protected long getLongDispatchDelay() { 473 return LONG_DISPATCH_DELAY; 474 } 475 476 480 protected void handleException(CoreException e) { 481 errors.handleException(e); 482 } 483 484 498 protected abstract void processEvent(Event event, IProgressMonitor monitor) throws CoreException; 499 500 504 public Job getEventHandlerJob() { 505 return eventHandlerJob; 506 } 507 } 508 | Popular Tags |