KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > core > CVSWorkspaceSubscriber


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.core;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.List JavaDoc;
15
16 import org.eclipse.core.resources.*;
17 import org.eclipse.core.resources.mapping.ResourceMapping;
18 import org.eclipse.core.resources.mapping.ResourceTraversal;
19 import org.eclipse.core.runtime.*;
20 import org.eclipse.osgi.util.NLS;
21 import org.eclipse.team.core.*;
22 import org.eclipse.team.core.diff.IDiff;
23 import org.eclipse.team.core.diff.IThreeWayDiff;
24 import org.eclipse.team.core.subscribers.*;
25 import org.eclipse.team.core.synchronize.SyncInfo;
26 import org.eclipse.team.core.synchronize.SyncInfoSet;
27 import org.eclipse.team.core.variants.*;
28 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
29 import org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer;
30 import org.eclipse.team.internal.ccvs.core.syncinfo.*;
31 import org.eclipse.team.internal.ccvs.core.util.ResourceStateChangeListeners;
32 import org.eclipse.team.internal.core.subscribers.ActiveChangeSetManager;
33
34 /**
35  * CVSWorkspaceSubscriber
36  */

37 public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IResourceStateChangeListener {
38     
39     private CVSResourceVariantTree baseTree, remoteTree;
40
41     // qualified name for remote sync info
42
private static final String JavaDoc REMOTE_RESOURCE_KEY = "remote-resource-key"; //$NON-NLS-1$
43

44     private boolean contentFetch;
45     
46     CVSWorkspaceSubscriber(QualifiedName id, String JavaDoc name) {
47         super(id, name);
48         
49         // install sync info participant
50
ResourceVariantByteStore baseSynchronizer = new CVSBaseResourceVariantTree();
51         baseTree = new CVSResourceVariantTree(baseSynchronizer, null, getCacheFileContentsHint()) {
52             public IResource[] refresh(IResource[] resources, int depth, IProgressMonitor monitor) throws TeamException {
53                 // TODO Ensure that file contents are cached for modified local files
54
try {
55                     monitor.beginTask(null, 100);
56                     return new IResource[0];
57                 } finally {
58                     monitor.done();
59                 }
60             }
61         };
62         CVSDescendantResourceVariantByteStore remoteSynchronizer = new CVSDescendantResourceVariantByteStore(
63                 baseSynchronizer,
64                 new PersistantResourceVariantByteStore(new QualifiedName(SYNC_KEY_QUALIFIER, REMOTE_RESOURCE_KEY)));
65         remoteTree = new CVSResourceVariantTree(remoteSynchronizer, null, getCacheFileContentsHint()) {
66             public boolean isCacheFileContentsHint() {
67                 return getCacheFileContentsHint();
68             }
69         };
70         
71         ResourceStateChangeListeners.getListener().addResourceStateChangeListener(this);
72     }
73
74     /*
75      * Return the list of projects shared with a CVS team provider.
76      *
77      * [Issue : this will have to change when folders can be shared with
78      * a team provider instead of the current project restriction]
79      * (non-Javadoc)
80      * @see org.eclipse.team.core.sync.ISyncTreeSubscriber#roots()
81      */

82     public IResource[] roots() {
83         List JavaDoc result = new ArrayList JavaDoc();
84         IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
85         for (int i = 0; i < projects.length; i++) {
86             IProject project = projects[i];
87             if(project.isOpen()) {
88                 RepositoryProvider provider = RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId());
89                 if(provider != null) {
90                     result.add(project);
91                 }
92             }
93         }
94         return (IProject[]) result.toArray(new IProject[result.size()]);
95     }
96     
97     /* (non-Javadoc)
98      * @see org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener#resourceSyncInfoChanged(org.eclipse.core.resources.IResource[])
99      */

100     public void resourceSyncInfoChanged(IResource[] changedResources) {
101         internalResourceSyncInfoChanged(changedResources, true);
102     }
103
104     private void internalResourceSyncInfoChanged(IResource[] changedResources, boolean canModifyWorkspace) {
105         getRemoteByteStore().handleResourceChanges(changedResources, canModifyWorkspace);
106         fireTeamResourceChange(SubscriberChangeEvent.asSyncChangedDeltas(this, changedResources));
107     }
108
109     /* (non-Javadoc)
110      * @see org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener#externalSyncInfoChange(org.eclipse.core.resources.IResource[])
111      */

112     public void externalSyncInfoChange(IResource[] changedResources) {
113         internalResourceSyncInfoChanged(changedResources, false);
114     }
115
116     /* (non-Javadoc)
117      * @see org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener#resourceModified(org.eclipse.core.resources.IResource[])
118      */

119     public void resourceModified(IResource[] changedResources) {
120         // This is only ever called from a delta POST_CHANGE
121
// which causes problems since the workspace tree is closed
122
// for modification and we flush the sync info in resourceSyncInfoChanged
123

124         // Since the listeners of the Subscriber will also listen to deltas
125
// we don't need to propogate this.
126
}
127
128     /* (non-Javadoc)
129      * @see org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener#projectConfigured(org.eclipse.core.resources.IProject)
130      */

131     public void projectConfigured(IProject project) {
132         SubscriberChangeEvent delta = new SubscriberChangeEvent(this, ISubscriberChangeEvent.ROOT_ADDED, project);
133         fireTeamResourceChange(new SubscriberChangeEvent[] {delta});
134     }
135
136     /* (non-Javadoc)
137      * @see org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener#projectDeconfigured(org.eclipse.core.resources.IProject)
138      */

139     public void projectDeconfigured(IProject project) {
140         try {
141             getRemoteTree().flushVariants(project, IResource.DEPTH_INFINITE);
142         } catch (TeamException e) {
143             CVSProviderPlugin.log(e);
144         }
145         SubscriberChangeEvent delta = new SubscriberChangeEvent(this, ISubscriberChangeEvent.ROOT_REMOVED, project);
146         fireTeamResourceChange(new SubscriberChangeEvent[] {delta});
147     }
148
149     public void setRemote(IResource resource, IResourceVariant remote, IProgressMonitor monitor) throws TeamException {
150         // TODO: This exposes internal behavior to much
151
IResource[] changedResources =
152             ((CVSResourceVariantTree)getRemoteTree()).collectChanges(resource, remote, IResource.DEPTH_INFINITE, monitor);
153         if (changedResources.length != 0) {
154             fireTeamResourceChange(SubscriberChangeEvent.asSyncChangedDeltas(this, changedResources));
155         }
156     }
157
158     /* (non-Javadoc)
159      * @see org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber#getBaseSynchronizationCache()
160      */

161     protected IResourceVariantTree getBaseTree() {
162         return baseTree;
163     }
164
165     /* (non-Javadoc)
166      * @see org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber#getRemoteSynchronizationCache()
167      */

168     protected IResourceVariantTree getRemoteTree() {
169         return remoteTree;
170     }
171     
172     /* (non-Javadoc)
173      * @see org.eclipse.team.core.subscribers.Subscriber#collectOutOfSync(org.eclipse.core.resources.IResource[], int, org.eclipse.team.core.synchronize.SyncInfoSet, org.eclipse.core.runtime.IProgressMonitor)
174      */

175     public void collectOutOfSync(IResource[] resources, int depth, final SyncInfoSet set, final IProgressMonitor monitor) {
176         monitor.beginTask(null, IProgressMonitor.UNKNOWN);
177         for (int i = 0; i < resources.length; i++) {
178             IResource resource = resources[i];
179             try {
180                 if (!isSupervised(resource)) {
181                     return;
182                 }
183             } catch (TeamException e) {
184                 // fallthrough and try to collect sync info
185
CVSProviderPlugin.log(e);
186             }
187             try {
188                 visit(resource, new IResourceVisitor() {
189                     public boolean visit(IResource innerResource) throws CoreException {
190                         try {
191                             Policy.checkCanceled(monitor);
192                             if (innerResource.getType() != IResource.FILE) {
193                                 monitor.subTask(NLS.bind(CVSMessages.CVSWorkspaceSubscriber_1, new String JavaDoc[] { innerResource.getFullPath().toString() }));
194                             }
195                             if (isOutOfSync(innerResource, monitor)) {
196                                 SyncInfo info = getSyncInfo(innerResource);
197                                 if (info != null && info.getKind() != 0) {
198                                     set.add(info);
199                                 }
200                             }
201                         } catch (TeamException e) {
202                             set.addError(new TeamStatus(
203                                     IStatus.ERROR, CVSProviderPlugin.ID, ITeamStatus.RESOURCE_SYNC_INFO_ERROR,
204                                     NLS.bind(CVSMessages.CVSWorkspaceSubscriber_2, new String JavaDoc[] { innerResource.getFullPath().toString(), e.getMessage() }), e, innerResource));
205                         }
206                         return true;
207                     }
208                 }, depth);
209             } catch (CoreException e) {
210                 set.addError(new TeamStatus(
211                         IStatus.ERROR, CVSProviderPlugin.ID, ITeamStatus.SYNC_INFO_SET_ERROR,
212                         e.getMessage(), e, ResourcesPlugin.getWorkspace().getRoot()));
213             }
214         }
215         monitor.done();
216     }
217     
218     private void visit(IResource resource, IResourceVisitor visitor, int depth) throws CoreException {
219         boolean keepGoing = visitor.visit(resource);
220         if (keepGoing && depth != IResource.DEPTH_ZERO) {
221             IResource[] members = members(resource);
222             for (int i = 0; i < members.length; i++) {
223                 IResource member = members[i];
224                 visit(member, visitor, depth == IResource.DEPTH_ONE ? IResource.DEPTH_ZERO : IResource.DEPTH_INFINITE);
225             }
226         }
227     }
228
229     /* internal use only */ boolean isOutOfSync(IResource resource, IProgressMonitor monitor) throws TeamException {
230         return (hasIncomingChange(resource) || hasOutgoingChange(resource, monitor));
231     }
232     
233     private boolean hasIncomingChange(IResource resource) throws TeamException {
234         return getRemoteByteStore().isVariantKnown(resource);
235     }
236     
237     private boolean hasOutgoingChange(IResource resource, IProgressMonitor monitor) throws CVSException {
238         if (resource.getType() == IResource.PROJECT || resource.getType() == IResource.ROOT) {
239             // a project (or the workspace root) cannot have outgoing changes
240
return false;
241         }
242         int state = EclipseSynchronizer.getInstance().getModificationState(resource.getParent());
243         if (state == ICVSFile.CLEAN) {
244             // if the parent is known to be clean then the resource must also be clean
245
return false;
246         }
247         if (resource.getType() == IResource.FILE) {
248             // A file is an outgoing change if it is modified
249
ICVSFile file = CVSWorkspaceRoot.getCVSFileFor((IFile)resource);
250             return file.isModified(monitor);
251         } else {
252             // A folder is an outgoing change if it is not a CVS folder and not ignored
253
ICVSFolder folder = CVSWorkspaceRoot.getCVSFolderFor((IContainer)resource);
254             return !folder.isCVSFolder() && !folder.isIgnored();
255         }
256     }
257     
258     /*
259      * TODO: Should not need to access this here
260      */

261     private CVSDescendantResourceVariantByteStore getRemoteByteStore() {
262         return (CVSDescendantResourceVariantByteStore)((CVSResourceVariantTree)getRemoteTree()).getByteStore();
263     }
264
265     /**
266      * Update the remote tree to the base
267      * @param folder
268      * @param recurse
269      */

270     public void updateRemote(CVSTeamProvider provider, ICVSFolder folder, boolean recurse, IProgressMonitor monitor) throws TeamException {
271         try {
272             monitor.beginTask(null, IProgressMonitor.UNKNOWN);
273             IResource resource = folder.getIResource();
274             if (resource != null) {
275                 ICVSResource tree = buildBaseTree(
276                         resource,
277                         false,
278                         Policy.subMonitorFor(monitor, 50));
279                 setRemote(resource, (IResourceVariant)tree, Policy.subMonitorFor(monitor, 50));
280             }
281         } finally {
282             monitor.done();
283         }
284     }
285     
286     public ICVSRemoteResource buildBaseTree(IResource resource, boolean immutable, IProgressMonitor monitor) throws TeamException {
287         try {
288             monitor.beginTask(null, IProgressMonitor.UNKNOWN);
289             return ((CVSResourceVariantTree)getBaseTree()).buildTree(null, resource, immutable, monitor);
290         } finally {
291             monitor.done();
292         }
293     }
294
295     public ICVSRemoteResource buildRemoteTree(IResource resource, boolean immutable, IProgressMonitor monitor) throws TeamException {
296         try {
297             monitor.beginTask(null, IProgressMonitor.UNKNOWN);
298             return ((CVSResourceVariantTree)getRemoteTree()).buildTree(null, resource, immutable, monitor);
299         } finally {
300             monitor.done();
301         }
302     }
303     
304     /* (non-Javadoc)
305      * @see org.eclipse.team.core.subscribers.Subscriber#getState(org.eclipse.core.resources.mapping.ResourceMapping, int, org.eclipse.core.runtime.IProgressMonitor)
306      */

307     public int getState(ResourceMapping mapping, int stateMask, IProgressMonitor monitor) throws CoreException {
308         if ((stateMask & IThreeWayDiff.INCOMING) == 0) {
309             // If we're only interested in outgoing changes, used the cached modified state
310
ResourceTraversal[] traversals = mapping.getTraversals(new SubscriberResourceMappingContext(this, false), monitor);
311             if (hasLocalChanges(traversals, monitor)) {
312                 int state = IThreeWayDiff.OUTGOING;
313                 state |= getOutgoingKind(traversals, monitor);
314                 return state;
315             } else {
316                 return 0;
317             }
318         }
319         return super.getState(mapping, stateMask, monitor);
320     }
321     
322     private int getOutgoingKind(ResourceTraversal[] traversals, IProgressMonitor monitor) throws CoreException {
323         int kind = 0;
324         for (int i = 0; i < traversals.length; i++) {
325             ResourceTraversal traversal = traversals[i];
326             IResource[] resources = traversal.getResources();
327             for (int j = 0; j < resources.length; j++) {
328                 IResource resource = resources[j];
329                 IDiff node = getDiff(resource);
330                 if (node == null)
331                     return IDiff.CHANGE;
332                 int nextKind = node.getKind();
333                 if (kind == 0)
334                     kind = nextKind;
335                 if (nextKind != kind || nextKind == IDiff.CHANGE)
336                     return IDiff.CHANGE;
337             }
338         }
339         return kind;
340     }
341
342     /* (non-Javadoc)
343      * @see org.eclipse.team.core.subscribers.Subscriber#hasLocalChanges(org.eclipse.core.resources.mapping.ResourceTraversal[], org.eclipse.core.runtime.IProgressMonitor)
344      */

345     public boolean hasLocalChanges(ResourceTraversal[] traversals, IProgressMonitor monitor) throws CoreException {
346         monitor = Policy.monitorFor(monitor);
347         for (int i = 0; i < traversals.length; i++) {
348             ResourceTraversal traversal = traversals[i];
349             IResource[] resources = traversal.getResources();
350             switch (traversal.getDepth()) {
351             case IResource.DEPTH_ZERO:
352                 for (int j = 0; j < resources.length; j++) {
353                     IResource resource = resources[j];
354                     if (isDirectlyDirty(resource, monitor)) {
355                         return true;
356                     }
357                 }
358                 break;
359             case IResource.DEPTH_INFINITE:
360                 for (int j = 0; j < resources.length; j++) {
361                     IResource resource = resources[j];
362                     if (isDirty(resource, monitor)) {
363                         return true;
364                     }
365                 }
366                 break;
367             case IResource.DEPTH_ONE:
368                 for (int j = 0; j < resources.length; j++) {
369                     IResource resource = resources[j];
370                     if (isDirectlyDirty(resource, monitor)) {
371                         return true;
372                     }
373                     IResource[] children = members(resource);
374                     for (int k = 0; k < children.length; k++) {
375                         IResource child = children[k];
376                         if (isDirectlyDirty(child, monitor)) {
377                             return true;
378                         }
379                     }
380                 }
381                 break;
382             }
383         }
384         return false;
385     }
386     
387     private boolean isDirectlyDirty(IResource resource, IProgressMonitor monitor) throws CoreException {
388         if (resource.getType() == IResource.FILE) {
389             if (isDirty(resource, monitor))
390                 return true;
391         } else {
392             IDiff node = getDiff(resource);
393             if (node != null
394                     && node instanceof IThreeWayDiff
395                     && ((IThreeWayDiff)node).getLocalChange() != null
396                     && ((IThreeWayDiff)node).getLocalChange().getKind() != IDiff.NO_CHANGE)
397                 return true;
398         }
399         return false;
400     }
401     
402     public boolean isDirty(final ICVSResource cvsResource, IProgressMonitor monitor) throws CVSException {
403         if (cvsResource.exists())
404             return !cvsResource.isIgnored() && cvsResource.isModified(monitor);
405         return cvsResource.isManaged() && cvsResource.isModified(monitor);
406     }
407     
408     public boolean isDirty(IResource resource, IProgressMonitor monitor) throws CVSException {
409         try {
410             ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource);
411             return isDirty(cvsResource, monitor);
412         } catch (CVSException e) {
413             //if we get an error report it to the log but assume dirty.
414
boolean accessible = resource.getProject().isAccessible();
415             if (accessible) {
416                 throw e;
417             }
418             // Return dirty if the project is open and clean otherwise
419
return accessible;
420         }
421
422     }
423
424     public Object JavaDoc getAdapter(Class JavaDoc adapter) {
425         if (adapter == ActiveChangeSetManager.class) {
426             return CVSProviderPlugin.getPlugin().getChangeSetManager();
427         }
428         return super.getAdapter(adapter);
429     }
430
431     public void refreshWithContentFetch(ResourceTraversal[] traversals, IProgressMonitor monitor) throws TeamException {
432         try {
433             contentFetch = true;
434             refresh(traversals, monitor);
435         } finally {
436             contentFetch = false;
437         }
438     }
439     
440     protected boolean getCacheFileContentsHint() {
441         return contentFetch;
442     }
443 }
444
Popular Tags