1 11 package org.eclipse.team.internal.ccvs.ui.subscriber; 12 13 import java.lang.ref.SoftReference ; 14 import java.util.ArrayList ; 15 import java.util.HashMap ; 16 import java.util.Iterator ; 17 import java.util.List ; 18 import java.util.Map ; 19 20 import org.eclipse.core.resources.*; 21 import org.eclipse.core.runtime.*; 22 import org.eclipse.core.runtime.jobs.Job; 23 import org.eclipse.team.core.TeamException; 24 import org.eclipse.team.core.subscribers.Subscriber; 25 import org.eclipse.team.core.synchronize.*; 26 import org.eclipse.team.internal.ccvs.core.*; 27 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; 28 import org.eclipse.team.internal.ccvs.core.resources.RemoteFile; 29 import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; 30 import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; 31 import org.eclipse.team.internal.ccvs.core.util.Util; 32 import org.eclipse.team.internal.ccvs.ui.*; 33 import org.eclipse.team.internal.ccvs.ui.Policy; 34 import org.eclipse.team.internal.ccvs.ui.mappings.ModelCompareParticipant; 35 import org.eclipse.team.internal.ccvs.ui.operations.RemoteLogOperation; 36 import org.eclipse.team.internal.ccvs.ui.operations.RemoteLogOperation.LogEntryCache; 37 import org.eclipse.team.internal.core.BackgroundEventHandler; 38 import org.eclipse.team.internal.core.subscribers.SubscriberResourceCollector; 39 import org.eclipse.team.ui.synchronize.*; 40 41 45 public class LogEntryCacheUpdateHandler extends BackgroundEventHandler { 46 47 private static final int REMOVAL = 1; 48 private static final int CHANGE = 2; 49 private static final int FETCH_REQUEST = 3; 50 private static final int PAUSE = 4; 51 52 56 private final Object queueLock = new Object (); 57 58 61 private static final OperationCanceledException PAUSE_EXCEPTION = new OperationCanceledException(); 62 63 68 private static final int WAIT_INCREMENT = 10; 69 private static final int MAX_WAIT = 1000; 70 71 74 private final SyncInfoTree collectedInfos = new SyncInfoTree(); 75 76 79 81 85 private SoftReference cacheReference; 86 87 91 private final LogEntryResourceCollector collector; 92 93 96 private final Subscriber subscriber; 97 98 104 private final List updates = new ArrayList (); 105 106 109 private final List fetches = new ArrayList (); 110 private final ISynchronizePageConfiguration configuration; 111 112 113 116 public interface ILogsFetchedListener { 117 118 void logEntriesFetched(SyncInfoSet set, LogEntryCache logEntryCache, IProgressMonitor monitor); 119 120 } 121 122 125 private ILogsFetchedListener listener; 126 127 131 private class LogEntryResourceCollector extends SubscriberResourceCollector { 132 133 public LogEntryResourceCollector(Subscriber subscriber) { 134 super(subscriber); 135 } 136 137 140 protected void remove(IResource resource) { 141 queueEvent(new ResourceEvent(resource, REMOVAL, IResource.DEPTH_INFINITE), false ); 142 } 143 144 147 protected void change(IResource resource, int depth) { 148 queueEvent(new ResourceEvent(resource, CHANGE, depth), false ); 149 } 150 151 protected boolean hasMembers(IResource resource) { 152 return collectedInfos.hasMembers(resource); 153 } 154 } 155 156 159 private class FetchRequest extends Event { 160 private final SyncInfo[] infos; 161 public FetchRequest(SyncInfo[] infos) { 162 super(FETCH_REQUEST); 163 this.infos = infos; 164 } 165 public SyncInfo[] getInfos() { 166 return infos; 167 } 168 } 169 170 public LogEntryCacheUpdateHandler(ISynchronizePageConfiguration configuration) { 171 super(CVSUIMessages.LogEntryCacheUpdateHandler_1, CVSUIMessages.LogEntryCacheUpdateHandler_0); this.configuration = configuration; 173 this.subscriber = getSubscriber(configuration); 174 cacheReference = new SoftReference (new LogEntryCache()); 175 collector = new LogEntryResourceCollector(subscriber); 176 } 177 178 private Subscriber getSubscriber(ISynchronizePageConfiguration configuration) { 179 ISynchronizeParticipant participant = configuration.getParticipant(); 180 if (participant instanceof SubscriberParticipant) { 181 SubscriberParticipant sp = (SubscriberParticipant) participant; 182 return sp.getSubscriber(); 183 } 184 if (participant instanceof ModelCompareParticipant) { 185 ModelCompareParticipant mcp = (ModelCompareParticipant) participant; 186 return mcp.getSubscriber(); 187 } 188 return CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber(); 189 } 190 191 public ISynchronizePageConfiguration getConfiguration() { 192 return configuration; 193 } 194 195 public Subscriber getSubscriber() { 196 return subscriber; 197 } 198 199 204 public void setListener(ILogsFetchedListener listener) { 205 this.listener = listener; 206 } 207 208 211 protected Object getJobFamiliy() { 212 return ISynchronizeManager.FAMILY_SYNCHRONIZE_OPERATION; 213 } 214 215 218 protected void createEventHandlingJob() { 219 super.createEventHandlingJob(); 220 Job job = getEventHandlerJob(); 221 job.setSystem(false); 222 job.setUser(false); 223 } 224 225 228 protected void processEvent(Event event, IProgressMonitor monitor) throws CoreException { 229 Policy.checkCanceled(monitor); 230 switch (event.getType()) { 231 case REMOVAL: 232 case CHANGE: 233 updates.add(event); 234 break; 235 case FETCH_REQUEST: 236 fetches.add(event); 237 break; 238 case PAUSE: 239 throw PAUSE_EXCEPTION; 240 } 241 242 } 243 244 247 protected boolean doDispatchEvents(IProgressMonitor monitor) throws TeamException { 248 Policy.checkCanceled(monitor); 249 boolean dispatched = false; 250 monitor.beginTask(null, 50); 251 dispatched |= updateCache(Policy.subMonitorFor(monitor, 20)); 252 dispatched |= processQueuedFetches(Policy.subMonitorFor(monitor, 80)); 253 monitor.done(); 254 return dispatched; 255 } 256 257 261 private boolean updateCache(IProgressMonitor monitor) { 262 if (updates.isEmpty()) return false; 263 try { 264 collectedInfos.beginInput(); 265 for (Iterator iter = updates.iterator(); iter.hasNext();) { 267 Event event = (Event) iter.next(); 268 Policy.checkCanceled(monitor); 269 if (event.getType() == REMOVAL) { 270 remove(event.getResource(), ((ResourceEvent)event).getDepth()); 271 } else if (event.getType() == CHANGE) { 272 change(event.getResource(), ((ResourceEvent)event).getDepth()); 273 } 274 iter.remove(); 277 } 278 } finally { 279 collectedInfos.endInput(monitor); 280 } 281 return true; 282 } 283 284 287 public void shutdown() { 288 super.shutdown(); 289 collector.dispose(); 290 if (cacheReference != null) { 292 LogEntryCache cache = (LogEntryCache)cacheReference.get(); 293 if (cache != null) { 294 cache.clearEntries(); 295 } 296 } 297 collectedInfos.clear(); 298 299 } 300 301 private void remove(IResource resource, int depth) { 302 collectedInfos.remove(resource, depth); 303 } 304 305 private void remove(SyncInfo info) { 306 if (info != null) { 307 collectedInfos.remove(info.getLocal()); 308 LogEntryCache cache = (LogEntryCache)cacheReference.get(); 309 if (cache != null) { 310 ICVSRemoteResource remoteResource = getRemoteResource(info); 311 if (remoteResource != null) 312 cache.clearEntries(remoteResource); 313 } 314 } 315 } 316 317 public ICVSRemoteResource getRemoteResource(SyncInfo info) { 318 try { 319 ICVSRemoteResource remote = (ICVSRemoteResource) info.getRemote(); 320 ICVSRemoteResource local = CVSWorkspaceRoot.getRemoteResourceFor(info.getLocal()); 321 if(local == null) { 322 local = (ICVSRemoteResource)info.getBase(); 323 } 324 325 boolean useRemote = true; 326 if (local != null && remote != null) { 327 String remoteRevision = getRevisionString(remote); 328 String localRevision = getRevisionString(local); 329 useRemote = useRemote(localRevision, remoteRevision); 330 } else if (remote == null) { 331 useRemote = false; 332 } 333 if (useRemote) { 334 return remote; 335 } else if (local != null) { 336 return local; 337 } 338 return null; 339 } catch (CVSException e) { 340 CVSUIPlugin.log(e); 341 return null; 342 } 343 } 344 345 private boolean useRemote(String localRevision, String remoteRevision) { 346 boolean useRemote; 347 if (remoteRevision == null && localRevision == null) { 348 useRemote = true; 349 } else if (localRevision == null) { 350 useRemote = true; 351 } else if (remoteRevision == null) { 352 useRemote = false; 353 } else { 354 useRemote = ResourceSyncInfo.isLaterRevision(remoteRevision, localRevision); 355 } 356 return useRemote; 357 } 358 359 private String getRevisionString(ICVSRemoteResource remoteFile) { 360 if(remoteFile instanceof RemoteFile) { 361 return ((RemoteFile)remoteFile).getRevision(); 362 } 363 return null; 364 } 365 366 private void change(IResource resource, int depth) { 367 SyncInfo[] collected = collectedInfos.getSyncInfos(resource, depth); 370 change(collected); 371 } 372 373 private void change(SyncInfo[] collected) { 374 Subscriber subscriber = getSubscriber(); 375 for (int i = 0; i < collected.length; i++) { 376 try { 377 SyncInfo info = collected[i]; 378 SyncInfo newInfo = subscriber.getSyncInfo(info.getLocal()); 379 if (newInfo == null || !newInfo.equals(info)) { 380 remove(info); 383 } 384 } catch (TeamException e) { 385 CVSUIPlugin.log(e); 387 } 388 } 389 } 390 391 397 public void fetch(SyncInfo[] infos) throws CVSException { 398 synchronized(queueLock) { 399 Job job = getEventHandlerJob(); 400 if (job.isSystem() && job.getState() != Job.NONE) { 401 super.queueEvent(new Event(PAUSE), true ); 403 int count = 0; 404 while (job.getState() != Job.NONE && count < MAX_WAIT) { 405 count += WAIT_INCREMENT; 406 try { 407 Thread.sleep(WAIT_INCREMENT); } catch (InterruptedException e) { 409 } 411 } 412 if (job.getState() != Job.NONE) { 413 throw new CVSException(CVSUIMessages.LogEntryCacheUpdateHandler_2); 415 } 416 } 417 queueEvent(new FetchRequest(infos), false ); 419 } 420 } 421 422 425 protected void queueEvent(Event event, boolean front) { 426 synchronized(queueLock) { 428 Job job = getEventHandlerJob(); 429 if (job.getState() == Job.NONE) { 430 job.setSystem(event.getType() != FETCH_REQUEST); 431 } 432 super.queueEvent(event, front); 433 } 434 } 435 436 439 private boolean processQueuedFetches(IProgressMonitor monitor) { 440 if (fetches.isEmpty()) return false; 441 try { 442 Map projectMapping = getFetchesByProject(); 444 if (projectMapping.isEmpty()) return true; 445 LogEntryCache logEntriesCache = (LogEntryCache)cacheReference.get(); 446 if (logEntriesCache == null) { 447 logEntriesCache = new LogEntryCache(); 448 cacheReference = new SoftReference (logEntriesCache); 449 } 450 monitor.beginTask(CVSUIMessages.CVSChangeSetCollector_4, 100 * projectMapping.size()); 451 monitor.setTaskName(CVSUIMessages.CVSChangeSetCollector_4); 452 for (Iterator iter = projectMapping.values().iterator(); iter.hasNext();) { 453 SyncInfoSet set = (SyncInfoSet) iter.next(); 454 Policy.checkCanceled(monitor); 455 fetchLogEntries(logEntriesCache, set, Policy.subMonitorFor(monitor, 90)); 456 fireFetchedNotification(logEntriesCache, set, Policy.subMonitorFor(monitor, 10)); 457 } 458 } finally { 459 fetches.clear(); 462 monitor.done(); 463 } 464 return true; 465 } 466 467 private void fireFetchedNotification(LogEntryCache logEntriesCache, SyncInfoSet set, IProgressMonitor monitor) { 468 if (listener != null) { 469 listener.logEntriesFetched(set, logEntriesCache, monitor); 470 } 471 } 472 473 480 private Map getFetchesByProject() { 481 Map result = new HashMap (); 482 for (Iterator iter = fetches.iterator(); iter.hasNext();) { 483 FetchRequest request = (FetchRequest) iter.next(); 484 SyncInfo[] infos = request.getInfos(); 485 for (int i = 0; i < infos.length; i++) { 486 SyncInfo info = infos[i]; 487 IProject project = info.getLocal().getProject(); 488 SyncInfoSet infoSet = (SyncInfoSet)result.get(project); 489 if (infoSet == null) { 490 infoSet = new SyncInfoSet(); 491 result.put(project, infoSet); 492 } 493 infoSet.add(info); 494 } 495 } 496 return result; 497 } 498 499 private boolean isFetchRequired(SyncInfo info) { 500 return info.getLocal().getType() == IResource.FILE && !isLogEntryCached(info) && isRemoteChange(info); 503 504 } 505 506 511 private boolean isLogEntryCached(SyncInfo info) { 512 SyncInfo collectedInfo = collectedInfos.getSyncInfo(info.getLocal()); 513 if (collectedInfo != null && !collectedInfo.equals(info)) { 514 remove(collectedInfo); 515 collectedInfo = null; 516 } 517 return collectedInfo != null; 518 } 519 520 525 public boolean isRemoteChange(SyncInfo info) { 526 int kind = info.getKind(); 527 if(info.getLocal().getType() != IResource.FILE) return false; 528 if(info.getComparator().isThreeWay()) { 529 return (kind & SyncInfo.DIRECTION_MASK) != SyncInfo.OUTGOING; 530 } 531 if (info.getRemote() != null) return true; 533 ICVSFile file = CVSWorkspaceRoot.getCVSFileFor((IFile)info.getLocal()); 534 try { 535 return file.getSyncBytes() != null; 536 } catch (CVSException e) { 537 CVSUIPlugin.log(e); 539 return false; 540 } 541 } 542 543 546 private void fetchLogEntries(LogEntryCache logEntriesCache, SyncInfoSet set, IProgressMonitor monitor) { 547 try { 548 if (subscriber instanceof CVSCompareSubscriber) { 549 CVSCompareSubscriber compareSubscriber = (CVSCompareSubscriber)subscriber; 550 fetchLogEntries(logEntriesCache, compareSubscriber, set, monitor); 551 } else { 552 fetchLogs(logEntriesCache, set, null, null, monitor); 554 } 555 } catch (CVSException e) { 556 handleException(e); 557 } catch (InterruptedException e) { 558 throw new OperationCanceledException(); 559 } 560 561 } 562 563 private void fetchLogEntries(LogEntryCache logEntriesCache, CVSCompareSubscriber compareSubscriber, SyncInfoSet set, IProgressMonitor monitor) throws CVSException, InterruptedException { 564 Map localTagMap = getLocalTagMap(set); 565 monitor.beginTask(null, 100 * localTagMap.size()); 566 for (Iterator iter = localTagMap.keySet().iterator(); iter.hasNext();) { 567 CVSTag localTag = (CVSTag) iter.next(); 568 fetchLogEntries(logEntriesCache, compareSubscriber, set, localTag, Policy.subMonitorFor(monitor, 100)); 569 } 570 Policy.checkCanceled(monitor); 571 monitor.done(); 572 } 573 574 578 private Map getLocalTagMap(SyncInfoSet set) { 579 Map result = new HashMap (); 580 for (Iterator iter = set.iterator(); iter.hasNext();) { 581 SyncInfo info = (SyncInfo) iter.next(); 582 CVSTag tag = getLocalTag(info); 583 SyncInfoSet tagSet = (SyncInfoSet)result.get(tag); 584 if (tagSet == null) { 585 tagSet = new SyncInfoSet(); 586 result.put(tag, tagSet); 587 } 588 tagSet.add(info); 589 } 590 return result; 591 } 592 593 private CVSTag getLocalTag(SyncInfo syncInfo) { 594 try { 595 IResource local = syncInfo.getLocal(); 596 ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(local); 597 CVSTag tag = null; 598 if(cvsResource.isFolder()) { 599 FolderSyncInfo info = ((ICVSFolder)cvsResource).getFolderSyncInfo(); 600 if(info != null) { 601 tag = info.getTag(); 602 } 603 if (tag != null && tag.getType() == CVSTag.BRANCH) { 604 tag = Util.getAccurateFolderTag(local, tag); 605 } 606 } else { 607 tag = Util.getAccurateFileTag(cvsResource); 608 } 609 if(tag == null) { 610 tag = new CVSTag(); 611 } 612 return tag; 613 } catch (CVSException e) { 614 CVSUIPlugin.log(e); 615 return new CVSTag(); 616 } 617 } 618 619 private void fetchLogEntries(LogEntryCache logEntriesCache, CVSCompareSubscriber compareSubscriber, SyncInfoSet set, CVSTag localTag, IProgressMonitor monitor) throws CVSException, InterruptedException { 620 if (compareSubscriber.isMultipleTagComparison()) { 621 Map rootToInfoMap = getRootToInfoMap(compareSubscriber, set); 622 monitor.beginTask(null, 100 * rootToInfoMap.size()); 623 for (Iterator iterator = rootToInfoMap.keySet().iterator(); iterator.hasNext();) { 624 IResource root = (IResource) iterator.next(); 625 Policy.checkCanceled(monitor); 626 fetchLogs(logEntriesCache, set, localTag, compareSubscriber.getTag(root), Policy.subMonitorFor(monitor, 100)); 627 } 628 monitor.done(); 629 } else { 630 Policy.checkCanceled(monitor); 631 fetchLogs(logEntriesCache, set, localTag, compareSubscriber.getTag(), monitor); 632 } 633 } 634 635 private Map getRootToInfoMap(CVSCompareSubscriber compareSubscriber, SyncInfoSet set) { 636 Map rootToInfosMap = new HashMap (); 637 IResource[] roots = compareSubscriber.roots(); 638 for (Iterator iter = set.iterator(); iter.hasNext();) { 639 SyncInfo info = (SyncInfo) iter.next(); 640 IPath localPath = info.getLocal().getFullPath(); 641 for (int j = 0; j < roots.length; j++) { 642 IResource resource = roots[j]; 643 if (resource.getFullPath().isPrefixOf(localPath)) { 644 SyncInfoSet infoList = (SyncInfoSet)rootToInfosMap.get(resource); 645 if (infoList == null) { 646 infoList = new SyncInfoSet(); 647 rootToInfosMap.put(resource, infoList); 648 } 649 infoList.add(info); 650 break; } 652 } 653 654 } 655 return rootToInfosMap; 656 } 657 658 private void fetchLogs(LogEntryCache logEntriesCache, SyncInfoSet set, CVSTag localTag, CVSTag remoteTag, IProgressMonitor monitor) throws CVSException, InterruptedException { 659 ICVSRemoteResource[] remoteResources = getRemotesToFetch(set.getSyncInfos()); 660 if (remoteResources.length > 0) { 661 RemoteLogOperation logOperation = new RemoteLogOperation(getConfiguration().getSite().getPart(), remoteResources, localTag, remoteTag, logEntriesCache); 662 logOperation.execute(monitor); 663 } 664 collectedInfos.addAll(set); 665 } 666 667 private ICVSRemoteResource[] getRemotesToFetch(SyncInfo[] infos) { 668 List remotes = new ArrayList (); 669 for (int i = 0; i < infos.length; i++) { 670 SyncInfo info = infos[i]; 671 if (isFetchRequired(info)) { 672 ICVSRemoteResource remote = getRemoteResource(info); 673 if(remote != null) { 674 remotes.add(remote); 675 } 676 } 677 } 678 return (ICVSRemoteResource[]) remotes.toArray(new ICVSRemoteResource[remotes.size()]); 679 } 680 681 684 public void stopFetching() { 685 try { 686 getEventHandlerJob().cancel(); 687 getEventHandlerJob().join(); 688 } catch (InterruptedException e) { 689 } 690 } 691 } 692 | Popular Tags |