KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > core > subscribers > SubscriberResourceMappingContext


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 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.core.subscribers;
12
13 import java.util.*;
14
15 import org.eclipse.core.internal.resources.mapping.*;
16 import org.eclipse.core.resources.*;
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.team.core.TeamException;
19 import org.eclipse.team.core.subscribers.Subscriber;
20 import org.eclipse.team.core.synchronize.SyncInfo;
21 import org.eclipse.team.core.synchronize.SyncInfoFilter;
22 import org.eclipse.team.core.variants.IResourceVariant;
23 import org.eclipse.team.internal.core.*;
24
25 /**
26  * A resource mapping context that provides the client access to the remote state
27  * of local resources using a subscriber. It uses a <code>SyncInfoFilter</code>
28  * to determine whether the local contents differ from the remote contents.
29  * This allows the context to be used for different operations (check-in,
30  * update and replace).
31  * @since 3.1
32  */

33 public class SubscriberResourceMappingContext extends RemoteResourceMappingContext {
34     
35     private final Subscriber subscriber;
36     private final SyncInfoFilter contentDiffFilter;
37     
38     // Lists used to keep track of resources that have been refreshed
39
Set shallowRefresh = new HashSet();
40     Set deepRefresh = new HashSet();
41     
42     /**
43      * Return a resource mapping context suitable for a replace operations.
44      * @return a resource mapping context suitable for a replace operations
45      */

46     public static ResourceMappingContext getReplaceContext(Subscriber subscriber) {
47         return new SubscriberResourceMappingContext(subscriber, new SyncInfoFilter() {
48             public boolean select(SyncInfo info, IProgressMonitor monitor) {
49                 if (info != null) {
50                     int direction = info.getKind() & SyncInfo.DIRECTION_MASK;
51                     // When replacing, both incoming and outgoing changes are needed
52
return direction != 0;
53                 }
54                 return false;
55             }
56         
57         });
58     }
59     
60     /**
61      * Return a resource mapping context suitable for a update operations.
62      * That is, operations that fetch the latest remote changes from the
63      * server to update the local workspace resources.
64      * @return a resource mapping context suitable for a update operations
65      */

66     public static ResourceMappingContext getUpdateContext(Subscriber subscriber) {
67         return new SubscriberResourceMappingContext(subscriber, new SyncInfoFilter() {
68             public boolean select(SyncInfo info, IProgressMonitor monitor) {
69                 if (info != null) {
70                     int direction = info.getKind() & SyncInfo.DIRECTION_MASK;
71                     // When updating, only incoming and conflicting changes are needed
72
return direction == SyncInfo.INCOMING || direction == SyncInfo.CONFLICTING ;
73                 }
74                 return false;
75             }
76         
77         });
78     }
79     
80     /**
81      * Return a resource mapping context suitable for a check-in (or commit) operations.
82      * That is, operations that uploads the latest local changes to the
83      * server from the local workspace resources, typically creating a new version of the resource.
84      * @return a resource mapping context suitable for a check-in operations
85      */

86     public static ResourceMappingContext getCheckInContext(Subscriber subscriber) {
87         return new SubscriberResourceMappingContext(subscriber, new SyncInfoFilter() {
88             public boolean select(SyncInfo info, IProgressMonitor monitor) {
89                 if (info != null) {
90                     int direction = info.getKind() & SyncInfo.DIRECTION_MASK;
91                     // When committing, only outgoing and conflicting changes are needed
92
return direction == SyncInfo.OUTGOING || direction == SyncInfo.CONFLICTING ;
93                 }
94                 return false;
95             }
96         
97         });
98     }
99
100     /**
101      * Return a resource mapping context suitable for comparison operations.
102      * Comparisons require that any out-of-sync resources have contents
103      * that differ.
104      * @return a resource mapping context suitable for compare operations
105      */

106     public static ResourceMappingContext getCompareContext(Subscriber subscriber) {
107         return new SubscriberResourceMappingContext(subscriber, new SyncInfoFilter() {
108             public boolean select(SyncInfo info, IProgressMonitor monitor) {
109                 if (info != null) {
110                     return info.getKind() != SyncInfo.IN_SYNC;
111                 }
112                 return false;
113             }
114         
115         });
116     }
117     
118     /**
119      * Create a resource mapping context for the given subscriber
120      * @param subscriber the subscriber
121      * @param contentDiffFilter filter that is used to determine if the remote contents differ
122      * from the local contents
123      */

124     public SubscriberResourceMappingContext(Subscriber subscriber, SyncInfoFilter contentDiffFilter) {
125         this.subscriber = subscriber;
126         this.contentDiffFilter = contentDiffFilter;
127     }
128
129     /* (non-Javadoc)
130      * @see org.eclipse.core.resources.mapping.ResourceMappingContext#contentDiffers(org.eclipse.core.resources.IFile, org.eclipse.core.runtime.IProgressMonitor)
131      */

132     public final boolean contentDiffers(IFile file, IProgressMonitor monitor) throws CoreException {
133         try {
134             monitor.beginTask(null, 100);
135             ensureRefreshed(file, IResource.DEPTH_ZERO, NONE, Policy.subMonitorFor(monitor, 10));
136             SyncInfo syncInfo = subscriber.getSyncInfo(file);
137             validateRemote(file, syncInfo);
138             return syncInfo != null && contentDiffFilter.select(syncInfo, Policy.subMonitorFor(monitor, 90));
139         } finally {
140             monitor.done();
141         }
142     }
143
144     /* (non-Javadoc)
145      * @see org.eclipse.core.resources.mapping.ResourceMappingContext#fetchContents(org.eclipse.core.resources.IFile, org.eclipse.core.runtime.IProgressMonitor)
146      */

147     public final IStorage fetchContents(IFile file, IProgressMonitor monitor) throws CoreException {
148         try {
149             monitor.beginTask(null, 100);
150             ensureRefreshed(file, IResource.DEPTH_ZERO, FILE_CONTENTS_REQUIRED, Policy.subMonitorFor(monitor, 10));
151             SyncInfo syncInfo = subscriber.getSyncInfo(file);
152             IResourceVariant remote = validateRemote(file, syncInfo);
153             if (remote == null) {
154                 return null;
155             }
156             return remote.getStorage(Policy.subMonitorFor(monitor, 90));
157         } finally {
158             monitor.done();
159         }
160     }
161
162     /* (non-Javadoc)
163      * @see org.eclipse.core.resources.mapping.ResourceMappingContext#fetchMembers(org.eclipse.core.resources.IContainer, org.eclipse.core.runtime.IProgressMonitor)
164      */

165     public final IResource[] fetchMembers(IContainer container, IProgressMonitor monitor) throws CoreException {
166         try {
167             monitor.beginTask(null, 100);
168             ensureRefreshed(container, IResource.DEPTH_ONE, NONE, Policy.subMonitorFor(monitor, 100));
169             SyncInfo syncInfo = subscriber.getSyncInfo(container);
170             if (validateRemote(container, syncInfo) == null) {
171                 // There is no remote so return null to indicate this
172
return null;
173             }
174             return subscriber.members(container);
175         } finally {
176             monitor.done();
177         }
178     }
179
180     /* (non-Javadoc)
181      * @see org.eclipse.core.resources.mapping.ResourceMappingContext#refresh(org.eclipse.core.resources.mapping.ResourceTraversal[], int, org.eclipse.core.runtime.IProgressMonitor)
182      */

183     public final void refresh(ResourceTraversal[] traversals, int flags, IProgressMonitor monitor) throws CoreException {
184         Set zero = new HashSet();
185         Set one = new HashSet();
186         Set infinite = new HashSet();
187         for (int i = 0; i < traversals.length; i++) {
188             ResourceTraversal traversal = traversals[i];
189             switch (traversal.getDepth()) {
190             case IResource.DEPTH_INFINITE:
191                 infinite.addAll(Arrays.asList(traversal.getResources()));
192                 break;
193             case IResource.DEPTH_ONE:
194                 one.addAll(Arrays.asList(traversal.getResources()));
195                 break;
196             case IResource.DEPTH_ZERO:
197                 zero.addAll(Arrays.asList(traversal.getResources()));
198                 break;
199             }
200         }
201         if (!zero.isEmpty())
202             refresh((IResource[]) zero.toArray(new IResource[zero.size()]), IResource.DEPTH_ZERO, flags, monitor);
203         if (!one.isEmpty())
204             refresh((IResource[]) one.toArray(new IResource[one.size()]), IResource.DEPTH_ONE, flags, monitor);
205         if (!infinite.isEmpty())
206             refresh((IResource[]) infinite.toArray(new IResource[infinite.size()]), IResource.DEPTH_INFINITE, flags, monitor);
207     }
208
209     /**
210      * Refresh the subscriber and cache the fact that the resources were refreshed by
211      * calling the <code>refreshed</code> method. The default implementation only refreshes
212      * the state and does not fetch contents in the <code>FILE_CONTENTS_REQUIRED</code>
213      * flag is passed. It is up to subclass to handle this.
214      * @param resources the resources to be refreshed
215      * @param depth the depth of the refresh
216      * @param flags the flags that indicate extra state that shoudl be fetched
217      * @param monitor a progress monitor
218      * @throws TeamException
219      */

220     protected void refresh(IResource[] resources, int depth, int flags, IProgressMonitor monitor) throws TeamException {
221         subscriber.refresh(resources, depth, monitor);
222         refreshed(resources, depth);
223     }
224
225     /**
226      * Record the fact that the resources have been refreshed to the given depth.
227      * This is done so that accesses to refreshed resources will not need to perform
228      * another refresh.
229      * @param resources the resources that were refreshed
230      * @param depth the depth to which the resources were refreshed
231      */

232     protected final void refreshed(IResource[] resources, int depth) {
233         for (int i = 0; i < resources.length; i++) {
234             IResource resource = resources[i];
235             // Include files and depth-one folders as shallow
236
if (depth == IResource.DEPTH_ONE || resource.getType() == IResource.FILE) {
237                 shallowRefresh.add(resource);
238             } else if (depth == IResource.DEPTH_INFINITE) {
239                 deepRefresh.add(resource);
240             }
241         }
242     }
243     
244     /*
245      * Ensure that the given resource has been refreshed to the specified depth
246      * since the context has been created.
247      */

248     private void ensureRefreshed(IResource resource, int depth, int flags, IProgressMonitor monitor) throws TeamException {
249         if (depth == IResource.DEPTH_INFINITE) {
250             // If the resource or a parent was refreshed deeply, no need to do it again
251
if (wasRefreshedDeeply(resource))
252                 return;
253             // if the resource is a file, a shallow refresh is enough
254
if (resource.getType() == IResource.FILE && wasRefreshedShallow(resource))
255                 return;
256         } else {
257             if (wasRefreshedShallow(resource))
258                 return;
259         }
260         refresh(new IResource[] { resource }, depth, flags, monitor);
261     }
262
263     /*
264      * Look for a shallow refresh of the resource. If not there,
265      * look fir a deep refresh of a parent or a shallow refresh of the
266      * direct parent if the resource is a file.
267      */

268     private boolean wasRefreshedShallow(IResource resource) {
269         if (shallowRefresh.contains(resource))
270             return true;
271         if (resource.getType() == IResource.FILE && shallowRefresh.contains(resource.getParent()))
272             return true;
273         if (wasRefreshedDeeply(resource))
274             return true;
275         return false;
276     }
277
278     /*
279      * Look for a deep refresh of the resource or any of it's parents
280      */

281     private boolean wasRefreshedDeeply(IResource resource) {
282         if (resource.getType() == IResource.ROOT)
283             return false;
284         if (deepRefresh.contains(resource))
285             return true;
286         return wasRefreshedDeeply(resource.getParent());
287     }
288     
289     /*
290      * Validate that the remote resource is of the proper type and return the
291      * remote resource if it is OK. A return of null indicates that there is no remote.
292      */

293     private IResourceVariant validateRemote(IResource resource, SyncInfo syncInfo) throws CoreException {
294         if (syncInfo == null) return null;
295         IResourceVariant remote = syncInfo.getRemote();
296         if (remote == null) return null;
297         boolean containerExpected = resource.getType() != IResource.FILE;
298         if (remote.isContainer() && !containerExpected) {
299             throw new CoreException(new Status(IStatus.ERROR, TeamPlugin.ID, IResourceStatus.RESOURCE_WRONG_TYPE, Messages.SubscriberResourceMappingContext_0 + resource.getFullPath().toString(), null));
300         } else if (!remote.isContainer() && containerExpected) {
301             throw new CoreException(new Status(IStatus.ERROR, TeamPlugin.ID, IResourceStatus.RESOURCE_WRONG_TYPE, Messages.SubscriberResourceMappingContext_1 + resource.getFullPath().toString(), null));
302         }
303         return remote;
304     }
305 }
306
Popular Tags