KickJava   Java API By Example, From Geeks To Geeks.

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


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

32 public class SubscriberResourceMappingContext extends RemoteResourceMappingContext {
33     
34     private final Subscriber subscriber;
35     
36     // Lists used to keep track of resources that have been refreshed
37
private Set shallowRefresh = new HashSet();
38     private Set deepRefresh = new HashSet();
39     private boolean autoRefresh;
40     
41     /**
42      * Return a resource mapping context suitable for comparison operations.
43      * Comparisons require that any out-of-sync resources have contents
44      * that differ.
45      * @param subscriber the subscriber
46      * @return a resource mapping context suitable for compare operations
47      */

48     public static RemoteResourceMappingContext createContext(Subscriber subscriber) {
49         return new SubscriberResourceMappingContext(subscriber, true);
50     }
51     
52     /**
53      * Create a resource mapping context for the given subscriber
54      * @param subscriber the subscriber
55      * from the local contents
56      * @param autoRefresh whether the context should auto-refresh when queried
57      */

58     public SubscriberResourceMappingContext(Subscriber subscriber, boolean autoRefresh) {
59         this.subscriber = subscriber;
60         this.autoRefresh = autoRefresh;
61     }
62
63     /* (non-Javadoc)
64      * @see org.eclipse.core.internal.resources.mapping.RemoteResourceMappingContext#hasRemoteChange(org.eclipse.core.resources.IResource, org.eclipse.core.runtime.IProgressMonitor)
65      */

66     public final boolean hasRemoteChange(IResource resource, IProgressMonitor monitor) throws CoreException {
67         try {
68             monitor.beginTask(null, 100);
69             ensureRefreshed(resource, IResource.DEPTH_ONE, NONE, monitor);
70             SyncInfo syncInfo = subscriber.getSyncInfo(resource);
71             validateRemote(resource, syncInfo);
72             if (syncInfo == null) return false;
73             int direction = SyncInfo.getDirection(syncInfo.getKind());
74             return direction == SyncInfo.OUTGOING || direction == SyncInfo.CONFLICTING;
75         } finally {
76             monitor.done();
77         }
78     }
79     
80     /* (non-Javadoc)
81      * @see org.eclipse.core.internal.resources.mapping.RemoteResourceMappingContext#hasLocalChange(org.eclipse.core.resources.IResource, org.eclipse.core.runtime.IProgressMonitor)
82      */

83     public boolean hasLocalChange(IResource resource, IProgressMonitor monitor) throws CoreException {
84         SyncInfo syncInfo = subscriber.getSyncInfo(resource);
85         if (syncInfo == null) return false;
86         int direction = SyncInfo.getDirection(syncInfo.getKind());
87         return direction == SyncInfo.OUTGOING || direction == SyncInfo.CONFLICTING;
88     }
89
90     /* (non-Javadoc)
91      * @see org.eclipse.core.resources.mapping.ResourceMappingContext#fetchContents(org.eclipse.core.resources.IFile, org.eclipse.core.runtime.IProgressMonitor)
92      */

93     public final IStorage fetchRemoteContents(IFile file, IProgressMonitor monitor) throws CoreException {
94         try {
95             monitor.beginTask(null, 100);
96             ensureRefreshed(file, IResource.DEPTH_ZERO, FILE_CONTENTS_REQUIRED, Policy.subMonitorFor(monitor, 10));
97             SyncInfo syncInfo = subscriber.getSyncInfo(file);
98             IResourceVariant remote = validateRemote(file, syncInfo);
99             if (remote == null) {
100                 return null;
101             }
102             return remote.getStorage(Policy.subMonitorFor(monitor, 90));
103         } finally {
104             monitor.done();
105         }
106     }
107     
108     /* (non-Javadoc)
109      * @see org.eclipse.core.internal.resources.mapping.RemoteResourceMappingContext#fetchBaseContents(org.eclipse.core.resources.IFile, org.eclipse.core.runtime.IProgressMonitor)
110      */

111     public final IStorage fetchBaseContents(IFile file, IProgressMonitor monitor) throws CoreException {
112         try {
113             monitor.beginTask(null, 100);
114             ensureRefreshed(file, IResource.DEPTH_ZERO, FILE_CONTENTS_REQUIRED, Policy.subMonitorFor(monitor, 10));
115             SyncInfo syncInfo = subscriber.getSyncInfo(file);
116             IResourceVariant base = validateBase(file, syncInfo);
117             if (base == null) {
118                 return null;
119             }
120             return base.getStorage(Policy.subMonitorFor(monitor, 90));
121         } finally {
122             monitor.done();
123         }
124     }
125
126     /* (non-Javadoc)
127      * @see org.eclipse.core.resources.mapping.ResourceMappingContext#fetchMembers(org.eclipse.core.resources.IContainer, org.eclipse.core.runtime.IProgressMonitor)
128      */

129     public final IResource[] fetchMembers(IContainer container, IProgressMonitor monitor) throws CoreException {
130         try {
131             monitor.beginTask(null, 100);
132             ensureRefreshed(container, IResource.DEPTH_ONE, NONE, Policy.subMonitorFor(monitor, 100));
133             SyncInfo syncInfo = subscriber.getSyncInfo(container);
134             if (validateRemote(container, syncInfo) == null) {
135                 // There is no remote so return an empty array
136
return new IResource[0];
137             }
138             return subscriber.members(container);
139         } finally {
140             monitor.done();
141         }
142     }
143
144     /* (non-Javadoc)
145      * @see org.eclipse.core.resources.mapping.ResourceMappingContext#refresh(org.eclipse.core.resources.mapping.ResourceTraversal[], int, org.eclipse.core.runtime.IProgressMonitor)
146      */

147     public final void refresh(ResourceTraversal[] traversals, int flags, IProgressMonitor monitor) throws CoreException {
148         subscriber.refresh(traversals, monitor);
149         for (int i = 0; i < traversals.length; i++) {
150             ResourceTraversal traversal = traversals[i];
151             refreshed(traversal.getResources(), traversal.getDepth());
152         }
153     }
154
155     /**
156      * Refresh the subscriber and cache the fact that the resources were refreshed by
157      * calling the <code>refreshed</code> method. The default implementation only refreshes
158      * the state and does not fetch contents in the <code>FILE_CONTENTS_REQUIRED</code>
159      * flag is passed. It is up to subclass to handle this.
160      * @param resources the resources to be refreshed
161      * @param depth the depth of the refresh
162      * @param flags the flags that indicate extra state that should be fetched
163      * @param monitor a progress monitor
164      * @throws TeamException
165      */

166     protected void refresh(IResource[] resources, int depth, int flags, IProgressMonitor monitor) throws TeamException {
167         subscriber.refresh(resources, depth, monitor);
168         refreshed(resources, depth);
169     }
170
171     /**
172      * Record the fact that the resources have been refreshed to the given depth.
173      * This is done so that accesses to refreshed resources will not need to perform
174      * another refresh.
175      * @param resources the resources that were refreshed
176      * @param depth the depth to which the resources were refreshed
177      */

178     protected final void refreshed(IResource[] resources, int depth) {
179         for (int i = 0; i < resources.length; i++) {
180             IResource resource = resources[i];
181             // Include files and depth-one folders as shallow
182
if (depth == IResource.DEPTH_ONE || resource.getType() == IResource.FILE) {
183                 shallowRefresh.add(resource);
184             } else if (depth == IResource.DEPTH_INFINITE) {
185                 deepRefresh.add(resource);
186             }
187         }
188     }
189     
190     /*
191      * Ensure that the given resource has been refreshed to the specified depth
192      * since the context has been created.
193      */

194     private void ensureRefreshed(IResource resource, int depth, int flags, IProgressMonitor monitor) throws TeamException {
195         if (autoRefresh) {
196             if (depth == IResource.DEPTH_INFINITE) {
197                 // If the resource or a parent was refreshed deeply, no need to do it again
198
if (wasRefreshedDeeply(resource))
199                     return;
200                 // if the resource is a file, a shallow refresh is enough
201
if (resource.getType() == IResource.FILE && wasRefreshedShallow(resource))
202                     return;
203             } else {
204                 if (wasRefreshedShallow(resource))
205                     return;
206             }
207             refresh(new IResource[] { resource }, depth, flags, monitor);
208         }
209     }
210
211     /*
212      * Look for a shallow refresh of the resource. If not there,
213      * look fir a deep refresh of a parent or a shallow refresh of the
214      * direct parent if the resource is a file.
215      */

216     private boolean wasRefreshedShallow(IResource resource) {
217         if (shallowRefresh.contains(resource))
218             return true;
219         if (resource.getType() == IResource.FILE && shallowRefresh.contains(resource.getParent()))
220             return true;
221         if (wasRefreshedDeeply(resource))
222             return true;
223         return false;
224     }
225
226     /*
227      * Look for a deep refresh of the resource or any of it's parents
228      */

229     private boolean wasRefreshedDeeply(IResource resource) {
230         if (resource.getType() == IResource.ROOT)
231             return false;
232         if (deepRefresh.contains(resource))
233             return true;
234         return wasRefreshedDeeply(resource.getParent());
235     }
236     
237     /*
238      * Validate that the remote resource is of the proper type and return the
239      * remote resource if it is OK. A return of null indicates that there is no remote.
240      */

241     private IResourceVariant validateRemote(IResource resource, SyncInfo syncInfo) throws CoreException {
242         if (syncInfo == null) return null;
243         IResourceVariant remote = syncInfo.getRemote();
244         if (remote == null) return null;
245         return validateRemote(resource, remote);
246     }
247
248     private IResourceVariant validateRemote(IResource resource, IResourceVariant remote) throws CoreException {
249         boolean containerExpected = resource.getType() != IResource.FILE;
250         if (remote.isContainer() && !containerExpected) {
251             throw new CoreException(new Status(IStatus.ERROR, TeamPlugin.ID, IResourceStatus.RESOURCE_WRONG_TYPE, Messages.SubscriberResourceMappingContext_0 + resource.getFullPath().toString(), null));
252         } else if (!remote.isContainer() && containerExpected) {
253             throw new CoreException(new Status(IStatus.ERROR, TeamPlugin.ID, IResourceStatus.RESOURCE_WRONG_TYPE, Messages.SubscriberResourceMappingContext_1 + resource.getFullPath().toString(), null));
254         }
255         return remote;
256     }
257     
258     /*
259      * Validate that the base resource is of the proper type and return the
260      * base resource if it is OK. A return of null indicates that there is no base.
261      */

262     private IResourceVariant validateBase(IResource resource, SyncInfo syncInfo) throws CoreException {
263         if (syncInfo == null) return null;
264         IResourceVariant base = syncInfo.getBase();
265         if (base == null) return null;
266         return validateRemote(resource, base);
267     }
268
269     /**
270      * Set whether the context should refresh the state of resources
271      * when their state is requested. The context keeps track of what
272      * resources were refreshed and only auto-refreshes a resource
273      * once.
274      * @param autoRefresh whether the context should refresh the state of resources
275      * when their state is requested
276      */

277     public void setAutoRefresh(boolean autoRefresh) {
278         this.autoRefresh = autoRefresh;
279     }
280
281     /* (non-Javadoc)
282      * @see org.eclipse.core.resources.mapping.RemoteResourceMappingContext#isThreeWay()
283      */

284     public boolean isThreeWay() {
285         return subscriber.getResourceComparator().isThreeWay();
286     }
287
288     /* (non-Javadoc)
289      * @see org.eclipse.core.resources.mapping.RemoteResourceMappingContext#contentDiffers(org.eclipse.core.resources.IFile, org.eclipse.core.runtime.IProgressMonitor)
290      */

291     public boolean contentDiffers(IFile file, IProgressMonitor monitor) throws CoreException {
292         return hasRemoteChange(file, monitor) || hasLocalChange(file, monitor);
293     }
294     
295     public IProject[] getProjects() {
296         Set projects = new HashSet();
297         IResource[] roots = subscriber.roots();
298         for (int i = 0; i < roots.length; i++) {
299             IResource resource = roots[i];
300             projects.add(resource.getProject());
301         }
302         return (IProject[]) projects.toArray(new IProject[projects.size()]);
303     }
304 }
305
Popular Tags