KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > core > resources > SynchronizerSyncInfoCache


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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.resources;
12
13 import java.util.*;
14
15 import org.eclipse.core.resources.IContainer;
16 import org.eclipse.core.resources.IFolder;
17 import org.eclipse.core.resources.IProject;
18 import org.eclipse.core.resources.IResource;
19 import org.eclipse.core.resources.IResourceStatus;
20 import org.eclipse.core.resources.ISynchronizer;
21 import org.eclipse.core.resources.ResourcesPlugin;
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.IPath;
24 import org.eclipse.team.internal.ccvs.core.CVSException;
25 import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
26 import org.eclipse.team.internal.ccvs.core.ICVSFolder;
27 import org.eclipse.team.internal.ccvs.core.ICVSResource;
28 import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
29 import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
30 import org.eclipse.team.internal.ccvs.core.util.Util;
31
32 /**
33  * This cache uses session properties to hold the bytes representing the sync
34  * info
35  */

36 /*package*/ class SynchronizerSyncInfoCache extends SyncInfoCache {
37     
38     // Map of sync bytes that were set without a scheduling rule
39
Map pendingCacheWrites = new HashMap();
40     private static final Object JavaDoc BYTES_REMOVED = new byte[0];
41
42     public SynchronizerSyncInfoCache() {
43         getWorkspaceSynchronizer().add(FOLDER_SYNC_KEY);
44         getWorkspaceSynchronizer().add(RESOURCE_SYNC_KEY);
45     }
46     /**
47      * Return the Eclipse Workspace Synchronizer (from org.eclipse.core.resources)
48      */

49     private ISynchronizer getWorkspaceSynchronizer() {
50         return ResourcesPlugin.getWorkspace().getSynchronizer();
51     }
52     
53     /*package*/ void flush(IProject project) throws CVSException {
54         purgeCache(project, true);
55     }
56     
57     /**
58      * Method flush.
59      * @param folder
60      */

61     /*package*/ void flush(IFolder folder) throws CVSException {
62         purgeCache(folder, false);
63     }
64     
65     /**
66      * Returns the folder sync info for the container; null if none.
67      * Folder must exist and must not be the workspace root.
68      * The folder sync info for the container MUST ALREADY BE CACHED.
69      * @param container the container
70      *
71      * @return the folder sync info for the folder, or null if none.
72      * @see #cacheFolderSync
73      */

74     FolderSyncInfo getCachedFolderSync(IContainer container, boolean threadSafeAccess) throws CVSException {
75         byte[] bytes = internalGetCachedSyncBytes(container);
76         if (bytes == null) return null;
77         return FolderSyncInfo.getFolderSyncInfo(bytes);
78     }
79     
80     boolean hasCachedFolderSync(IContainer container) throws CVSException {
81         return internalGetCachedSyncBytes(container) != null;
82     };
83     
84     /*
85      * Retieve the cached sync bytes from the synchronizer. A null
86      * is returned if there are no cached sync bytes.
87      */

88     private byte[] internalGetCachedSyncBytes(IContainer container) throws CVSException {
89         try {
90             return getWorkspaceSynchronizer().getSyncInfo(FOLDER_SYNC_KEY, container);
91         } catch (CoreException e) {
92             throw CVSException.wrapException(e);
93         }
94     }
95     /**
96      * Sets the folder sync info for the container; if null, deletes it.
97      * Folder must exist and must not be the workspace root.
98      * The folder sync info for the container need not have previously been
99      * cached.
100      *
101      * @param container the container
102      * @param info the new folder sync info
103      */

104     void setCachedFolderSync(IContainer container, FolderSyncInfo info, boolean canModifyWorkspace) throws CVSException {
105         try {
106             if (info == null) {
107                 if (container.exists() || container.isPhantom()) {
108                     getWorkspaceSynchronizer().flushSyncInfo(FOLDER_SYNC_KEY, container, IResource.DEPTH_ZERO);
109                 }
110             } else {
111                 getWorkspaceSynchronizer().setSyncInfo(FOLDER_SYNC_KEY, container, info.getBytes());
112             }
113         } catch (CoreException e) {
114             throw CVSException.wrapException(e);
115         }
116     }
117
118     /**
119      * @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#getCachedSyncBytes(org.eclipse.core.resources.IResource, boolean)
120      */

121     byte[] getCachedSyncBytes(IResource resource, boolean threadSafeAccess) throws CVSException {
122         try {
123             byte[] bytes = null;
124             if (!hasPendingCacheRemoval(resource)) {
125                 bytes = getPendingCacheWrite(resource);
126                 if (bytes == null) {
127                     bytes = getWorkspaceSynchronizer().getSyncInfo(RESOURCE_SYNC_KEY, resource);
128                 }
129             }
130             if (bytes != null && resource.getType() == IResource.FILE) {
131                 if (ResourceSyncInfo.isAddition(bytes)) {
132                     // The local file has been deleted but was an addition
133
// Therefore, ignore the sync bytes
134
bytes = null;
135                 } else if (!ResourceSyncInfo.isDeletion(bytes)) {
136                     // Ensure the bytes indicate an outgoing deletion
137
bytes = ResourceSyncInfo.convertToDeletion(bytes);
138                 }
139             }
140             return bytes;
141         } catch (CoreException e) {
142             throw CVSException.wrapException(e);
143         }
144     }
145     
146     /**
147      * @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#setCachedSyncBytes(org.eclipse.core.resources.IResource, byte[])
148      */

149     void setCachedSyncBytes(IResource resource, byte[] syncBytes, boolean canModifyWorkspace) throws CVSException {
150         byte[] oldBytes = getCachedSyncBytes(resource, true);
151         try {
152             if (syncBytes == null) {
153                 if (oldBytes != null) {
154                     if (canModifyWorkspace) {
155                         if (resource.exists() || resource.isPhantom()) {
156                             getWorkspaceSynchronizer().flushSyncInfo(RESOURCE_SYNC_KEY, resource, IResource.DEPTH_ZERO);
157                         }
158                         removePendingCacheWrite(resource);
159                     } else {
160                         if (resource.exists() || resource.isPhantom()) {
161                             setPendingCacheWriteToDelete(resource);
162                         }
163                     }
164                 }
165             } else {
166                 // ensure that the sync info is not already set to the same thing.
167
// We do this to avoid causing a resource delta when the sync info is
168
// initially loaded (i.e. the synchronizer has it and so does the Entries file
169
// Ignore the
170
if (oldBytes == null || !equals(syncBytes, oldBytes)) {
171                     if (canModifyWorkspace) {
172                         getWorkspaceSynchronizer().setSyncInfo(RESOURCE_SYNC_KEY, resource, syncBytes);
173                         removePendingCacheWrite(resource);
174                     } else {
175                         setPendingCacheWrite(resource, syncBytes);
176                     }
177                 }
178             }
179         } catch (CoreException e) {
180             throw CVSException.wrapException(e);
181         }
182     }
183
184     /*
185      * Convert file sync bytes to deletions to ensure proper comparison
186      */

187     private boolean equals(byte[] syncBytes, byte[] oldBytes) throws CVSException {
188         if (!ResourceSyncInfo.isFolder(syncBytes)) {
189             syncBytes = ResourceSyncInfo.convertToDeletion(syncBytes);
190         }
191         if (!ResourceSyncInfo.isFolder(oldBytes)) {
192             try {
193                 oldBytes = ResourceSyncInfo.convertToDeletion(oldBytes);
194             } catch (CVSException e) {
195                 CVSProviderPlugin.log(e);
196                 return false;
197             }
198         }
199         return Util.equals(syncBytes, oldBytes);
200     }
201     
202     /* (non-Javadoc)
203      * @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#getDirtyIndicator(org.eclipse.core.resources.IResource)
204      */

205     String JavaDoc getDirtyIndicator(IResource resource, boolean threadSafeAccess) throws CVSException {
206         if (resource.getType() == IResource.FILE) {
207             // a phantom file is dirty if it was managed before it was deleted
208
return getCachedSyncBytes(resource, threadSafeAccess) != null ?
209                             IS_DIRTY_INDICATOR :
210                             NOT_DIRTY_INDICATOR;
211         } else {
212             return calculateDirtyCountForPhantomFolder((IContainer)resource);
213         }
214     }
215
216     /* (non-Javadoc)
217      * @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#setDirtyIndicator(org.eclipse.core.resources.IResource, java.lang.String)
218      */

219     void setDirtyIndicator(IResource resource, String JavaDoc indicator) throws CVSException {
220         // We don't cache the dirty count for folders because it would cause
221
// resource delta's in the decorator thread and possible deadlock.
222
}
223     
224     /* (non-Javadoc)
225      * @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#cachesDirtyState()
226      */

227     public boolean cachesDirtyState() {
228         // We don't cache the dirty count for folders because it would cause
229
// resource delta's in the decorator thread and possible deadlock.
230
return false;
231     }
232         
233     /*package*/ void flushDirtyCache(IResource container) throws CVSException {
234         // Dirty state is not cached
235
}
236     
237     /*package*/ boolean isSyncInfoLoaded(IContainer parent) throws CVSException {
238         return true;
239     }
240     
241     /**
242      * @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#isResourceSyncInfoCached(org.eclipse.core.resources.IContainer)
243      */

244     boolean isResourceSyncInfoCached(IContainer container) throws CVSException {
245         // the sync info is always cahced when using the synchronizer
246
return true;
247     }
248     
249     /**
250      * @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#setResourceSyncInfoCached(org.eclipse.core.resources.IContainer)
251      */

252     void setResourceSyncInfoCached(IContainer container) throws CVSException {
253         // do nothing
254
}
255     /**
256      * @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#isFolderSyncInfoCached(org.eclipse.core.resources.IContainer)
257      */

258     boolean isFolderSyncInfoCached(IContainer container) throws CVSException {
259         return true;
260     }
261     
262     /*
263      * Calculate the dirty count for the given phantom folder, performing any
264      * necessary calculations on the childen as well
265      */

266     private String JavaDoc calculateDirtyCountForPhantomFolder(IContainer parent) throws CVSException {
267         ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(parent);
268         if(getCachedFolderSync(parent, true) == null) {
269             return NOT_DIRTY_INDICATOR;
270         }
271         
272         String JavaDoc indicator = NOT_DIRTY_INDICATOR;
273         ICVSResource[] children = cvsFolder.members(ICVSFolder.MANAGED_MEMBERS | ICVSFolder.PHANTOM_MEMBERS);
274         for (int i = 0; i < children.length; i++) {
275             ICVSResource resource = children[i];
276             // keep looking into phantom folders until a managed phantom file
277
// is found.
278
if (resource.isFolder()) {
279                 indicator = calculateDirtyCountForPhantomFolder((IContainer)resource.getIResource());
280             } else {
281                 // Any non-existant managed files are dirty (outgoing deletion)
282
indicator = IS_DIRTY_INDICATOR;
283                 break;
284             }
285         }
286         return indicator;
287     }
288     
289     /**
290      * @param root
291      * @param deep
292      */

293     public void purgeCache(IContainer root, boolean deep) throws CVSException {
294         int depth = deep ? IResource.DEPTH_INFINITE : IResource.DEPTH_ZERO;
295         try {
296             if (root.exists() || root.isPhantom()) {
297                 getWorkspaceSynchronizer().flushSyncInfo(RESOURCE_SYNC_KEY, root, depth);
298             }
299             if (root.exists() || root.isPhantom()) {
300                 getWorkspaceSynchronizer().flushSyncInfo(FOLDER_SYNC_KEY, root, depth);
301             }
302             if (deep) {
303                 removePendingCacheWritesUnder(root);
304             } else {
305                 removePendingCacheWrite(root);
306             }
307         } catch (CoreException e) {
308             if (e.getStatus().getCode() == IResourceStatus.RESOURCE_NOT_FOUND) {
309                 // Must have been deleted since we checked
310
return;
311             }
312             throw CVSException.wrapException(e);
313         }
314         
315     }
316     
317     public boolean isPhantom(IResource resource) {
318         return resource.isPhantom() || hasPendingCacheWrite(resource);
319     }
320     
321     public IResource[] members(IContainer folder) throws CoreException {
322         IResource[] pendingWrites = getPendingCacheWrites();
323         if (pendingWrites != null){
324             HashSet cachedResources = new HashSet();
325             for (int i = 0; i < pendingWrites.length; i++) {
326                 IResource resource = pendingWrites[i];
327                 if (resource.getParent().equals(folder))
328                     cachedResources.add(resource);
329             }
330             
331             if (cachedResources.size() != 0){
332                 IResource[] resources = folder.members(true);
333                 IResource[] cachedResourcesArray = (IResource[]) cachedResources.toArray(new IResource[cachedResources.size()]);
334                 IResource[]finalResources = new IResource[resources.length + cachedResourcesArray.length];
335                 System.arraycopy(resources, 0, finalResources, 0, resources.length);
336                 System.arraycopy(cachedResourcesArray, 0, finalResources, resources.length, cachedResourcesArray.length);
337                 return finalResources;
338             }
339         }
340         try {
341             return folder.members(true);
342         } catch (CoreException e) {
343             if (e.getStatus().getCode() == IResourceStatus.RESOURCE_NOT_FOUND)
344                 return new IResource[0];
345             throw e;
346         }
347     }
348
349     /**
350      * Return whether the given resource has a pending cache write
351      * @param resource the resource
352      * @return whether the given resource has a pending cache write
353      */

354     private boolean hasPendingCacheWrite(IResource resource) {
355         synchronized (pendingCacheWrites) {
356             return pendingCacheWrites.containsKey(resource);
357         }
358     }
359     
360     private byte[] getPendingCacheWrite(IResource resource) {
361         synchronized (pendingCacheWrites) {
362             Object JavaDoc object = pendingCacheWrites.get(resource);
363             if (object instanceof byte[]) {
364                 return (byte[])object;
365             }
366             return null;
367         }
368     }
369     
370     private boolean hasPendingCacheRemoval(IResource resource) {
371         synchronized (pendingCacheWrites) {
372             Object JavaDoc object = pendingCacheWrites.get(resource);
373             return object == BYTES_REMOVED;
374         }
375     }
376     
377     private void setPendingCacheWrite(IResource resource, byte[] syncBytes) {
378         synchronized (pendingCacheWrites) {
379             pendingCacheWrites.put(resource, syncBytes);
380         }
381     }
382     
383     private void setPendingCacheWriteToDelete(IResource resource) {
384         synchronized (pendingCacheWrites) {
385             pendingCacheWrites.put(resource, BYTES_REMOVED);
386         }
387     }
388     
389     private void removePendingCacheWrite(IResource resource) {
390         synchronized (pendingCacheWrites) {
391             pendingCacheWrites.remove(resource);
392         }
393     }
394     
395     private void removePendingCacheWritesUnder(IContainer root) {
396         synchronized (pendingCacheWrites) {
397             IPath fullPath = root.getFullPath();
398             for (Iterator iter = pendingCacheWrites.keySet().iterator(); iter.hasNext();) {
399                 IResource resource = (IResource) iter.next();
400                 if (fullPath.isPrefixOf(resource.getFullPath())) {
401                     iter.remove();
402                 }
403             }
404         }
405     }
406     
407     /**
408      * Return the resources with pending cache writes or
409      * <code>null</code> if there aren't any.
410      * @return the resources with pending cache writes or
411      * <code>null</code>
412      */

413     private IResource[] getPendingCacheWrites() {
414         synchronized (pendingCacheWrites) {
415             if (pendingCacheWrites.isEmpty())
416                 return null;
417             return (IResource[]) pendingCacheWrites.keySet().toArray(new IResource[pendingCacheWrites.size()]);
418         }
419     }
420 }
421
Popular Tags