KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > ui > subscriber > LogEntryCacheUpdateHandler


1 /*******************************************************************************
2  * Copyright (c) 2000, 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 Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.team.internal.ccvs.ui.subscriber;
12
13 import java.lang.ref.SoftReference JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
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 /**
42  * This class wraps a LogEntryCache in order to clear entries once they are no longer
43  * in the subscriber.
44  */

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     /*
53      * Lock used to ensure that fetches are queued when the job is
54      * a non-system job.
55      */

56     private final Object JavaDoc queueLock = new Object JavaDoc();
57     
58     /*
59      * Exception used to stop processing so the job can be restarted as a non-system job
60      */

61     private static final OperationCanceledException PAUSE_EXCEPTION = new OperationCanceledException();
62     
63     /*
64      * Contants for configuring how long to wait for the job to be paused
65      * when a fetch is required and the job needs to be converted to a non-system
66      * job. If the wait time is elapsed, an exception is thrown.
67      */

68     private static final int WAIT_INCREMENT = 10;
69     private static final int MAX_WAIT = 1000;
70     
71     /*
72      * Set that keeps track of all resource for which we haved fetched log entries
73      */

74     private final SyncInfoTree collectedInfos = new SyncInfoTree();
75     
76     /*
77      * The cache that hold the log entries while the job is running
78      */

79     //private LogEntryCache logEntriesCache;
80

81     /*
82      * SoftReference used to hold on to the log entry cache while
83      * the job is not running so the cache can be cleared if memory is low.
84      */

85     private SoftReference JavaDoc cacheReference;
86     
87     /*
88      * Collector that forewards subscriber changes so that
89      * stale cache entries can be cleared.
90      */

91     private final LogEntryResourceCollector collector;
92
93     /*
94      * The subscriber generating the SyncInfo and log entries
95      */

96     private final Subscriber subscriber;
97     
98     /*
99      * The accumulated list of updates that need to be dispatched
100      * (i.e. the cache should be purged of out-of-date resources).
101      * This list is only modified and accessed from the event processing
102      * thread.
103      */

104     private final List JavaDoc updates = new ArrayList JavaDoc();
105     
106     /*
107      * The accumulated list of fetches that have been requested
108      */

109     private final List JavaDoc fetches = new ArrayList JavaDoc();
110     private final ISynchronizePageConfiguration configuration;
111     
112     
113     /*
114      * Interface for notifying a single client that the infos have been fetched
115      */

116     public interface ILogsFetchedListener {
117
118         void logEntriesFetched(SyncInfoSet set, LogEntryCache logEntryCache, IProgressMonitor monitor);
119         
120     }
121     
122     /*
123      * The listener or null if noone is listening
124      */

125     private ILogsFetchedListener listener;
126     
127     /*
128      * Subscriber resource collector that forwards subscriber changes
129      * through the handler so that stale cache entries can be cleared
130      */

131     private class LogEntryResourceCollector extends SubscriberResourceCollector {
132
133         public LogEntryResourceCollector(Subscriber subscriber) {
134             super(subscriber);
135         }
136
137         /* (non-Javadoc)
138          * @see org.eclipse.team.internal.core.subscribers.SubscriberResourceCollector#remove(org.eclipse.core.resources.IResource)
139          */

140         protected void remove(IResource resource) {
141             queueEvent(new ResourceEvent(resource, REMOVAL, IResource.DEPTH_INFINITE), false /* do not put in on the front of the queue*/);
142         }
143
144         /* (non-Javadoc)
145          * @see org.eclipse.team.internal.core.subscribers.SubscriberResourceCollector#change(org.eclipse.core.resources.IResource, int)
146          */

147         protected void change(IResource resource, int depth) {
148             queueEvent(new ResourceEvent(resource, CHANGE, depth), false /* do not put in on the front of the queue*/);
149         }
150
151         protected boolean hasMembers(IResource resource) {
152             return collectedInfos.hasMembers(resource);
153         }
154     }
155     
156     /*
157      * Custom event for queue a log entry fetch request
158      */

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); //
172
this.configuration = configuration;
173         this.subscriber = getSubscriber(configuration);
174         cacheReference = new SoftReference JavaDoc(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     /**
200      * Set the listener that should receive notification when log entries
201      * have been fetched and are avalable.
202      * @param listener the listener or <code>null</code>
203      */

204     public void setListener(ILogsFetchedListener listener) {
205         this.listener = listener;
206     }
207     
208     /* (non-Javadoc)
209      * @see org.eclipse.team.internal.core.BackgroundEventHandler#getJobFamiliy()
210      */

211     protected Object JavaDoc getJobFamiliy() {
212         return ISynchronizeManager.FAMILY_SYNCHRONIZE_OPERATION;
213     }
214     
215     /* (non-Javadoc)
216      * @see org.eclipse.team.internal.core.BackgroundEventHandler#createEventHandlingJob()
217      */

218     protected void createEventHandlingJob() {
219         super.createEventHandlingJob();
220         Job job = getEventHandlerJob();
221         job.setSystem(false);
222         job.setUser(false);
223     }
224     
225     /* (non-Javadoc)
226      * @see org.eclipse.team.internal.core.BackgroundEventHandler#processEvent(org.eclipse.team.internal.core.BackgroundEventHandler.Event, org.eclipse.core.runtime.IProgressMonitor)
227      */

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     /* (non-Javadoc)
245      * @see org.eclipse.team.internal.core.BackgroundEventHandler#doDispatchEvents(org.eclipse.core.runtime.IProgressMonitor)
246      */

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     /*
258      * Remove any stale or unneeded log entries from the cache.
259      * Return whether there were any entries to purge.
260      */

261     private boolean updateCache(IProgressMonitor monitor) {
262         if (updates.isEmpty()) return false;
263         try {
264             collectedInfos.beginInput();
265             // Cycle through the update events
266
for (Iterator JavaDoc 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                 // Use the iterator to remove so that updates will not be lost
275
// if the job is cancelled and then restarted.
276
iter.remove();
277             }
278         } finally {
279             collectedInfos.endInput(monitor);
280         }
281         return true;
282     }
283
284     /* (non-Javadoc)
285      * @see org.eclipse.team.internal.core.BackgroundEventHandler#shutdown()
286      */

287     public void shutdown() {
288         super.shutdown();
289         collector.dispose();
290         // Probably not necessary as GC would take care of it but we'll do it anyway
291
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 JavaDoc remoteRevision = getRevisionString(remote);
328                 String JavaDoc 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 JavaDoc localRevision, String JavaDoc 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 JavaDoc 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         // We only need to remove collected log entries that don't apply
368
// any longer. They will be refetched when they are required.
369
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                     // The cached log entry no longer applies to the new sync info.
381
// It will be refetched when required.
382
remove(info);
383                 }
384             } catch (TeamException e) {
385                 // Log and continue
386
CVSUIPlugin.log(e);
387             }
388         }
389     }
390
391     /**
392      * Queue a request to fetch log entries for the given SyncInfo nodes.
393      * The event handler must be a non-system job when revision histories
394      * are fetched.
395      * @param infos the nodes whose log entries are to be fetched
396      */

397     public void fetch(SyncInfo[] infos) throws CVSException {
398         synchronized(queueLock) {
399             Job job = getEventHandlerJob();
400             if (job.isSystem() && job.getState() != Job.NONE) {
401                 // queue an event to pause the processor
402
super.queueEvent(new Event(PAUSE), true /* put on the front of the queue */);
403                 int count = 0;
404                 while (job.getState() != Job.NONE && count < MAX_WAIT) {
405                     count += WAIT_INCREMENT;
406                     try {
407                         Thread.sleep(WAIT_INCREMENT); // Wait a little while
408
} catch (InterruptedException JavaDoc e) {
409                         // Ignore
410
}
411                 }
412                 if (job.getState() != Job.NONE) {
413                     // The job never completed in the time aloted so throw an exception
414
throw new CVSException(CVSUIMessages.LogEntryCacheUpdateHandler_2);
415                 }
416             }
417             // Queue the event even if the job didn't stop in the time aloted
418
queueEvent(new FetchRequest(infos), false /* don't place at the end */);
419         }
420     }
421     
422     /* (non-Javadoc)
423      * @see org.eclipse.team.internal.core.BackgroundEventHandler#queueEvent(org.eclipse.team.internal.core.BackgroundEventHandler.Event, boolean)
424      */

425     protected void queueEvent(Event event, boolean front) {
426         // Override to snure that queues by this handler are serialized
427
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     /*
437      * Method invoked during event dispatch to fetch log entries
438      */

439     private boolean processQueuedFetches(IProgressMonitor monitor) {
440         if (fetches.isEmpty()) return false;
441         try {
442             // Now perform the fetching
443
Map JavaDoc 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 JavaDoc(logEntriesCache);
449             }
450             monitor.beginTask(CVSUIMessages.CVSChangeSetCollector_4, 100 * projectMapping.size());
451             monitor.setTaskName(CVSUIMessages.CVSChangeSetCollector_4);
452             for (Iterator JavaDoc 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             // Clear the fetches even if we were cancelled.
460
// Restarting will need to re-request all infos
461
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     /*
474      * Return a map of IProject to SyncInfoSet as that is how entries are fetched.
475      * The set for each project includes all infos from the original set.
476      * This is one so that the completion notification contains all infos
477      * including those were a fetch was not required either because the
478      * entry was already cached or the resource has no history.
479      */

480     private Map JavaDoc getFetchesByProject() {
481         Map JavaDoc result = new HashMap JavaDoc();
482         for (Iterator JavaDoc 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         // We only need to fetch if we don't have the log entry already
501
// and the change is a remote change
502
return info.getLocal().getType() == IResource.FILE && !isLogEntryCached(info) && isRemoteChange(info);
503         
504     }
505     
506     /*
507      * Return whether the given SyncInfo is cached. If there is
508      * an info for the resource that does not match the given info,
509      * it is removed and false is returned.
510      */

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     /*
521      * Return if this sync info should be considered as part of a remote change
522      * meaning that it can be placed inside an incoming commit set (i.e. the
523      * set is determined using the comments from the log entry of the file).
524      */

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         // For two-way, the change is only remote if it has a remote or has a base locally
532
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             // Log the error and exclude the file from consideration
538
CVSUIPlugin.log(e);
539             return false;
540         }
541     }
542     
543     /*
544      * Fetch the log entries for the info in the given set
545      */

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                 // Run the log command once with no tags
553
fetchLogs(logEntriesCache, set, null, null, monitor);
554             }
555         } catch (CVSException e) {
556             handleException(e);
557         } catch (InterruptedException JavaDoc e) {
558             throw new OperationCanceledException();
559         }
560         
561     }
562     
563     private void fetchLogEntries(LogEntryCache logEntriesCache, CVSCompareSubscriber compareSubscriber, SyncInfoSet set, IProgressMonitor monitor) throws CVSException, InterruptedException JavaDoc {
564         Map JavaDoc localTagMap = getLocalTagMap(set);
565         monitor.beginTask(null, 100 * localTagMap.size());
566         for (Iterator JavaDoc 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     /*
575      * Return the resources grouped by the tag found in the
576      * workspace. The map is CVSTag->SyncInfoSet
577      */

578     private Map JavaDoc getLocalTagMap(SyncInfoSet set) {
579         Map JavaDoc result = new HashMap JavaDoc();
580         for (Iterator JavaDoc 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 JavaDoc {
620         if (compareSubscriber.isMultipleTagComparison()) {
621             Map JavaDoc rootToInfoMap = getRootToInfoMap(compareSubscriber, set);
622             monitor.beginTask(null, 100 * rootToInfoMap.size());
623             for (Iterator JavaDoc 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 JavaDoc getRootToInfoMap(CVSCompareSubscriber compareSubscriber, SyncInfoSet set) {
636         Map JavaDoc rootToInfosMap = new HashMap JavaDoc();
637         IResource[] roots = compareSubscriber.roots();
638         for (Iterator JavaDoc 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; // out of inner loop
651
}
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 JavaDoc {
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 JavaDoc remotes = new ArrayList JavaDoc();
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     /**
682      * Stop any current fetch in process.
683      */

684     public void stopFetching() {
685         try {
686             getEventHandlerJob().cancel();
687             getEventHandlerJob().join();
688         } catch (InterruptedException JavaDoc e) {
689         }
690     }
691 }
692
Popular Tags