KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > localstore > FileSystemResourceManager


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.core.internal.localstore;
12
13 import java.io.*;
14 import java.net.URI JavaDoc;
15 import java.util.*;
16 import org.eclipse.core.filesystem.*;
17 import org.eclipse.core.internal.resources.*;
18 import org.eclipse.core.internal.resources.File;
19 import org.eclipse.core.internal.utils.*;
20 import org.eclipse.core.resources.*;
21 import org.eclipse.core.runtime.*;
22 import org.eclipse.osgi.util.NLS;
23 import org.xml.sax.InputSource JavaDoc;
24
25 /**
26  * Manages the synchronization between the workspace's view and the file system.
27  */

28 public class FileSystemResourceManager implements ICoreConstants, IManager {
29
30     /**
31      * The history store is initialized lazily - always use the accessor method
32      */

33     protected IHistoryStore _historyStore;
34     protected Workspace workspace;
35
36     public FileSystemResourceManager(Workspace workspace) {
37         this.workspace = workspace;
38     }
39
40     /**
41      * Returns the workspace paths of all resources that may correspond to
42      * the given file system location. Returns an empty ArrayList if there are no
43      * such paths. This method does not consider whether resources actually
44      * exist at the given locations.
45      */

46     protected ArrayList allPathsForLocation(URI JavaDoc inputLocation) {
47         URI JavaDoc location = FileUtil.canonicalURI(inputLocation);
48         final boolean isFileLocation = EFS.SCHEME_FILE.equals(inputLocation.getScheme());
49         final IWorkspaceRoot root = getWorkspace().getRoot();
50         final ArrayList results = new ArrayList();
51         if (URIUtil.equals(location, root.getLocationURI())) {
52             //there can only be one resource at the workspace root's location
53
results.add(Path.ROOT);
54             return results;
55         }
56         IPathVariableManager varMan = workspace.getPathVariableManager();
57         IProject[] projects = root.getProjects();
58         for (int i = 0; i < projects.length; i++) {
59             IProject project = projects[i];
60             //check the project location
61
URI JavaDoc testLocation = project.getLocationURI();
62             // if we are looking for file: locations try to get a file: location for this project
63
if (isFileLocation && !EFS.SCHEME_FILE.equals(testLocation.getScheme()))
64                 testLocation = getFileURI(testLocation);
65             if (testLocation == null)
66                 continue;
67             URI JavaDoc relative = testLocation.relativize(location);
68             if (!relative.isAbsolute() && !relative.equals(testLocation)) {
69                 IPath suffix = new Path(relative.getPath());
70                 results.add(project.getFullPath().append(suffix));
71             }
72             ProjectDescription description = ((Project) project).internalGetDescription();
73             if (description == null)
74                 continue;
75             HashMap links = description.getLinks();
76             if (links == null)
77                 continue;
78             for (Iterator it = links.values().iterator(); it.hasNext();) {
79                 LinkDescription link = (LinkDescription) it.next();
80                 testLocation = varMan.resolveURI(link.getLocationURI());
81                 // if we are looking for file: locations try to get a file: location for this link
82
if (isFileLocation && !EFS.SCHEME_FILE.equals(testLocation.getScheme()))
83                     testLocation = getFileURI(testLocation);
84                 if (testLocation == null)
85                     continue;
86                 relative = testLocation.relativize(location);
87                 if (!relative.isAbsolute() && !relative.equals(testLocation)) {
88                     IPath suffix = new Path(relative.getPath());
89                     results.add(project.getFullPath().append(link.getProjectRelativePath()).append(suffix));
90                 }
91             }
92         }
93         return results;
94     }
95
96     /**
97      * Tries to obtain a file URI for the given URI. Returns <code>null</code> if the file system associated
98      * to the URI scheme does not map to the local file system.
99      * @param locationURI the URI to convert
100      * @return a file URI or <code>null</code>
101      */

102     private URI JavaDoc getFileURI(URI JavaDoc locationURI) {
103         try {
104             IFileStore testLocationStore = EFS.getStore(locationURI);
105             java.io.File JavaDoc storeAsFile = testLocationStore.toLocalFile(EFS.NONE, null);
106             if (storeAsFile != null)
107                 return URIUtil.toURI(storeAsFile.getAbsolutePath());
108         } catch (CoreException e) {
109             // we don't know such file system or some other failure, just return null
110
}
111         return null;
112     }
113
114     /**
115      * Returns all resources that correspond to the given file system location,
116      * including resources under linked resources. Returns an empty array
117      * if there are no corresponding resources.
118      * @param location the file system location
119      * @param files resources that may exist below the project level can
120      * be either files or folders. If this parameter is true, files will be returned,
121      * otherwise containers will be returned.
122      */

123     public IResource[] allResourcesFor(URI JavaDoc location, boolean files) {
124         ArrayList result = allPathsForLocation(location);
125         int count = 0;
126         for (int i = 0, imax = result.size(); i < imax; i++) {
127             //replace the path in the list with the appropriate resource type
128
IResource resource = resourceFor((IPath) result.get(i), files);
129             result.set(i, resource);
130             //count actual resources - some paths won't have a corresponding resource
131
if (resource != null)
132                 count++;
133         }
134         //convert to array and remove null elements
135
IResource[] toReturn = files ? (IResource[]) new IFile[count] : (IResource[]) new IContainer[count];
136         count = 0;
137         for (Iterator it = result.iterator(); it.hasNext();) {
138             IResource resource = (IResource) it.next();
139             if (resource != null)
140                 toReturn[count++] = resource;
141         }
142         return toReturn;
143     }
144
145     /* (non-javadoc)
146      * @see IResource.getResourceAttributes
147      */

148     public ResourceAttributes attributes(IResource resource) {
149         IFileStore store = getStore(resource);
150         IFileInfo fileInfo = store.fetchInfo();
151         if (!fileInfo.exists())
152             return null;
153         return FileUtil.fileInfoToAttributes(fileInfo);
154     }
155
156     /**
157      * Returns a container for the given file system location or null if there
158      * is no mapping for this path. If the path has only one segment, then an
159      * <code>IProject</code> is returned. Otherwise, the returned object
160      * is a <code>IFolder</code>. This method does NOT check the existence
161      * of a folder in the given location. Location cannot be null.
162      */

163     public IContainer containerForLocation(IPath location) {
164         IPath path = pathForLocation(location);
165         return path == null ? null : (IContainer) resourceFor(path, false);
166     }
167
168     public void copy(IResource target, IResource destination, int updateFlags, IProgressMonitor monitor) throws CoreException {
169         monitor = Policy.monitorFor(monitor);
170         try {
171             int totalWork = ((Resource) target).countResources(IResource.DEPTH_INFINITE, false);
172             String JavaDoc title = NLS.bind(Messages.localstore_copying, target.getFullPath());
173             monitor.beginTask(title, totalWork);
174             IFileStore destinationStore = getStore(destination);
175             if (destinationStore.fetchInfo().exists()) {
176                 String JavaDoc message = NLS.bind(Messages.localstore_resourceExists, destination.getFullPath());
177                 throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, destination.getFullPath(), message, null);
178             }
179             getHistoryStore().copyHistory(target, destination, false);
180             CopyVisitor visitor = new CopyVisitor(target, destination, updateFlags, monitor);
181             UnifiedTree tree = new UnifiedTree(target);
182             tree.accept(visitor, IResource.DEPTH_INFINITE);
183             IStatus status = visitor.getStatus();
184             if (!status.isOK())
185                 throw new ResourceException(status);
186         } finally {
187             monitor.done();
188         }
189     }
190
191     public void delete(IResource target, int flags, IProgressMonitor monitor) throws CoreException {
192         monitor = Policy.monitorFor(monitor);
193         try {
194             Resource resource = (Resource) target;
195             final int deleteWork = resource.countResources(IResource.DEPTH_INFINITE, false) * 2;
196             boolean force = (flags & IResource.FORCE) != 0;
197             int refreshWork = 0;
198             if (!force)
199                 refreshWork = Math.min(deleteWork, 100);
200             String JavaDoc title = NLS.bind(Messages.localstore_deleting, resource.getFullPath());
201             monitor.beginTask(title, deleteWork + refreshWork);
202             monitor.subTask(""); //$NON-NLS-1$
203
MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.FAILED_DELETE_LOCAL, Messages.localstore_deleteProblem, null);
204             List skipList = null;
205             UnifiedTree tree = new UnifiedTree(target);
206             if (!force) {
207                 IProgressMonitor sub = Policy.subMonitorFor(monitor, refreshWork);
208                 sub.beginTask("", 1000); //$NON-NLS-1$
209
try {
210                     CollectSyncStatusVisitor refreshVisitor = new CollectSyncStatusVisitor(Messages.localstore_deleteProblem, sub);
211                     refreshVisitor.setIgnoreLocalDeletions(true);
212                     tree.accept(refreshVisitor, IResource.DEPTH_INFINITE);
213                     status.merge(refreshVisitor.getSyncStatus());
214                     skipList = refreshVisitor.getAffectedResources();
215                 } finally {
216                     sub.done();
217                 }
218             }
219             DeleteVisitor deleteVisitor = new DeleteVisitor(skipList, flags, monitor, deleteWork);
220             tree.accept(deleteVisitor, IResource.DEPTH_INFINITE);
221             status.merge(deleteVisitor.getStatus());
222             if (!status.isOK())
223                 throw new ResourceException(status);
224         } finally {
225             monitor.done();
226         }
227     }
228
229     /**
230      * Returns true if the description on disk is different from the given byte array,
231      * and false otherwise.
232      */

233     private boolean descriptionChanged(IFile descriptionFile, byte[] newContents) {
234         InputStream stream = null;
235         try {
236             stream = new BufferedInputStream(descriptionFile.getContents(true));
237             int newLength = newContents.length;
238             byte[] oldContents = new byte[newLength];
239             int read = stream.read(oldContents);
240             if (read != newLength)
241                 return true;
242             //if the stream still has bytes available, then the description is changed
243
if (stream.read() >= 0)
244                 return true;
245             return !Arrays.equals(newContents, oldContents);
246         } catch (Exception JavaDoc e) {
247             Policy.log(e);
248             //if we failed to compare, just write the new contents
249
} finally {
250             FileUtil.safeClose(stream);
251         }
252         return true;
253     }
254
255     /**
256      * @deprecated
257      */

258     public int doGetEncoding(IFileStore store) throws CoreException {
259         InputStream input = null;
260         try {
261             input = store.openInputStream(EFS.NONE, null);
262             int first = input.read();
263             int second = input.read();
264             if (first == -1 || second == -1)
265                 return IFile.ENCODING_UNKNOWN;
266             first &= 0xFF;//converts unsigned byte to int
267
second &= 0xFF;
268             //look for the UTF-16 Byte Order Mark (BOM)
269
if (first == 0xFE && second == 0xFF)
270                 return IFile.ENCODING_UTF_16BE;
271             if (first == 0xFF && second == 0xFE)
272                 return IFile.ENCODING_UTF_16LE;
273             int third = (input.read() & 0xFF);
274             if (third == -1)
275                 return IFile.ENCODING_UNKNOWN;
276             //look for the UTF-8 BOM
277
if (first == 0xEF && second == 0xBB && third == 0xBF)
278                 return IFile.ENCODING_UTF_8;
279             return IFile.ENCODING_UNKNOWN;
280         } catch (IOException e) {
281             String JavaDoc message = NLS.bind(Messages.localstore_couldNotRead, store.toString());
282             throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, null, message, e);
283         } finally {
284             FileUtil.safeClose(input);
285         }
286     }
287
288     /**
289      * Optimized sync check for files. Returns true if the file exists and is in sync, and false
290      * otherwise. The intent is to let the default implementation handle the complex
291      * cases like gender change, case variants, etc.
292      */

293     public boolean fastIsSynchronized(File target) {
294         ResourceInfo info = target.getResourceInfo(false, false);
295         if (target.exists(target.getFlags(info), true)) {
296             IFileInfo fileInfo = getStore(target).fetchInfo();
297             if (!fileInfo.isDirectory() && info.getLocalSyncInfo() == fileInfo.getLastModified())
298                 return true;
299         }
300         return false;
301     }
302
303     /**
304      * Returns an IFile for the given file system location or null if there
305      * is no mapping for this path. This method does NOT check the existence
306      * of a file in the given location. Location cannot be null.
307      */

308     public IFile fileForLocation(IPath location) {
309         IPath path = pathForLocation(location);
310         return path == null ? null : (IFile) resourceFor(path, true);
311     }
312
313     /**
314      * @deprecated
315      */

316     public int getEncoding(File target) throws CoreException {
317         // thread safety: (the location can be null if the project for this file does not exist)
318
IFileStore store = getStore(target);
319         if (!store.fetchInfo().exists()) {
320             String JavaDoc message = NLS.bind(Messages.localstore_fileNotFound, store.toString());
321             throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, target.getFullPath(), message, null);
322         }
323         return doGetEncoding(store);
324     }
325
326     public IHistoryStore getHistoryStore() {
327         if (_historyStore == null) {
328             IPath location = getWorkspace().getMetaArea().getHistoryStoreLocation();
329             location.toFile().mkdirs();
330             _historyStore = ResourcesCompatibilityHelper.createHistoryStore(location, 256);
331         }
332         return _historyStore;
333     }
334
335     /**
336      * Returns the real name of the resource on disk. Returns null if no local
337      * file exists by that name. This is useful when dealing with
338      * case insensitive file systems.
339      */

340     public String JavaDoc getLocalName(IFileStore target) {
341         return target.fetchInfo().getName();
342     }
343
344     protected IPath getProjectDefaultLocation(IProject project) {
345         return workspace.getRoot().getLocation().append(project.getFullPath());
346     }
347
348     /**
349      * Never returns null
350      * @param target
351      * @return The file store for this resource
352      */

353     public IFileStore getStore(IResource target) {
354         try {
355             return getStoreRoot(target).createStore(target.getFullPath());
356         } catch (CoreException e) {
357             //callers aren't expecting failure here, so return null file system
358
return EFS.getNullFileSystem().getStore(target.getFullPath());
359         }
360     }
361
362     /**
363      * Returns the file store root for the provided resource. Never returns null.
364      */

365     private FileStoreRoot getStoreRoot(IResource target) {
366         ResourceInfo info = workspace.getResourceInfo(target.getFullPath(), true, false);
367         FileStoreRoot root;
368         if (info != null) {
369             root = info.getFileStoreRoot();
370             if (root != null && root.isValid())
371                 return root;
372             if (info.isSet(ICoreConstants.M_LINK)) {
373                 ProjectDescription description = ((Project) target.getProject()).internalGetDescription();
374                 if (description != null) {
375                     final URI JavaDoc linkLocation = description.getLinkLocationURI(target.getProjectRelativePath());
376                     //if we can't determine the link location, fall through to parent resource
377
if (linkLocation != null) {
378                         setLocation(target, info, linkLocation);
379                         return info.getFileStoreRoot();
380                     }
381                 }
382             }
383         }
384         final IContainer parent = target.getParent();
385         if (parent == null) {
386             //this is the root, so we know where this must be located
387
//initialize root location
388
info = workspace.getResourceInfo(Path.ROOT, false, true);
389             final IWorkspaceRoot rootResource = workspace.getRoot();
390             setLocation(rootResource, info, URIUtil.toURI(rootResource.getLocation()));
391             return info.getFileStoreRoot();
392         }
393         root = getStoreRoot(parent);
394         if (info != null)
395             info.setFileStoreRoot(root);
396         return root;
397     }
398
399     protected Workspace getWorkspace() {
400         return workspace;
401     }
402
403     /**
404      * Returns whether the project has any local content on disk.
405      */

406     public boolean hasSavedContent(IProject project) {
407         return getStore(project).fetchInfo().exists();
408     }
409
410     /**
411      * Returns whether the project has a project description file on disk.
412      */

413     public boolean hasSavedDescription(IProject project) {
414         return getStore(project).getChild(IProjectDescription.DESCRIPTION_FILE_NAME).fetchInfo().exists();
415     }
416
417     /**
418      * Initializes the file store for a resource.
419      *
420      * @param target The resource to initialize the file store for.
421      * @param location the File system location of this resource on disk
422      * @return The file store for the provided resource
423      */

424     private IFileStore initializeStore(IResource target, URI JavaDoc location) throws CoreException {
425         ResourceInfo info = ((Resource) target).getResourceInfo(false, true);
426         setLocation(target, info, location);
427         FileStoreRoot root = getStoreRoot(target);
428         return root.createStore(target.getFullPath());
429     }
430
431     /**
432      * The target must exist in the workspace. This method must only ever
433      * be called from Project.writeDescription(), because that method ensures
434      * that the description isn't then immediately discovered as a new change.
435      * @return true if a new description was written, and false if it wasn't written
436      * because it was unchanged
437      */

438     public boolean internalWrite(IProject target, IProjectDescription description, int updateFlags, boolean hasPublicChanges, boolean hasPrivateChanges) throws CoreException {
439         //write the project's private description to the metadata area
440
if (hasPrivateChanges)
441             getWorkspace().getMetaArea().writePrivateDescription(target);
442         if (!hasPublicChanges)
443             return false;
444         //can't do anything if there's no description
445
if (description == null)
446             return false;
447
448         //write the model to a byte array
449
ByteArrayOutputStream out = new ByteArrayOutputStream();
450         try {
451             new ModelObjectWriter().write(description, out);
452         } catch (IOException e) {
453             String JavaDoc msg = NLS.bind(Messages.resources_writeMeta, target.getFullPath());
454             throw new ResourceException(IResourceStatus.FAILED_WRITE_METADATA, target.getFullPath(), msg, e);
455         }
456         byte[] newContents = out.toByteArray();
457
458         //write the contents to the IFile that represents the description
459
IFile descriptionFile = target.getFile(IProjectDescription.DESCRIPTION_FILE_NAME);
460         if (!descriptionFile.exists())
461             workspace.createResource(descriptionFile, false);
462         else {
463             //if the description has not changed, don't write anything
464
if (!descriptionChanged(descriptionFile, newContents))
465                 return false;
466         }
467         ByteArrayInputStream in = new ByteArrayInputStream(newContents);
468         IFileInfo fileInfo = ((Resource) descriptionFile).getStore().fetchInfo();
469         if (fileInfo.getAttribute(EFS.ATTRIBUTE_READ_ONLY)) {
470             IStatus result = getWorkspace().validateEdit(new IFile[] {descriptionFile}, null);
471             if (!result.isOK())
472                 throw new ResourceException(result);
473         }
474         //write the project description file (don't use API because scheduling rule might not match)
475
write(descriptionFile, in, fileInfo, IResource.FORCE, false, Policy.monitorFor(null));
476         workspace.getAliasManager().updateAliases(descriptionFile, getStore(descriptionFile), IResource.DEPTH_ZERO, Policy.monitorFor(null));
477
478         //update the timestamp on the project as well so we know when it has
479
//been changed from the outside
480
long lastModified = ((Resource) descriptionFile).getResourceInfo(false, false).getLocalSyncInfo();
481         ResourceInfo info = ((Resource) target).getResourceInfo(false, true);
482         updateLocalSync(info, lastModified);
483
484         //for backwards compatibility, ensure the old .prj file is deleted
485
getWorkspace().getMetaArea().clearOldDescription(target);
486         return true;
487     }
488
489     /**
490      * Returns true if the given project's description is synchronized with
491      * the project description file on disk, and false otherwise.
492      */

493     public boolean isDescriptionSynchronized(IProject target) {
494         //sync info is stored on the description file, and on project info.
495
//when the file is changed by someone else, the project info modification
496
//stamp will be out of date
497
IFile descriptionFile = target.getFile(IProjectDescription.DESCRIPTION_FILE_NAME);
498         ResourceInfo projectInfo = ((Resource) target).getResourceInfo(false, false);
499         if (projectInfo == null)
500             return false;
501         return projectInfo.getLocalSyncInfo() == getStore(descriptionFile).fetchInfo().getLastModified();
502     }
503
504     /* (non-Javadoc)
505      * Returns true if the given resource is synchronized with the file system
506      * to the given depth. Returns false otherwise.
507      *
508      * @see IResource#isSynchronized(int)
509      */

510     public boolean isSynchronized(IResource target, int depth) {
511         switch (target.getType()) {
512             case IResource.ROOT :
513                 if (depth == IResource.DEPTH_ZERO)
514                     return true;
515                 //check sync on child projects.
516
depth = depth == IResource.DEPTH_ONE ? IResource.DEPTH_ZERO : depth;
517                 IProject[] projects = ((IWorkspaceRoot) target).getProjects();
518                 for (int i = 0; i < projects.length; i++) {
519                     if (!isSynchronized(projects[i], depth))
520                         return false;
521                 }
522                 return true;
523             case IResource.PROJECT :
524                 if (!target.isAccessible())
525                     return true;
526                 break;
527             case IResource.FILE :
528                 if (fastIsSynchronized((File) target))
529                     return true;
530                 break;
531         }
532         IsSynchronizedVisitor visitor = new IsSynchronizedVisitor(Policy.monitorFor(null));
533         UnifiedTree tree = new UnifiedTree(target);
534         try {
535             tree.accept(visitor, depth);
536         } catch (CoreException e) {
537             Policy.log(e);
538             return false;
539         } catch (IsSynchronizedVisitor.ResourceChangedException e) {
540             //visitor throws an exception if out of sync
541
return false;
542         }
543         return true;
544     }
545
546     public void link(Resource target, URI JavaDoc location, IFileInfo fileInfo) throws CoreException {
547         initializeStore(target, location);
548         ResourceInfo info = target.getResourceInfo(false, true);
549         long lastModified = fileInfo == null ? 0 : fileInfo.getLastModified();
550         if (lastModified == 0)
551             info.clearModificationStamp();
552         updateLocalSync(info, lastModified);
553     }
554
555     /**
556      * Returns the resolved, absolute file system location of the given resource.
557      * Returns null if the location could not be resolved.
558      */

559     public IPath locationFor(IResource target) {
560         return getStoreRoot(target).localLocation(target.getFullPath());
561     }
562
563     /**
564      * Returns the resolved, absolute file system location of the given resource.
565      * Returns null if the location could not be resolved.
566      */

567     public URI JavaDoc locationURIFor(IResource target) {
568         return getStoreRoot(target).computeURI(target.getFullPath());
569     }
570
571     public void move(IResource source, IFileStore destination, int flags, IProgressMonitor monitor) throws CoreException {
572         //TODO figure out correct semantics for case where destination exists on disk
573
getStore(source).move(destination, EFS.NONE, monitor);
574     }
575
576     /**
577      * Returns a resource path to the given local location. Returns null if
578      * it is not under a project's location.
579      */

580     protected IPath pathForLocation(IPath location) {
581         if (workspace.getRoot().getLocation().equals(location))
582             return Path.ROOT;
583         IProject[] projects = getWorkspace().getRoot().getProjects();
584         for (int i = 0; i < projects.length; i++) {
585             IProject project = projects[i];
586             IPath projectLocation = project.getLocation();
587             if (projectLocation != null && projectLocation.isPrefixOf(location)) {
588                 int segmentsToRemove = projectLocation.segmentCount();
589                 return project.getFullPath().append(location.removeFirstSegments(segmentsToRemove));
590             }
591         }
592         return null;
593     }
594
595     public InputStream read(IFile target, boolean force, IProgressMonitor monitor) throws CoreException {
596         IFileStore store = getStore(target);
597         if (!force) {
598             final IFileInfo fileInfo = store.fetchInfo();
599             if (!fileInfo.exists()) {
600                 // thread safety: (the location can be null if the project for this file does not exist)
601
((Project) target.getProject()).checkExists(NULL_FLAG, true);
602                 String JavaDoc message = NLS.bind(Messages.localstore_fileNotFound, store.toString());
603                 throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, target.getFullPath(), message, null);
604             }
605             ResourceInfo info = ((Resource) target).getResourceInfo(true, false);
606             int flags = ((Resource) target).getFlags(info);
607             ((Resource) target).checkExists(flags, true);
608             if (fileInfo.getLastModified() != info.getLocalSyncInfo()) {
609                 String JavaDoc message = NLS.bind(Messages.localstore_resourceIsOutOfSync, target.getFullPath());
610                 throw new ResourceException(IResourceStatus.OUT_OF_SYNC_LOCAL, target.getFullPath(), message, null);
611             }
612         }
613         return store.openInputStream(EFS.NONE, monitor);
614     }
615
616     /**
617      * Reads and returns the project description for the given project.
618      * Never returns null.
619      * @param target the project whose description should be read.
620      * @param creation true if this project is just being created, in which
621      * case the private project information (including the location) needs to be read
622      * from disk as well.
623      * @exception CoreException if there was any failure to read the project
624      * description, or if the description was missing.
625      */

626     public ProjectDescription read(IProject target, boolean creation) throws CoreException {
627         //read the project location if this project is being created
628
URI JavaDoc projectLocation = null;
629         ProjectDescription privateDescription = null;
630         if (creation) {
631             privateDescription = new ProjectDescription();
632             getWorkspace().getMetaArea().readPrivateDescription(target, privateDescription);
633             projectLocation = privateDescription.getLocationURI();
634         } else {
635             IProjectDescription description = ((Project) target).internalGetDescription();
636             if (description != null && description.getLocationURI() != null) {
637                 projectLocation = description.getLocationURI();
638             }
639         }
640         final boolean isDefaultLocation = projectLocation == null;
641         if (isDefaultLocation) {
642             projectLocation = URIUtil.toURI(getProjectDefaultLocation(target));
643         }
644         IFileStore projectStore = initializeStore(target, projectLocation);
645         IFileStore descriptionStore = projectStore.getChild(IProjectDescription.DESCRIPTION_FILE_NAME);
646         ProjectDescription description = null;
647         //hold onto any exceptions until after sync info is updated, then throw it
648
ResourceException error = null;
649         InputStream in = null;
650         try {
651             in = new BufferedInputStream(descriptionStore.openInputStream(EFS.NONE, null));
652             description = new ProjectDescriptionReader(target).read(new InputSource JavaDoc(in));
653         } catch (CoreException e) {
654             //try the legacy location in the meta area
655
description = getWorkspace().getMetaArea().readOldDescription(target);
656             if (description != null)
657                 return description;
658             if (!descriptionStore.fetchInfo().exists()) {
659                 String JavaDoc msg = NLS.bind(Messages.resources_missingProjectMeta, target.getName());
660                 throw new ResourceException(IResourceStatus.FAILED_READ_METADATA, target.getFullPath(), msg, null);
661             }
662             String JavaDoc msg = NLS.bind(Messages.resources_readProjectMeta, target.getName());
663             error = new ResourceException(IResourceStatus.FAILED_READ_METADATA, target.getFullPath(), msg, e);
664         } finally {
665             FileUtil.safeClose(in);
666         }
667         if (error == null && description == null) {
668             String JavaDoc msg = NLS.bind(Messages.resources_readProjectMeta, target.getName());
669             error = new ResourceException(IResourceStatus.FAILED_READ_METADATA, target.getFullPath(), msg, null);
670         }
671         if (description != null) {
672             //don't trust the project name in the description file
673
description.setName(target.getName());
674             if (!isDefaultLocation)
675                 description.setLocationURI(projectLocation);
676             if (creation && privateDescription != null)
677                 description.setDynamicReferences(privateDescription.getDynamicReferences(false));
678         }
679         long lastModified = descriptionStore.fetchInfo().getLastModified();
680         IFile descriptionFile = target.getFile(IProjectDescription.DESCRIPTION_FILE_NAME);
681         //don't get a mutable copy because we might be in restore which isn't an operation
682
//it doesn't matter anyway because local sync info is not included in deltas
683
ResourceInfo info = ((Resource) descriptionFile).getResourceInfo(false, false);
684         if (info == null) {
685             //create a new resource on the sly -- don't want to start an operation
686
info = getWorkspace().createResource(descriptionFile, false);
687             updateLocalSync(info, lastModified);
688         }
689         //if the project description has changed between sessions, let it remain
690
//out of sync -- that way link changes will be reconciled on next refresh
691
if (!creation)
692             updateLocalSync(info, lastModified);
693
694         //update the timestamp on the project as well so we know when it has
695
//been changed from the outside
696
info = ((Resource) target).getResourceInfo(false, true);
697         updateLocalSync(info, lastModified);
698
699         if (error != null)
700             throw error;
701         return description;
702     }
703
704     public boolean refresh(IResource target, int depth, boolean updateAliases, IProgressMonitor monitor) throws CoreException {
705         switch (target.getType()) {
706             case IResource.ROOT :
707                 return refreshRoot((IWorkspaceRoot) target, depth, updateAliases, monitor);
708             case IResource.PROJECT :
709                 if (!target.isAccessible())
710                     return false;
711                 //fall through
712
case IResource.FOLDER :
713             case IResource.FILE :
714                 return refreshResource(target, depth, updateAliases, monitor);
715         }
716         return false;
717     }
718
719     protected boolean refreshResource(IResource target, int depth, boolean updateAliases, IProgressMonitor monitor) throws CoreException {
720         monitor = Policy.monitorFor(monitor);
721         int totalWork = RefreshLocalVisitor.TOTAL_WORK;
722         String JavaDoc title = NLS.bind(Messages.localstore_refreshing, target.getFullPath());
723         try {
724             monitor.beginTask(title, totalWork);
725             RefreshLocalVisitor visitor = updateAliases ? new RefreshLocalAliasVisitor(monitor) : new RefreshLocalVisitor(monitor);
726             IFileStore fileStore = ((Resource) target).getStore();
727             //try to get all info in one shot, if file system supports it
728
IFileTree fileTree = fileStore.getFileSystem().fetchFileTree(fileStore, new SubProgressMonitor(monitor, 0));
729             UnifiedTree tree = fileTree == null ? new UnifiedTree(target) : new UnifiedTree(target, fileTree);
730             tree.accept(visitor, depth);
731             IStatus result = visitor.getErrorStatus();
732             if (!result.isOK())
733                 throw new ResourceException(result);
734             return visitor.resourcesChanged();
735         } finally {
736             monitor.done();
737         }
738     }
739
740     /**
741      * Synchronizes the entire workspace with the local file system.
742      * The current implementation does this by synchronizing each of the
743      * projects currently in the workspace. A better implementation may
744      * be possible.
745      */

746     protected boolean refreshRoot(IWorkspaceRoot target, int depth, boolean updateAliases, IProgressMonitor monitor) throws CoreException {
747         monitor = Policy.monitorFor(monitor);
748         IProject[] projects = target.getProjects();
749         int totalWork = projects.length;
750         String JavaDoc title = Messages.localstore_refreshingRoot;
751         try {
752             monitor.beginTask(title, totalWork);
753             // if doing depth zero, there is nothing to do (can't refresh the root).
754
// Note that we still need to do the beginTask, done pair.
755
if (depth == IResource.DEPTH_ZERO)
756                 return false;
757             boolean changed = false;
758             // drop the depth by one level since processing the root counts as one level.
759
depth = depth == IResource.DEPTH_ONE ? IResource.DEPTH_ZERO : depth;
760             for (int i = 0; i < projects.length; i++)
761                 changed |= refresh(projects[i], depth, updateAliases, Policy.subMonitorFor(monitor, 1));
762             return changed;
763         } finally {
764             monitor.done();
765         }
766     }
767
768     /**
769      * Returns the resource corresponding to the given workspace path. The
770      * "files" parameter is used for paths of two or more segments. If true,
771      * a file is returned, otherwise a folder is returned. Returns null if files is true
772      * and the path is not of sufficient length.
773      */

774     protected IResource resourceFor(IPath path, boolean files) {
775         int numSegments = path.segmentCount();
776         if (files && numSegments < ICoreConstants.MINIMUM_FILE_SEGMENT_LENGTH)
777             return null;
778         IWorkspaceRoot root = getWorkspace().getRoot();
779         if (path.isRoot())
780             return root;
781         if (numSegments == 1)
782             return root.getProject(path.segment(0));
783         return files ? (IResource) root.getFile(path) : (IResource) root.getFolder(path);
784     }
785
786     /* (non-javadoc)
787      * @see IResouce.setLocalTimeStamp
788      */

789     public long setLocalTimeStamp(IResource target, ResourceInfo info, long value) throws CoreException {
790         IFileStore store = getStore(target);
791         IFileInfo fileInfo = store.fetchInfo();
792         fileInfo.setLastModified(value);
793         store.putInfo(fileInfo, EFS.SET_LAST_MODIFIED, null);
794         //actual value may be different depending on file system granularity
795
fileInfo = store.fetchInfo();
796         long actualValue = fileInfo.getLastModified();
797         updateLocalSync(info, actualValue);
798         return actualValue;
799     }
800
801     /**
802      * The storage location for a resource has changed; update the location.
803      * @param target
804      * @param info
805      * @param location
806      */

807     public void setLocation(IResource target, ResourceInfo info, URI JavaDoc location) {
808         FileStoreRoot oldRoot = info.getFileStoreRoot();
809         if (location != null) {
810             info.setFileStoreRoot(new FileStoreRoot(location, target.getFullPath()));
811         } else {
812             //project is in default location so clear the store root
813
info.setFileStoreRoot(null);
814         }
815         if (oldRoot != null)
816             oldRoot.setValid(false);
817     }
818
819     /* (non-javadoc)
820      * @see IResource.setResourceAttributes
821      */

822     public void setResourceAttributes(IResource resource, ResourceAttributes attributes) throws CoreException {
823         IFileStore store = getStore(resource);
824         //when the executable bit is changed on a folder a refresh is required
825
boolean refresh = false;
826         if (resource instanceof IContainer && ((store.getFileSystem().attributes() & EFS.ATTRIBUTE_EXECUTABLE) != 0))
827             refresh = store.fetchInfo().getAttribute(EFS.ATTRIBUTE_EXECUTABLE) != attributes.isExecutable();
828         store.putInfo(FileUtil.attributesToFileInfo(attributes), EFS.SET_ATTRIBUTES, null);
829         //must refresh in the background because we are not inside an operation
830
if (refresh)
831             workspace.getRefreshManager().refresh(resource);
832     }
833
834     public void shutdown(IProgressMonitor monitor) throws CoreException {
835         if (_historyStore != null)
836             _historyStore.shutdown(monitor);
837     }
838
839     public void startup(IProgressMonitor monitor) throws CoreException {
840         //nothing to do
841
}
842
843     /**
844      * The ResourceInfo must be mutable.
845      */

846     public void updateLocalSync(ResourceInfo info, long localSyncInfo) {
847         info.setLocalSyncInfo(localSyncInfo);
848         if (localSyncInfo == I_NULL_SYNC_INFO)
849             info.clear(M_LOCAL_EXISTS);
850         else
851             info.set(M_LOCAL_EXISTS);
852     }
853
854     /**
855      * The target must exist in the workspace. The content InputStream is
856      * closed even if the method fails. If the force flag is false we only write
857      * the file if it does not exist or if it is already local and the timestamp
858      * has NOT changed since last synchronization, otherwise a CoreException
859      * is thrown.
860      */

861     public void write(IFile target, InputStream content, IFileInfo fileInfo, int updateFlags, boolean append, IProgressMonitor monitor) throws CoreException {
862         monitor = Policy.monitorFor(null);
863         try {
864             IFileStore store = getStore(target);
865             if (fileInfo.getAttribute(EFS.ATTRIBUTE_READ_ONLY)) {
866                 String JavaDoc message = NLS.bind(Messages.localstore_couldNotWriteReadOnly, target.getFullPath());
867                 throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, target.getFullPath(), message, null);
868             }
869             long lastModified = fileInfo.getLastModified();
870             if (BitMask.isSet(updateFlags, IResource.FORCE)) {
871                 if (append && !target.isLocal(IResource.DEPTH_ZERO) && !fileInfo.exists()) {
872                     // force=true, local=false, existsInFileSystem=false
873
String JavaDoc message = NLS.bind(Messages.resources_mustBeLocal, target.getFullPath());
874                     throw new ResourceException(IResourceStatus.RESOURCE_NOT_LOCAL, target.getFullPath(), message, null);
875                 }
876             } else {
877                 if (target.isLocal(IResource.DEPTH_ZERO)) {
878                     // test if timestamp is the same since last synchronization
879
ResourceInfo info = ((Resource) target).getResourceInfo(true, false);
880                     if (lastModified != info.getLocalSyncInfo()) {
881                         String JavaDoc message = NLS.bind(Messages.localstore_resourceIsOutOfSync, target.getFullPath());
882                         throw new ResourceException(IResourceStatus.OUT_OF_SYNC_LOCAL, target.getFullPath(), message, null);
883                     }
884                 } else {
885                     if (fileInfo.exists()) {
886                         String JavaDoc message = NLS.bind(Messages.localstore_resourceExists, target.getFullPath());
887                         throw new ResourceException(IResourceStatus.EXISTS_LOCAL, target.getFullPath(), message, null);
888                     }
889                     if (append) {
890                         String JavaDoc message = NLS.bind(Messages.resources_mustBeLocal, target.getFullPath());
891                         throw new ResourceException(IResourceStatus.RESOURCE_NOT_LOCAL, target.getFullPath(), message, null);
892                     }
893                 }
894             }
895             // add entry to History Store.
896
if (BitMask.isSet(updateFlags, IResource.KEEP_HISTORY) && fileInfo.exists())
897                 //never move to the history store, because then the file is missing if write fails
898
getHistoryStore().addState(target.getFullPath(), store, fileInfo, false);
899             if (!fileInfo.exists())
900                 store.getParent().mkdir(EFS.NONE, null);
901             int options = append ? EFS.APPEND : EFS.NONE;
902             OutputStream out = store.openOutputStream(options, Policy.subMonitorFor(monitor, 0));
903             FileUtil.transferStreams(content, out, store.toString(), monitor);
904             // get the new last modified time and stash in the info
905
lastModified = store.fetchInfo().getLastModified();
906             ResourceInfo info = ((Resource) target).getResourceInfo(false, true);
907             updateLocalSync(info, lastModified);
908             info.incrementContentId();
909             info.clear(M_CONTENT_CACHE);
910             workspace.updateModificationStamp(info);
911         } finally {
912             FileUtil.safeClose(content);
913         }
914     }
915
916     /**
917      * If force is false, this method fails if there is already a resource in
918      * target's location.
919      */

920     public void write(IFolder target, boolean force, IProgressMonitor monitor) throws CoreException {
921         IFileStore store = getStore(target);
922         if (!force) {
923             IFileInfo fileInfo = store.fetchInfo();
924             if (fileInfo.isDirectory()) {
925                 String JavaDoc message = NLS.bind(Messages.localstore_resourceExists, target.getFullPath());
926                 throw new ResourceException(IResourceStatus.EXISTS_LOCAL, target.getFullPath(), message, null);
927             }
928             if (fileInfo.exists()) {
929                 String JavaDoc message = NLS.bind(Messages.localstore_fileExists, target.getFullPath());
930                 throw new ResourceException(IResourceStatus.OUT_OF_SYNC_LOCAL, target.getFullPath(), message, null);
931             }
932         }
933         store.mkdir(EFS.NONE, monitor);
934         ResourceInfo info = ((Resource) target).getResourceInfo(false, true);
935         updateLocalSync(info, store.fetchInfo().getLastModified());
936     }
937
938     /**
939      * Write the .project file without modifying the resource tree. This is called
940      * during save when it is discovered that the .project file is missing. The tree
941      * cannot be modified during save.
942      */

943     public void writeSilently(IProject target) throws CoreException {
944         IPath location = locationFor(target);
945         //if the project location cannot be resolved, we don't know if a description file exists or not
946
if (location == null)
947             return;
948         IFileStore projectStore = getStore(target);
949         projectStore.mkdir(EFS.NONE, null);
950         //can't do anything if there's no description
951
IProjectDescription desc = ((Project) target).internalGetDescription();
952         if (desc == null)
953             return;
954         //write the project's private description to the meta-data area
955
getWorkspace().getMetaArea().writePrivateDescription(target);
956
957         //write the file that represents the project description
958
IFileStore fileStore = projectStore.getChild(IProjectDescription.DESCRIPTION_FILE_NAME);
959         OutputStream out = null;
960         try {
961             out = fileStore.openOutputStream(EFS.NONE, null);
962             new ModelObjectWriter().write(desc, out);
963         } catch (IOException e) {
964             String JavaDoc msg = NLS.bind(Messages.resources_writeMeta, target.getFullPath());
965             throw new ResourceException(IResourceStatus.FAILED_WRITE_METADATA, target.getFullPath(), msg, e);
966         } finally {
967             if (out != null) {
968                 try {
969                     out.close();
970                 } catch (IOException e) {
971                     // ignore failure to close stream
972
}
973             }
974         }
975         //for backwards compatibility, ensure the old .prj file is deleted
976
getWorkspace().getMetaArea().clearOldDescription(target);
977     }
978 }
979
Popular Tags