KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > ui > mappings > WorkspaceSubscriberContext


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.mappings;
12
13 import java.lang.reflect.InvocationTargetException JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.List JavaDoc;
16
17 import org.eclipse.core.resources.*;
18 import org.eclipse.core.resources.mapping.*;
19 import org.eclipse.core.runtime.*;
20 import org.eclipse.osgi.util.NLS;
21 import org.eclipse.team.core.RepositoryProvider;
22 import org.eclipse.team.core.diff.IDiff;
23 import org.eclipse.team.core.diff.IThreeWayDiff;
24 import org.eclipse.team.core.diff.provider.DiffTree;
25 import org.eclipse.team.core.history.IFileRevision;
26 import org.eclipse.team.core.mapping.*;
27 import org.eclipse.team.core.mapping.provider.ResourceDiffTree;
28 import org.eclipse.team.core.subscribers.Subscriber;
29 import org.eclipse.team.core.subscribers.SubscriberScopeManager;
30 import org.eclipse.team.core.synchronize.SyncInfo;
31 import org.eclipse.team.core.synchronize.SyncInfoFilter;
32 import org.eclipse.team.core.synchronize.SyncInfoFilter.ContentComparisonSyncInfoFilter;
33 import org.eclipse.team.core.variants.IResourceVariant;
34 import org.eclipse.team.internal.ccvs.core.*;
35 import org.eclipse.team.internal.ccvs.core.client.PruneFolderVisitor;
36 import org.eclipse.team.internal.ccvs.core.mapping.CVSActiveChangeSetCollector;
37 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
38 import org.eclipse.team.internal.ccvs.core.resources.RemoteFile;
39 import org.eclipse.team.internal.ccvs.ui.*;
40 import org.eclipse.team.internal.ccvs.ui.Policy;
41 import org.eclipse.team.internal.ccvs.ui.operations.*;
42 import org.eclipse.team.internal.core.mapping.GroupProgressMonitor;
43 import org.eclipse.team.internal.core.subscribers.SubscriberDiffTreeEventHandler;
44
45 public class WorkspaceSubscriberContext extends CVSSubscriberMergeContext {
46
47     public static final class ChangeSetSubscriberScopeManager extends SubscriberScopeManager {
48         private final boolean consultSets;
49
50         private ChangeSetSubscriberScopeManager(String JavaDoc name, ResourceMapping[] mappings, Subscriber subscriber, boolean consultModels, boolean consultSets) {
51             super(name, mappings, subscriber, consultModels);
52             this.consultSets = consultSets;
53         }
54
55         protected ResourceTraversal[] adjustInputTraversals(ResourceTraversal[] traversals) {
56             if (isConsultSets())
57                 return ((CVSActiveChangeSetCollector)CVSUIPlugin.getPlugin().getChangeSetManager()).adjustInputTraversals(traversals);
58             return super.adjustInputTraversals(traversals);
59         }
60
61         public boolean isConsultSets() {
62             return consultSets;
63         }
64     }
65
66     private final int type;
67
68     public static SubscriberScopeManager createWorkspaceScopeManager(ResourceMapping[] mappings, boolean consultModels, final boolean consultChangeSets) {
69         return new ChangeSetSubscriberScopeManager(CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().getName(), mappings, CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber(), consultModels, consultChangeSets);
70     }
71     
72     public static SubscriberScopeManager createUpdateScopeManager(ResourceMapping[] mappings, boolean consultModels) {
73         return new SubscriberScopeManager(CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().getName(), mappings, CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber(), consultModels);
74     }
75     
76     public static WorkspaceSubscriberContext createContext(ISynchronizationScopeManager manager, int type) {
77         CVSWorkspaceSubscriber subscriber = CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber();
78         WorkspaceSubscriberContext mergeContext = new WorkspaceSubscriberContext(subscriber, manager, type);
79         mergeContext.initialize();
80         return mergeContext;
81     }
82     
83     protected WorkspaceSubscriberContext(CVSWorkspaceSubscriber subscriber, ISynchronizationScopeManager manager, int type) {
84         super(subscriber, manager);
85         this.type = type;
86     }
87
88     public void markAsMerged(IDiff[] nodes, boolean inSyncHint, IProgressMonitor monitor) throws CoreException {
89         if (getType() == TWO_WAY) {
90             // For, TWO_WAY merges (i.e. replace) should not adjust sync info
91
// but should remove the node from the tree so that other models do
92
// not modify the file
93
DiffTree tree = ((DiffTree)getDiffTree());
94             try {
95                 tree.beginInput();
96                 for (int i = 0; i < nodes.length; i++) {
97                     IDiff diff = nodes[i];
98                     tree.remove(diff.getPath());
99                 }
100             } finally {
101                 tree.endInput(monitor);
102             }
103         } else {
104             super.markAsMerged(nodes, inSyncHint, monitor);
105         }
106     }
107
108     public void markAsMerged(final IDiff diff, final boolean inSyncHint, IProgressMonitor monitor) throws CoreException {
109         run(new IWorkspaceRunnable() {
110             public void run(IProgressMonitor monitor) throws CoreException {
111                 // Get the latest sync info for the file (i.e. not what is in the set).
112
// We do this because the client may have modified the file since the
113
// set was populated.
114
IResource resource = getDiffTree().getResource(diff);
115                 if (resource.getType() != IResource.FILE) {
116                     if (diff instanceof IThreeWayDiff) {
117                         IThreeWayDiff twd = (IThreeWayDiff) diff;
118                         if (resource.getType() == IResource.FOLDER
119                                 && twd.getKind() == IDiff.ADD
120                                 && twd.getDirection() == IThreeWayDiff.INCOMING
121                                 && resource.exists()) {
122                             // The folder was created by merge
123
SyncInfo info = getSyncInfo(resource);
124                             if (info instanceof CVSSyncInfo) {
125                                 CVSSyncInfo cvsInfo = (CVSSyncInfo) info;
126                                 cvsInfo.makeInSync();
127                             }
128                         }
129                     }
130                     return;
131                 }
132                 if (getType() == TWO_WAY) {
133                     // For, TWO_WAY merges (i.e. replace) should not adjust sync info
134
// but should remove the node from the tree so that other models do
135
// not modify the file
136
((DiffTree)getDiffTree()).remove(diff.getPath());
137                 } else {
138                     SyncInfo info = getSyncInfo(resource);
139                     ensureRemotesMatch(resource, diff, info);
140                     if (info instanceof CVSSyncInfo) {
141                         CVSSyncInfo cvsInfo = (CVSSyncInfo) info;
142                         monitor.beginTask(null, 50 + (inSyncHint ? 100 : 0));
143                         cvsInfo.makeOutgoing(Policy.subMonitorFor(monitor, 50));
144                         if (inSyncHint) {
145                             // Compare the contents of the file with the remote
146
// and make the file in-sync if they match
147
ContentComparisonSyncInfoFilter comparator = new SyncInfoFilter.ContentComparisonSyncInfoFilter(false);
148                             if (resource.getType() == IResource.FILE && info.getRemote() != null) {
149                                 if (comparator.compareContents((IFile)resource, info.getRemote(), Policy.subMonitorFor(monitor, 100))) {
150                                     ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor((IFile)resource);
151                                     cvsFile.checkedIn(null, false /* not a commit */);
152                                 }
153                             }
154                         }
155                         monitor.done();
156                     }
157                 }
158             }
159         }, getMergeRule(diff), IResource.NONE, monitor);
160     }
161
162     protected void makeInSync(final IDiff diff, IProgressMonitor monitor) throws CoreException {
163         run(new IWorkspaceRunnable() {
164             public void run(IProgressMonitor monitor) throws CoreException {
165                 // Get the latest sync info for the file (i.e. not what is in the set).
166
// We do this because the client may have modified the file since the
167
// set was populated.
168
IResource resource = getDiffTree().getResource(diff);
169                 if (resource.getType() != IResource.FILE)
170                     return;
171                 SyncInfo info = getSyncInfo(resource);
172                 ensureRemotesMatch(resource, diff, info);
173                 IResourceVariant remote = info.getRemote();
174                 RemoteFile file = (RemoteFile)remote;
175                 if (file != null)
176                     remote = file.getCachedHandle();
177                 
178                 if (info instanceof CVSSyncInfo) {
179                     CVSSyncInfo cvsInfo = (CVSSyncInfo) info;
180                     cvsInfo.makeOutgoing(monitor);
181                     if (resource.getType() == IResource.FILE && info.getRemote() != null) {
182                         ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor((IFile)resource);
183                         if (remote != null && remote instanceof RemoteFile){
184                             cvsFile.setExecutable(((RemoteFile)remote).isExecutable());
185                             cvsFile.setTimeStamp(((RemoteFile) remote).getTimeStamp());
186                             cvsFile.setReadOnly(getReadOnly(cvsFile));
187                         }
188                         cvsFile.checkedIn(null , false /* not a commit */);
189                     }
190                 }
191             }
192         }, getMergeRule(diff), IResource.NONE, monitor);
193     }
194     
195     protected boolean getReadOnly(ICVSFile cvsFile) {
196         IResource resource = cvsFile.getIResource();
197         RepositoryProvider provider = RepositoryProvider.getProvider(resource.getProject());
198         if (provider instanceof CVSTeamProvider) {
199             CVSTeamProvider ctp = (CVSTeamProvider) provider;
200             try {
201                 return ctp.isWatchEditEnabled();
202             } catch (CVSException e) {
203                 CVSUIPlugin.log(e);
204             }
205         }
206         return false;
207     }
208
209     protected void ensureRemotesMatch(IResource resource, IDiff node, SyncInfo info) throws CVSException {
210         IResourceVariant variant = info.getRemote();
211         IFileRevision remote = getRemote(node);
212         if (variant != null && remote != null && remote instanceof IFileRevision) {
213             String JavaDoc ci1 = variant.getContentIdentifier();
214             String JavaDoc ci2 = ((IFileRevision)remote).getContentIdentifier();
215             if (!ci1.equals(ci2)) {
216                 throw new CVSException(NLS.bind(CVSUIMessages.WorkspaceSubscriberContext_0, resource.getFullPath().toString()));
217             }
218         }
219     }
220
221     private IFileRevision getRemote(IDiff node) {
222         if (node == null) return null;
223         if (node instanceof IThreeWayDiff) {
224             IThreeWayDiff twd = (IThreeWayDiff) node;
225             return getRemote(twd.getRemoteChange());
226         }
227         if (node instanceof IResourceDiff) {
228             IResourceDiff rd = (IResourceDiff) node;
229             return rd.getAfterState();
230         }
231         return null;
232     }
233
234     /* (non-Javadoc)
235      * @see org.eclipse.team.core.mapping.MergeContext#merge(org.eclipse.team.core.diff.IDiffNode, boolean, org.eclipse.core.runtime.IProgressMonitor)
236      */

237     public IStatus merge(IDiff delta, boolean force, IProgressMonitor monitor) throws CoreException {
238         if (getMergeType() == ISynchronizationContext.TWO_WAY) {
239             force = true;
240         }
241         // First, verify that the provided delta matches the current state
242
// i.e. it is possible that a concurrent change has occurred
243
IThreeWayDiff currentDiff = (IThreeWayDiff)getSubscriber().getDiff(getDiffTree().getResource(delta));
244         if (currentDiff == null
245                 || currentDiff.getKind() == IDiff.NO_CHANGE
246                 || (currentDiff.getDirection() == IThreeWayDiff.OUTGOING && !force)) {
247             // Seems like this one was already merged so return OK
248
return Status.OK_STATUS;
249         }
250         if (!equals(currentDiff, (IThreeWayDiff)delta)) {
251             throw new CVSException(NLS.bind(CVSUIMessages.CVSMergeContext_1, delta.getPath()));
252         }
253         try {
254             monitor.beginTask(null, 100);
255             IStatus status = super.merge(delta, force, Policy.subMonitorFor(monitor, 99));
256             if (status.isOK()) {
257                 IResource resource = getDiffTree().getResource(delta);
258                 if (resource.getType() == IResource.FILE && !resource.exists()) {
259                     ICVSResource localResource = CVSWorkspaceRoot.getCVSResourceFor(resource);
260                     localResource.unmanage(Policy.subMonitorFor(monitor, 1));
261                 }
262                 pruneEmptyParents(new IDiff[] { delta });
263             }
264             return status;
265         } finally {
266             monitor.done();
267         }
268     }
269
270     private boolean equals(IThreeWayDiff currentDiff, IThreeWayDiff otherDiff) {
271         return currentDiff.getKind() == otherDiff.getKind()
272             && currentDiff.getDirection() == otherDiff.getDirection();
273     }
274
275     private void pruneEmptyParents(IDiff[] deltas) throws CVSException {
276         // TODO: A more explicit tie in to the pruning mechanism would be preferable.
277
// i.e. I don't like referencing the option and visitor directly
278
if (!CVSProviderPlugin.getPlugin().getPruneEmptyDirectories()) return;
279         ICVSResource[] cvsResources = new ICVSResource[deltas.length];
280         for (int i = 0; i < cvsResources.length; i++) {
281             cvsResources[i] = CVSWorkspaceRoot.getCVSResourceFor(getDiffTree().getResource(deltas[i]));
282         }
283         new PruneFolderVisitor().visit(
284             CVSWorkspaceRoot.getCVSFolderFor(ResourcesPlugin.getWorkspace().getRoot()),
285             cvsResources);
286     }
287     
288     /* (non-Javadoc)
289      * @see org.eclipse.team.core.mapping.provider.MergeContext#getMergeType()
290      */

291     public int getMergeType() {
292         return type;
293     }
294     
295     /* (non-Javadoc)
296      * @see org.eclipse.team.core.subscribers.SubscriberMergeContext#refresh(org.eclipse.core.resources.mapping.ResourceTraversal[], int, org.eclipse.core.runtime.IProgressMonitor)
297      */

298     public void refresh(final ResourceTraversal[] traversals, int flags, IProgressMonitor monitor) throws CoreException {
299         SubscriberDiffTreeEventHandler handler = getHandler();
300         if (handler != null) {
301             GroupProgressMonitor group = getGroup(monitor);
302             if (group != null)
303                 handler.setProgressGroupHint(group.getGroup(), group.getTicks());
304             handler.initializeIfNeeded();
305             ((CVSWorkspaceSubscriber)getSubscriber()).refreshWithContentFetch(traversals, monitor);
306             runInBackground(new IWorkspaceRunnable() {
307                 public void run(IProgressMonitor monitor) throws CoreException {
308                     cacheContents(traversals, getDiffTree(), true, monitor);
309                 }
310             });
311         } else {
312             super.refresh(traversals, flags, monitor);
313             runInBackground(new IWorkspaceRunnable() {
314                 public void run(IProgressMonitor monitor) throws CoreException {
315                     cacheContents(traversals, getDiffTree(), false, monitor);
316                 }
317             });
318         }
319     }
320     
321     private SubscriberDiffTreeEventHandler getHandler() {
322         Object JavaDoc o = getAdapter(SubscriberDiffTreeEventHandler.class);
323         if (o instanceof SubscriberDiffTreeEventHandler) {
324             return (SubscriberDiffTreeEventHandler) o;
325         }
326         return null;
327     }
328
329     private GroupProgressMonitor getGroup(IProgressMonitor monitor) {
330         if (monitor instanceof GroupProgressMonitor) {
331             return (GroupProgressMonitor) monitor;
332         }
333         if (monitor instanceof ProgressMonitorWrapper) {
334             ProgressMonitorWrapper wrapper = (ProgressMonitorWrapper) monitor;
335             return getGroup(wrapper.getWrappedProgressMonitor());
336         }
337         return null;
338     }
339     
340     protected void cacheContents(final ResourceTraversal[] traversals, IResourceDiffTree tree, boolean baseOnly, IProgressMonitor monitor) throws CVSException {
341         // cache the base and remote contents
342
// TODO: Refreshing and caching now takes 3 round trips.
343
// OPTIMIZE: remote state and contents could be obtained in 1
344
// OPTIMIZE: Based could be avoided if we always cached base locally
345
ResourceMapping[] mappings = new ResourceMapping[] { new ResourceMapping() {
346             public Object JavaDoc getModelObject() {
347                 return WorkspaceSubscriberContext.this;
348             }
349             public IProject[] getProjects() {
350                 return ResourcesPlugin.getWorkspace().getRoot().getProjects();
351             }
352             public ResourceTraversal[] getTraversals(ResourceMappingContext context, IProgressMonitor monitor) throws CoreException {
353                 return traversals;
354             }
355             public boolean contains(ResourceMapping mapping) {
356                 return false;
357             }
358             public String JavaDoc getModelProviderId() {
359                 return ModelProvider.RESOURCE_MODEL_PROVIDER_ID;
360             }
361         }};
362         try {
363             monitor.beginTask(null, 50);
364             new CacheBaseContentsOperation(null, mappings, tree, true).run(Policy.subMonitorFor(monitor, 25));
365             if (!baseOnly) {
366                 new CacheRemoteContentsOperation(null, mappings, tree).run(Policy.subMonitorFor(monitor, 25));
367             }
368         } catch (InvocationTargetException JavaDoc e) {
369             throw CVSException.wrapException(e);
370         } catch (InterruptedException JavaDoc e) {
371             // Ignore
372
} finally {
373             monitor.done();
374         }
375     }
376     
377     public IStatus merge(IDiff[] deltas, boolean force, IProgressMonitor monitor) throws CoreException {
378         try {
379             if (deltas.length == 0)
380                 return Status.OK_STATUS;
381             String JavaDoc taskName = getMergeTaskName(deltas, force);
382             monitor.beginTask(taskName, 100);
383             monitor.setTaskName(taskName);
384             cacheContents(getTraversals(deltas), getDiffTree(deltas), false, Policy.subMonitorFor(monitor, 30));
385             return super.merge(deltas, force, Policy.subMonitorFor(monitor, 70));
386         } finally {
387             monitor.done();
388         }
389     }
390
391     private String JavaDoc getMergeTaskName(IDiff[] deltas, boolean force) {
392         if (force) {
393             if (deltas.length == 1) {
394                 return NLS.bind(CVSUIMessages.WorkspaceSubscriberContext_1, getDiffTree().getResource(deltas[0]).getFullPath());
395             }
396             return NLS.bind(CVSUIMessages.WorkspaceSubscriberContext_2, new Integer JavaDoc(deltas.length));
397         }
398         if (deltas.length == 1) {
399             return NLS.bind(CVSUIMessages.WorkspaceSubscriberContext_3, getDiffTree().getResource(deltas[0]).getFullPath());
400         }
401         return NLS.bind(CVSUIMessages.WorkspaceSubscriberContext_4, new Integer JavaDoc(deltas.length));
402     }
403
404     private ResourceTraversal[] getTraversals(IDiff[] deltas) {
405         List JavaDoc result = new ArrayList JavaDoc();
406         for (int i = 0; i < deltas.length; i++) {
407             IDiff diff = deltas[i];
408             IResource resource = ResourceDiffTree.getResourceFor(diff);
409             if (resource != null) {
410                 result.add(resource);
411             }
412         }
413         return new ResourceTraversal[] {
414                 new ResourceTraversal((IResource[]) result.toArray(new IResource[result.size()]), IResource.DEPTH_ZERO, IResource.NONE)
415         };
416     }
417
418     private IResourceDiffTree getDiffTree(IDiff[] deltas) {
419         ResourceDiffTree tree = new ResourceDiffTree();
420         for (int i = 0; i < deltas.length; i++) {
421             IDiff diff = deltas[i];
422             tree.add(diff);
423         }
424         return tree;
425     }
426     
427     protected void performReplace(IDiff diff, IProgressMonitor monitor) throws CoreException {
428         IResource resource = ResourceDiffTree.getResourceFor(diff);
429         if (resource.getType() == IResource.FILE){
430             IFile file = (IFile) resource;
431             ICVSFile mFile = CVSWorkspaceRoot.getCVSFileFor(file);
432             try {
433                 // The file may have been set as read-only by a previous checkout/update
434
if (mFile.isReadOnly()) mFile.setReadOnly(false);
435             } catch (CVSException e) {
436                 // Just log and keep going
437
CVSProviderPlugin.log(e);
438             }
439         }
440         super.performReplace(diff, monitor);
441
442     }
443 }
Popular Tags