KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > core > variants > AbstractResourceVariantTree


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.variants;
12
13 import java.util.*;
14
15 import org.eclipse.core.resources.IContainer;
16 import org.eclipse.core.resources.IResource;
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.osgi.util.NLS;
19 import org.eclipse.team.core.TeamException;
20 import org.eclipse.team.internal.core.*;
21
22 /**
23  * An implementation of <code>IResourceVariantTree</code> that provides the logic for
24  * refreshing the tree and collecting the results so they can be cached locally.
25  * This class does not perform the caching but relies on subclasses to do that by
26  * overriding the <code>setVariant</code> method. The subclass
27  * {@link ResourceVariantTree} does provide caching.
28  *
29  * @see IResourceVariantTree
30  * @see ResourceVariantTree
31  *
32  * @since 3.0
33  */

34 public abstract class AbstractResourceVariantTree implements IResourceVariantTree {
35
36     /**
37      * Refreshes the resource variant tree for the specified resources and possibly their descendants,
38      * depending on the depth. The default implementation of this method invokes
39      * <code>refresh(IResource, int, IProgressMonitor)</code> for each resource.
40      * Subclasses may override but should either invoke the above mentioned refresh or
41      * <code>collectChanges</code> in order to reconcile the resource variant tree.
42      * @param resources the resources whose variants should be refreshed
43      * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>,
44      * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>)
45      * @param monitor a progress monitor
46      * @return the array of resources whose corresponding variants have changed
47      * @throws TeamException
48      */

49     public IResource[] refresh(IResource[] resources, int depth, IProgressMonitor monitor) throws TeamException {
50         List changedResources = new ArrayList();
51         monitor.beginTask(null, 100 * resources.length);
52         for (int i = 0; i < resources.length; i++) {
53             IResource resource = resources[i];
54             IResource[] changed = refresh(resource, depth, Policy.subMonitorFor(monitor, 100));
55             changedResources.addAll(Arrays.asList(changed));
56         }
57         monitor.done();
58         return (IResource[]) changedResources.toArray(new IResource[changedResources.size()]);
59     }
60
61     /**
62      * Helper method invoked from <code>refresh(IResource[], int, IProgressMonitor monitor)</code>
63      * for each resource. The default implementation performs the following steps:
64      * <ol>
65      * <li>get the resource variant handle corresponding to the local resource by calling
66      * <code>getRemoteTree</code>.
67      * <li>pass the local resource and the resource variant handle to <code>collectChanges</code>
68      * </ol>
69      * Subclasses may override but should perform roughly the same steps.
70      * @param resource the resource being refreshed
71      * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>,
72      * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>)
73      * @param monitor a progress monitor
74      * @return the resource's whose variants have changed
75      * @throws TeamException
76      */

77     protected IResource[] refresh(IResource resource, int depth, IProgressMonitor monitor) throws TeamException {
78         IResource[] changedResources = null;
79         monitor.beginTask(null, 100);
80         try {
81             monitor.setTaskName(NLS.bind(Messages.SynchronizationCacheRefreshOperation_0, new String JavaDoc[] { resource.getFullPath().makeRelative().toString() }));
82             
83             // build the remote tree only if an initial tree hasn't been provided
84
IResourceVariant tree = fetchVariant(resource, depth, Policy.subMonitorFor(monitor, 70));
85             
86             // update the known remote handles
87
IProgressMonitor sub = Policy.infiniteSubMonitorFor(monitor, 30);
88             try {
89                 sub.beginTask(null, 64);
90                 changedResources = collectChanges(resource, tree, depth, Policy.subMonitorFor(sub, 64));
91             } finally {
92                 sub.done();
93             }
94         } finally {
95             monitor.done();
96         }
97         if (changedResources == null) return new IResource[0];
98         return changedResources;
99     }
100
101     /**
102      * Collect the changes in the remote tree to the specified depth.
103      * @param local the local resource being refreshed
104      * @param remote the corresponding resource variant
105      * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>,
106      * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>)
107      * @param monitor a progress monitor
108      * @return the resource's whose variants have changed
109      * @throws TeamException
110      */

111     protected IResource[] collectChanges(IResource local, IResourceVariant remote, int depth, IProgressMonitor monitor) throws TeamException {
112         List changedResources = new ArrayList();
113         collectChanges(local, remote, changedResources, depth, monitor);
114         return (IResource[]) changedResources.toArray(new IResource[changedResources.size()]);
115     }
116
117     /**
118      * Fetch the members of the given resource variant handle. This method may
119      * return members that were fetched when <code>fetchVariant</code> was called or
120      * may fetch the children directly (i.e. this method may contact the server).
121      * @param variant the resource variant
122      * @param progress a progress monitor
123      * @return the members of the resource variant.
124      */

125     protected abstract IResourceVariant[] fetchMembers(IResourceVariant variant, IProgressMonitor progress) throws TeamException;
126
127     /**
128      * Fetch the resource variant corresponding to the given resource. The depth
129      * parameter indicates the depth of the refresh operation and also indicates the
130      * depth to which the resource variant's descendants will be traversed.
131      * This method may pre-fetch the descendants to the provided depth
132      * or may just return the variant handle corresponding to the given
133      * local resource, in which case
134      * the descendant variants will be fetched by <code>fetchMembers(IResourceVariant, IProgressMonitor)</code>.
135      * @param resource the local resource
136      * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>,
137      * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>)
138      * @param monitor a progress monitor
139      * @return the resource variant corresponding to the given local resource
140      */

141     protected abstract IResourceVariant fetchVariant(IResource resource, int depth, IProgressMonitor monitor) throws TeamException;
142
143     /**
144      * Method that is invoked during collection to let subclasses know which members
145      * were collected for the given resource. Implementors should purge any cached
146      * state for children of the local resource that are no longer members. Any such resources
147      * should be returned to allow clients to clear any state they maintain for those resources.
148      * @param local the local resource
149      * @param members the collected members
150      * @return any resources that were previously collected whose state has been flushed
151      */

152     protected IResource[] collectedMembers(IResource local, IResource[] members) throws TeamException {
153         return new IResource[0];
154     }
155
156     /**
157      * Set the variant associated with the local resource to the newly fetched resource
158      * variant. This method is invoked during change collection and should return whether
159      * the variant associated with the local resource has changed
160      * @param local the local resource
161      * @param remote the newly fetched resource variant
162      * @return <code>true</code> if the resource variant changed
163      * @throws TeamException
164      */

165     protected abstract boolean setVariant(IResource local, IResourceVariant remote) throws TeamException;
166
167     private void collectChanges(IResource local, IResourceVariant remote, Collection changedResources, int depth, IProgressMonitor monitor) throws TeamException {
168         boolean changed = setVariant(local, remote);
169         if (changed) {
170             changedResources.add(local);
171         }
172         if (depth == IResource.DEPTH_ZERO) return;
173         Map children = mergedMembers(local, remote, monitor);
174         for (Iterator it = children.keySet().iterator(); it.hasNext();) {
175             IResource localChild = (IResource) it.next();
176             IResourceVariant remoteChild = (IResourceVariant)children.get(localChild);
177             collectChanges(localChild, remoteChild, changedResources,
178                     depth == IResource.DEPTH_INFINITE ? IResource.DEPTH_INFINITE : IResource.DEPTH_ZERO,
179                     monitor);
180         }
181         
182         IResource[] cleared = collectedMembers(local, (IResource[]) children.keySet().toArray(new IResource[children.keySet().size()]));
183         changedResources.addAll(Arrays.asList(cleared));
184         monitor.worked(1);
185     }
186
187     private Map mergedMembers(IResource local, IResourceVariant remote, IProgressMonitor progress) throws TeamException {
188         
189         // {IResource -> IResourceVariant}
190
Map mergedResources = new HashMap();
191         
192         IResourceVariant[] remoteChildren;
193         if (remote == null) {
194             remoteChildren = new IResourceVariant[0];
195         } else {
196             remoteChildren = fetchMembers(remote, progress);
197         }
198         
199         
200         IResource[] localChildren = members(local);
201     
202         if (remoteChildren.length > 0 || localChildren.length > 0) {
203             Set allSet = new HashSet(20);
204             Map localSet = null;
205             Map remoteSet = null;
206     
207             if (localChildren.length > 0) {
208                 localSet = new HashMap(10);
209                 for (int i = 0; i < localChildren.length; i++) {
210                     IResource localChild = localChildren[i];
211                     String JavaDoc name = localChild.getName();
212                     localSet.put(name, localChild);
213                     allSet.add(name);
214                 }
215             }
216     
217             if (remoteChildren.length > 0) {
218                 remoteSet = new HashMap(10);
219                 for (int i = 0; i < remoteChildren.length; i++) {
220                     IResourceVariant remoteChild = remoteChildren[i];
221                     String JavaDoc name = remoteChild.getName();
222                     remoteSet.put(name, remoteChild);
223                     allSet.add(name);
224                 }
225             }
226             
227             Iterator e = allSet.iterator();
228             while (e.hasNext()) {
229                 String JavaDoc keyChildName = (String JavaDoc) e.next();
230     
231                 Policy.checkCanceled(progress);
232     
233                 IResource localChild =
234                     localSet != null ? (IResource) localSet.get(keyChildName) : null;
235     
236                     IResourceVariant remoteChild =
237                         remoteSet != null ? (IResourceVariant) remoteSet.get(keyChildName) : null;
238                         
239                     if (localChild == null) {
240                         // there has to be a remote resource available if we got this far
241
Assert.isTrue(remoteChild != null);
242                         boolean isContainer = remoteChild.isContainer();
243                         localChild = getResourceChild(local /* parent */, keyChildName, isContainer);
244                     }
245                     if (localChild == null) {
246                         TeamPlugin.log(IStatus.ERROR, NLS.bind("File {0} cannot be the parent of remote resource {1}", //$NON-NLS-1$
247
new Object JavaDoc[] { local.getFullPath(), keyChildName }), null);
248                     } else {
249                         mergedResources.put(localChild, remoteChild);
250                     }
251             }
252         }
253         return mergedResources;
254     }
255
256     private IResource getResourceChild(IResource parent, String JavaDoc childName, boolean isContainer) {
257         if (parent.getType() == IResource.FILE) {
258             return null;
259         }
260         if (isContainer) {
261             return ((IContainer) parent).getFolder(new Path(null, childName));
262         } else {
263             return ((IContainer) parent).getFile(new Path(null, childName));
264         }
265     }
266
267 }
268
Popular Tags