KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > resources > ResourceTree


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.resources;
12
13 import java.net.URI JavaDoc;
14 import org.eclipse.core.filesystem.*;
15 import org.eclipse.core.internal.localstore.FileSystemResourceManager;
16 import org.eclipse.core.internal.properties.IPropertyManager;
17 import org.eclipse.core.internal.utils.Messages;
18 import org.eclipse.core.internal.utils.Policy;
19 import org.eclipse.core.resources.*;
20 import org.eclipse.core.resources.team.IResourceTree;
21 import org.eclipse.core.runtime.*;
22 import org.eclipse.core.runtime.jobs.ILock;
23 import org.eclipse.osgi.util.NLS;
24
25 /**
26  * @since 2.0
27  *
28  * Implementation note: Since the move/delete hook involves running third
29  * party code, the workspace lock is not held. This means the workspace
30  * lock must be re-acquired whenever we need to manipulate the workspace
31  * in any way. All entry points from third party code back into the tree must
32  * be done in an acquire/release pair.
33  */

34 class ResourceTree implements IResourceTree {
35
36     private boolean isValid = true;
37     private final FileSystemResourceManager localManager;
38     /**
39      * The lock to acquire when the workspace needs to be manipulated
40      */

41     private ILock lock;
42     private MultiStatus multistatus;
43     private int updateFlags;
44
45     /**
46      * Constructor for this class.
47      */

48     public ResourceTree(FileSystemResourceManager localManager, ILock lock, MultiStatus status, int updateFlags) {
49         super();
50         this.localManager = localManager;
51         this.lock = lock;
52         this.multistatus = status;
53         this.updateFlags = updateFlags;
54     }
55
56     /**
57      * @see IResourceTree#addToLocalHistory(IFile)
58      */

59     public void addToLocalHistory(IFile file) {
60         Assert.isLegal(isValid);
61         try {
62             lock.acquire();
63             if (!file.exists())
64                 return;
65             IFileStore store = localManager.getStore(file);
66             final IFileInfo fileInfo = store.fetchInfo();
67             if (!fileInfo.exists())
68                 return;
69             localManager.getHistoryStore().addState(file.getFullPath(), store, fileInfo, false);
70         } finally {
71             lock.release();
72         }
73     }
74
75     private IFileStore computeDestinationStore(IProjectDescription destDescription) throws CoreException {
76         URI JavaDoc destLocation = destDescription.getLocationURI();
77         // Use the default area if necessary for the destination.
78
if (destLocation == null) {
79             IPath rootLocation = ResourcesPlugin.getWorkspace().getRoot().getLocation();
80             destLocation = rootLocation.append(destDescription.getName()).toFile().toURI();
81         }
82         return EFS.getStore(destLocation);
83     }
84
85     /**
86      * @see IResourceTree#computeTimestamp(IFile)
87      */

88     public long computeTimestamp(IFile file) {
89         Assert.isLegal(isValid);
90         try {
91             lock.acquire();
92             if (!file.getProject().exists())
93                 return NULL_TIMESTAMP;
94             return internalComputeTimestamp(file);
95         } finally {
96             lock.release();
97         }
98     }
99
100     /**
101      * Copies the local history of source to destination. Note that if source
102      * is an IFolder, it is assumed that the same structure exists under destination
103      * and the local history of any IFile under source will be copied to the
104      * associated IFile under destination.
105      */

106     private void copyLocalHistory(IResource source, IResource destination) {
107         localManager.getHistoryStore().copyHistory(source, destination, true);
108     }
109
110     /**
111      * @see IResourceTree#deletedFile(IFile)
112      */

113     public void deletedFile(IFile file) {
114         Assert.isLegal(isValid);
115         try {
116             lock.acquire();
117             // Do nothing if the resource doesn't exist.
118
if (!file.exists())
119                 return;
120             try {
121                 // Delete properties, generate marker deltas, and remove the node from the workspace tree.
122
((Resource) file).deleteResource(true, null);
123             } catch (CoreException e) {
124                 String JavaDoc message = NLS.bind(Messages.resources_errorDeleting, file.getFullPath());
125                 IStatus status = new ResourceStatus(IStatus.ERROR, file.getFullPath(), message, e);
126                 failed(status);
127             }
128         } finally {
129             lock.release();
130         }
131     }
132
133     /**
134      * @see IResourceTree#deletedFolder(IFolder)
135      */

136     public void deletedFolder(IFolder folder) {
137         Assert.isLegal(isValid);
138         try {
139             lock.acquire();
140             // Do nothing if the resource doesn't exist.
141
if (!folder.exists())
142                 return;
143             try {
144                 // Delete properties, generate marker deltas, and remove the node from the workspace tree.
145
((Resource) folder).deleteResource(true, null);
146             } catch (CoreException e) {
147                 String JavaDoc message = NLS.bind(Messages.resources_errorDeleting, folder.getFullPath());
148                 IStatus status = new ResourceStatus(IStatus.ERROR, folder.getFullPath(), message, e);
149                 failed(status);
150             }
151         } finally {
152             lock.release();
153         }
154     }
155
156     /**
157      * @see IResourceTree#deletedProject(IProject)
158      */

159     public void deletedProject(IProject target) {
160         Assert.isLegal(isValid);
161         try {
162             lock.acquire();
163             // Do nothing if the resource doesn't exist.
164
if (!target.exists())
165                 return;
166             // Delete properties, generate marker deltas, and remove the node from the workspace tree.
167
try {
168                 ((Project) target).deleteResource(false, null);
169             } catch (CoreException e) {
170                 String JavaDoc message = NLS.bind(Messages.resources_errorDeleting, target.getFullPath());
171                 IStatus status = new ResourceStatus(IStatus.ERROR, target.getFullPath(), message, e);
172                 // log the status but don't return until we try and delete the rest of the project info
173
failed(status);
174             }
175         } finally {
176             lock.release();
177         }
178     }
179
180     /**
181      * Makes sure that the destination directory for a project move is unoccupied.
182      * Returns true if successful, and false if the move should be aborted
183      */

184     private boolean ensureDestinationEmpty(IProject source, IFileStore destinationStore, IProgressMonitor monitor) throws CoreException {
185         String JavaDoc message;
186         //Make sure the destination location is unoccupied
187
if (!destinationStore.fetchInfo().exists())
188             return true;
189         //check for existing children
190
if (destinationStore.childNames(EFS.NONE, Policy.subMonitorFor(monitor, 0)).length > 0) {
191             //allow case rename to proceed
192
if (((Resource) source).getStore().equals(destinationStore))
193                 return true;
194             //fail because the destination is occupied
195
message = NLS.bind(Messages.localstore_resourceExists, destinationStore);
196             IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, null);
197             failed(status);
198             return false;
199         }
200         //delete the destination directory to allow for efficient renaming
201
destinationStore.delete(EFS.NONE, Policy.subMonitorFor(monitor, 0));
202         return true;
203     }
204
205     /**
206      * This operation has failed for the given reason. Add it to this
207      * resource tree's status.
208      */

209     public void failed(IStatus reason) {
210         Assert.isLegal(isValid);
211         multistatus.add(reason);
212     }
213
214     /**
215      * Returns the status object held onto by this resource tree.
216      */

217     protected IStatus getStatus() {
218         return multistatus;
219     }
220
221     /**
222      * @see IResourceTree#getTimestamp(IFile)
223      */

224     public long getTimestamp(IFile file) {
225         Assert.isLegal(isValid);
226         try {
227             lock.acquire();
228             if (!file.exists())
229                 return NULL_TIMESTAMP;
230             ResourceInfo info = ((File) file).getResourceInfo(false, false);
231             return info == null ? NULL_TIMESTAMP : info.getLocalSyncInfo();
232         } finally {
233             lock.release();
234         }
235     }
236
237     /**
238      * Returns the local timestamp for a file.
239      *
240      * @param file
241      * @return The local file system timestamp
242      */

243     private long internalComputeTimestamp(IFile file) {
244         IFileInfo fileInfo = localManager.getStore(file).fetchInfo();
245         return fileInfo.exists() ? fileInfo.getLastModified() : NULL_TIMESTAMP;
246     }
247
248     /**
249      * Helper method for #standardDeleteFile. Returns a boolean indicating whether or
250      * not the delete was successful.
251      */

252     private boolean internalDeleteFile(IFile file, int flags, IProgressMonitor monitor) {
253         try {
254             String JavaDoc message = NLS.bind(Messages.resources_deleting, file.getFullPath());
255             monitor.beginTask(message, Policy.totalWork);
256             Policy.checkCanceled(monitor);
257
258             // Do nothing if the file doesn't exist in the workspace.
259
if (!file.exists()) {
260                 // Indicate that the delete was successful.
261
return true;
262             }
263             // Don't delete contents if this is a linked resource
264
if (file.isLinked()) {
265                 deletedFile(file);
266                 return true;
267             }
268             // If the file doesn't exist on disk then signal to the workspace to delete the
269
// file and return.
270
IFileStore fileStore = localManager.getStore(file);
271             boolean localExists = fileStore.fetchInfo().exists();
272             if (!localExists) {
273                 deletedFile(file);
274                 // Indicate that the delete was successful.
275
return true;
276             }
277
278             boolean keepHistory = (flags & IResource.KEEP_HISTORY) != 0;
279             boolean force = (flags & IResource.FORCE) != 0;
280
281             // Add the file to the local history if requested by the user.
282
if (keepHistory)
283                 addToLocalHistory(file);
284             monitor.worked(Policy.totalWork / 4);
285
286             // We want to fail if force is false and the file is not synchronized with the
287
// local file system.
288
if (!force) {
289                 boolean inSync = isSynchronized(file, IResource.DEPTH_ZERO);
290                 // only want to fail if the file still exists.
291
if (!inSync && localExists) {
292                     message = NLS.bind(Messages.localstore_resourceIsOutOfSync, file.getFullPath());
293                     IStatus status = new ResourceStatus(IResourceStatus.OUT_OF_SYNC_LOCAL, file.getFullPath(), message);
294                     failed(status);
295                     // Indicate that the delete was unsuccessful.
296
return false;
297                 }
298             }
299             monitor.worked(Policy.totalWork / 4);
300
301             // Try to delete the file from the file system.
302
try {
303                 fileStore.delete(EFS.NONE, Policy.subMonitorFor(monitor, Policy.totalWork / 4));
304                 // If the file was successfully deleted from the file system the
305
// workspace tree should be updated accordingly.
306
deletedFile(file);
307                 // Indicate that the delete was successful.
308
return true;
309             } catch (CoreException e) {
310                 message = NLS.bind(Messages.resources_couldnotDelete, fileStore.toString());
311                 IStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, file.getFullPath(), message, e);
312                 failed(status);
313             }
314             // Indicate that the delete was unsuccessful.
315
return false;
316         } finally {
317             monitor.done();
318         }
319     }
320
321     /**
322      * Helper method for #standardDeleteFolder. Returns a boolean indicating
323      * whether or not the deletion of this folder was successful. Does a best effort
324      * delete of this resource and its children.
325      */

326     private boolean internalDeleteFolder(IFolder folder, int flags, IProgressMonitor monitor) {
327         String JavaDoc message = NLS.bind(Messages.resources_deleting, folder.getFullPath());
328         monitor.beginTask("", Policy.totalWork); //$NON-NLS-1$
329
monitor.subTask(message);
330         Policy.checkCanceled(monitor);
331
332         // Do nothing if the folder doesn't exist in the workspace.
333
if (!folder.exists())
334             return true;
335
336         // Don't delete contents if this is a linked resource
337
if (folder.isLinked()) {
338             deletedFolder(folder);
339             return true;
340         }
341
342         // If the folder doesn't exist on disk then update the tree and return.
343
IFileStore fileStore = localManager.getStore(folder);
344         if (!fileStore.fetchInfo().exists()) {
345             deletedFolder(folder);
346             return true;
347         }
348
349         try {
350             //this will delete local and workspace
351
localManager.delete(folder, flags, Policy.subMonitorFor(monitor, Policy.totalWork));
352         } catch (CoreException ce) {
353             message = NLS.bind(Messages.localstore_couldnotDelete, folder.getFullPath());
354             MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.FAILED_DELETE_LOCAL, message, ce);
355             if (ce.getStatus() != null)
356                 status.merge(ce.getStatus());
357             failed(status);
358             return false;
359         }
360         return true;
361     }
362
363     /**
364      * Does a best-effort delete on this resource and all its children.
365      */

366     private boolean internalDeleteProject(IProject project, int flags, IProgressMonitor monitor) {
367
368         // Recursively delete each member of the project.
369
IResource[] members = null;
370         try {
371             members = project.members(IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS);
372         } catch (CoreException e) {
373             String JavaDoc message = NLS.bind(Messages.resources_errorMembers, project.getFullPath());
374             IStatus status = new ResourceStatus(IStatus.ERROR, project.getFullPath(), message, e);
375             failed(status);
376             // Indicate that the delete was unsuccessful.
377
return false;
378         }
379         boolean deletedChildren = true;
380         for (int i = 0; i < members.length; i++) {
381             IResource child = members[i];
382             switch (child.getType()) {
383                 case IResource.FILE :
384                     // ignore the .project file for now and delete it last
385
if (!IProjectDescription.DESCRIPTION_FILE_NAME.equals(child.getName()))
386                         deletedChildren &= internalDeleteFile((IFile) child, flags, Policy.subMonitorFor(monitor, Policy.totalWork / members.length));
387                     break;
388                 case IResource.FOLDER :
389                     deletedChildren &= internalDeleteFolder((IFolder) child, flags, Policy.subMonitorFor(monitor, Policy.totalWork / members.length));
390                     break;
391             }
392         }
393         IFileStore projectStore = localManager.getStore(project);
394         // Check to see if the children were deleted ok. If there was a problem
395
// just return as the problem should have been logged by the recursive
396
// call to the child.
397
if (!deletedChildren)
398             // Indicate that the delete was unsuccessful.
399
return false;
400
401         //Check if there are any undiscovered children of the project on disk other than description file
402
String JavaDoc[] children;
403         try {
404             children = projectStore.childNames(EFS.NONE, null);
405         } catch (CoreException e) {
406             //treat failure to access the directory as a non-existent directory
407
children = new String JavaDoc[0];
408         }
409         if (children.length != 1 || !IProjectDescription.DESCRIPTION_FILE_NAME.equals(children[0])) {
410             String JavaDoc message = NLS.bind(Messages.localstore_resourceIsOutOfSync, project.getName());
411             failed(new ResourceStatus(IResourceStatus.OUT_OF_SYNC_LOCAL, project.getFullPath(), message));
412             return false;
413         }
414
415         //Now delete the project description file
416
IResource file = project.findMember(IProjectDescription.DESCRIPTION_FILE_NAME);
417         if (file == null) {
418             //the .project have may have been recreated on disk automatically by snapshot
419
IFileStore dotProject = projectStore.getChild(IProjectDescription.DESCRIPTION_FILE_NAME);
420             try {
421                 dotProject.delete(EFS.NONE, null);
422             } catch (CoreException e) {
423                 failed(e.getStatus());
424             }
425         } else {
426             boolean deletedProjectFile = internalDeleteFile((IFile) file, flags, Policy.monitorFor(null));
427             if (!deletedProjectFile) {
428                 String JavaDoc message = NLS.bind(Messages.resources_couldnotDelete, file.getFullPath());
429                 IStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, file.getFullPath(), message);
430                 failed(status);
431                 // Indicate that the delete was unsuccessful.
432
return false;
433             }
434         }
435
436         //children are deleted, so now delete the parent
437
try {
438             projectStore.delete(EFS.NONE, null);
439             deletedProject(project);
440             // Indicate that the delete was successful.
441
return true;
442         } catch (CoreException e) {
443             String JavaDoc message = NLS.bind(Messages.resources_couldnotDelete, projectStore.toString());
444             IStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, project.getFullPath(), message, e);
445             failed(status);
446             // Indicate that the delete was unsuccessful.
447
return false;
448         }
449     }
450
451     /**
452      * Return <code>true</code> if there is a change in the content area for the project.
453      */

454     private boolean isContentChange(IProject project, IProjectDescription destDescription) {
455         IProjectDescription srcDescription = ((Project) project).internalGetDescription();
456         URI JavaDoc srcLocation = srcDescription.getLocationURI();
457         URI JavaDoc destLocation = destDescription.getLocationURI();
458         if (srcLocation == null || destLocation == null)
459             return true;
460         //don't use URIUtil because we want to treat case rename as a content change
461
return !srcLocation.equals(destLocation);
462     }
463
464     /**
465      * Return <code>true</code> if there is a change in the name of the project.
466      */

467     private boolean isNameChange(IProject project, IProjectDescription description) {
468         return !project.getName().equals(description.getName());
469     }
470
471     /**
472      * @see IResourceTree#isSynchronized(IResource, int)
473      */

474     public boolean isSynchronized(IResource resource, int depth) {
475         try {
476             lock.acquire();
477             return localManager.isSynchronized(resource, depth);
478         } finally {
479             lock.release();
480         }
481     }
482
483     /**
484      * The specific operation for which this tree was created has completed and this tree
485      * should not be used anymore. Ensure that this is the case by making it invalid. This
486      * is checked by all API methods.
487      */

488     void makeInvalid() {
489         this.isValid = false;
490     }
491
492     /**
493      * @see IResourceTree#movedFile(IFile, IFile)
494      */

495     public void movedFile(IFile source, IFile destination) {
496         Assert.isLegal(isValid);
497         try {
498             lock.acquire();
499             // Do nothing if the resource doesn't exist.
500
if (!source.exists())
501                 return;
502             // If the destination already exists then we have a problem.
503
if (destination.exists()) {
504                 String JavaDoc message = NLS.bind(Messages.resources_mustNotExist, destination.getFullPath());
505                 IStatus status = new ResourceStatus(IStatus.ERROR, destination.getFullPath(), message);
506                 // log the status but don't return until we try and move the rest of the resource information.
507
failed(status);
508             }
509
510             // Move the resource's persistent properties.
511
IPropertyManager propertyManager = ((Resource) source).getPropertyManager();
512             try {
513                 propertyManager.copy(source, destination, IResource.DEPTH_ZERO);
514                 propertyManager.deleteProperties(source, IResource.DEPTH_ZERO);
515             } catch (CoreException e) {
516                 String JavaDoc message = NLS.bind(Messages.resources_errorPropertiesMove, source.getFullPath(), destination.getFullPath());
517                 IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e);
518                 // log the status but don't return until we try and move the rest of the resource information.
519
failed(status);
520             }
521
522             // Move the node in the workspace tree.
523
Workspace workspace = (Workspace) source.getWorkspace();
524             try {
525                 workspace.move((Resource) source, destination.getFullPath(), IResource.DEPTH_ZERO, updateFlags, false);
526             } catch (CoreException e) {
527                 String JavaDoc message = NLS.bind(Messages.resources_errorMoving, source.getFullPath(), destination.getFullPath());
528                 IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e);
529                 // log the status but don't return until we try and move the rest of the resource information.
530
failed(status);
531             }
532
533             // Generate the marker deltas.
534
try {
535                 workspace.getMarkerManager().moved(source, destination, IResource.DEPTH_ZERO);
536             } catch (CoreException e) {
537                 String JavaDoc message = NLS.bind(Messages.resources_errorMarkersDelete, source.getFullPath());
538                 IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e);
539                 failed(status);
540             }
541
542             // Copy the local history information
543
copyLocalHistory(source, destination);
544         } finally {
545             lock.release();
546         }
547     }
548
549     /**
550      * @see IResourceTree#movedFolderSubtree(IFolder, IFolder)
551      */

552     public void movedFolderSubtree(IFolder source, IFolder destination) {
553         Assert.isLegal(isValid);
554         try {
555             lock.acquire();
556             // Do nothing if the source resource doesn't exist.
557
if (!source.exists())
558                 return;
559             // If the destination already exists then we have an error.
560
if (destination.exists()) {
561                 String JavaDoc message = NLS.bind(Messages.resources_mustNotExist, destination.getFullPath());
562                 IStatus status = new ResourceStatus(IStatus.ERROR, destination.getFullPath(), message);
563                 failed(status);
564                 return;
565             }
566
567             // Move the folder properties.
568
int depth = IResource.DEPTH_INFINITE;
569             IPropertyManager propertyManager = ((Resource) source).getPropertyManager();
570             try {
571                 propertyManager.copy(source, destination, depth);
572                 propertyManager.deleteProperties(source, depth);
573             } catch (CoreException e) {
574                 String JavaDoc message = NLS.bind(Messages.resources_errorPropertiesMove, source.getFullPath(), destination.getFullPath());
575                 IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e);
576                 // log the status but don't return until we try and move the rest of the resource info
577
failed(status);
578             }
579
580             // Create the destination node in the tree.
581
Workspace workspace = (Workspace) source.getWorkspace();
582             try {
583                 workspace.move((Resource) source, destination.getFullPath(), depth, updateFlags, false);
584             } catch (CoreException e) {
585                 String JavaDoc message = NLS.bind(Messages.resources_errorMoving, source.getFullPath(), destination.getFullPath());
586                 IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e);
587                 // log the status but don't return until we try and move the rest of the resource info
588
failed(status);
589             }
590
591             // Generate the marker deltas.
592
try {
593                 workspace.getMarkerManager().moved(source, destination, depth);
594             } catch (CoreException e) {
595                 String JavaDoc message = NLS.bind(Messages.resources_errorMarkersDelete, source.getFullPath());
596                 IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e);
597                 failed(status);
598             }
599
600             // Copy the local history for this folder
601
copyLocalHistory(source, destination);
602         } finally {
603             lock.release();
604         }
605     }
606
607     /**
608      * @see IResourceTree#movedProjectSubtree(IProject, IProjectDescription)
609      */

610     public boolean movedProjectSubtree(IProject project, IProjectDescription destDescription) {
611         Assert.isLegal(isValid);
612         try {
613             lock.acquire();
614             // Do nothing if the source resource doesn't exist.
615
if (!project.exists())
616                 return true;
617
618             Project source = (Project) project;
619             Project destination = (Project) source.getWorkspace().getRoot().getProject(destDescription.getName());
620             Workspace workspace = (Workspace) source.getWorkspace();
621             int depth = IResource.DEPTH_INFINITE;
622
623             // If the name of the source and destination projects are not the same then
624
// rename the meta area and make changes in the tree.
625
if (isNameChange(source, destDescription)) {
626                 if (destination.exists()) {
627                     String JavaDoc message = NLS.bind(Messages.resources_mustNotExist, destination.getFullPath());
628                     IStatus status = new ResourceStatus(IStatus.ERROR, destination.getFullPath(), message);
629                     failed(status);
630                     return false;
631                 }
632
633                 // Rename the project metadata area. Close the property store to flush everything to disk
634
try {
635                     source.getPropertyManager().closePropertyStore(source);
636                     localManager.getHistoryStore().closeHistoryStore(source);
637                 } catch (CoreException e) {
638                     String JavaDoc message = NLS.bind(Messages.properties_couldNotClose, source.getFullPath());
639                     IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e);
640                     // log the status but don't return until we try and move the rest of the resource info
641
failed(status);
642                 }
643                 final IFileSystem fileSystem = EFS.getLocalFileSystem();
644                 IFileStore oldMetaArea = fileSystem.getStore(workspace.getMetaArea().locationFor(source));
645                 IFileStore newMetaArea = fileSystem.getStore(workspace.getMetaArea().locationFor(destination));
646                 try {
647                     oldMetaArea.move(newMetaArea, EFS.NONE, new NullProgressMonitor());
648                 } catch (CoreException e) {
649                     String JavaDoc message = NLS.bind(Messages.resources_moveMeta, oldMetaArea, newMetaArea);
650                     IStatus status = new ResourceStatus(IResourceStatus.FAILED_WRITE_METADATA, destination.getFullPath(), message, e);
651                     // log the status but don't return until we try and move the rest of the resource info
652
failed(status);
653                 }
654
655                 // Move the workspace tree.
656
try {
657                     workspace.move(source, destination.getFullPath(), depth, updateFlags, true);
658                 } catch (CoreException e) {
659                     String JavaDoc message = NLS.bind(Messages.resources_errorMoving, source.getFullPath(), destination.getFullPath());
660                     IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e);
661                     // log the status but don't return until we try and move the rest of the resource info
662
failed(status);
663                 }
664
665                 // Clear stale state on the destination project.
666
((ProjectInfo) destination.getResourceInfo(false, true)).fixupAfterMove();
667
668                 // Generate marker deltas.
669
try {
670                     workspace.getMarkerManager().moved(source, destination, depth);
671                 } catch (CoreException e) {
672                     String JavaDoc message = NLS.bind(Messages.resources_errorMarkersMove, source.getFullPath(), destination.getFullPath());
673                     IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e);
674                     // log the status but don't return until we try and move the rest of the resource info
675
failed(status);
676                 }
677                 // Copy the local history
678
copyLocalHistory(source, destination);
679             }
680
681             // Write the new project description on the destination project.
682
try {
683                 //moving linked resources may have modified the description in memory
684
((ProjectDescription) destDescription).setLinkDescriptions(destination.internalGetDescription().getLinks());
685                 destination.internalSetDescription(destDescription, true);
686                 destination.writeDescription(IResource.FORCE);
687             } catch (CoreException e) {
688                 String JavaDoc message = Messages.resources_projectDesc;
689                 IStatus status = new ResourceStatus(IStatus.ERROR, destination.getFullPath(), message, e);
690                 failed(status);
691             }
692
693             // write the private project description, including the project location
694
try {
695                 workspace.getMetaArea().writePrivateDescription(destination);
696             } catch (CoreException e) {
697                 failed(e.getStatus());
698             }
699
700             // Do a refresh on the destination project to pick up any newly discovered resources
701
try {
702                 destination.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
703             } catch (CoreException e) {
704                 String JavaDoc message = NLS.bind(Messages.resources_errorRefresh, destination.getFullPath());
705                 IStatus status = new ResourceStatus(IStatus.ERROR, destination.getFullPath(), message, e);
706                 failed(status);
707                 return false;
708             }
709             return true;
710         } finally {
711             lock.release();
712         }
713     }
714
715     /**
716      * Helper method for moving the project content. Determines the content location
717      * based on the project description. (default location or user defined?)
718      */

719     private void moveProjectContent(IProject source, IFileStore destStore, int flags, IProgressMonitor monitor) throws CoreException {
720         try {
721             String JavaDoc message = NLS.bind(Messages.resources_moving, source.getFullPath());
722             monitor.beginTask(message, 10);
723             IProjectDescription srcDescription = source.getDescription();
724             URI JavaDoc srcLocation = srcDescription.getLocationURI();
725             // If the locations are the same (and non-default) then there is nothing to do.
726
if (srcLocation != null && URIUtil.equals(srcLocation, destStore.toURI()))
727                 return;
728
729             //If this is a replace, just make sure the destination location exists, and return
730
boolean replace = (flags & IResource.REPLACE) != 0;
731             if (replace) {
732                 destStore.mkdir(EFS.NONE, Policy.subMonitorFor(monitor, 10));
733                 return;
734             }
735
736             // Move the contents on disk.
737
localManager.move(source, destStore, flags, Policy.subMonitorFor(monitor, 9));
738
739             //if this is a deep move, move the contents of any linked resources
740
if ((flags & IResource.SHALLOW) == 0) {
741                 IResource[] children = source.members();
742                 for (int i = 0; i < children.length; i++) {
743                     if (children[i].isLinked()) {
744                         message = NLS.bind(Messages.resources_moving, children[i].getFullPath());
745                         monitor.subTask(message);
746                         IFileStore linkDestination = destStore.getChild(children[i].getName());
747                         try {
748                             localManager.move(children[i], linkDestination, flags, Policy.monitorFor(null));
749                         } catch (CoreException ce) {
750                             //log the failure, but keep trying on remaining links
751
failed(ce.getStatus());
752                         }
753                     }
754                 }
755             }
756             monitor.worked(1);
757         } finally {
758             monitor.done();
759         }
760     }
761
762     /**
763      * @see IResourceTree#standardDeleteFile(IFile, int, IProgressMonitor)
764      */

765     public void standardDeleteFile(IFile file, int flags, IProgressMonitor monitor) {
766         Assert.isLegal(isValid);
767         try {
768             lock.acquire();
769             internalDeleteFile(file, flags, monitor);
770         } finally {
771             lock.release();
772         }
773     }
774
775     /**
776      * @see IResourceTree#standardDeleteFolder(IFolder, int, IProgressMonitor)
777      */

778     public void standardDeleteFolder(IFolder folder, int flags, IProgressMonitor monitor) {
779         Assert.isLegal(isValid);
780         try {
781             lock.acquire();
782             internalDeleteFolder(folder, flags, monitor);
783         } finally {
784             lock.release();
785             monitor.done();
786         }
787     }
788
789     /**
790      * @see IResourceTree#standardDeleteProject(IProject, int, IProgressMonitor)
791      */

792     public void standardDeleteProject(IProject project, int flags, IProgressMonitor monitor) {
793         Assert.isLegal(isValid);
794         try {
795             lock.acquire();
796             String JavaDoc message = NLS.bind(Messages.resources_deleting, project.getFullPath());
797             monitor.beginTask(message, Policy.totalWork);
798             // Do nothing if the project doesn't exist in the workspace tree.
799
if (!project.exists())
800                 return;
801
802             boolean alwaysDeleteContent = (flags & IResource.ALWAYS_DELETE_PROJECT_CONTENT) != 0;
803             //force is implied if alwaysDeleteContent is true
804
if (alwaysDeleteContent)
805                 flags |= IResource.FORCE;
806             boolean force = (flags & IResource.FORCE) != 0;
807             boolean neverDeleteContent = (flags & IResource.NEVER_DELETE_PROJECT_CONTENT) != 0;
808             boolean success = true;
809
810             // Delete project content. Don't do anything if the user specified explicitly asked
811
// not to delete the project content or if the project is closed and
812
// ALWAYS_DELETE_PROJECT_CONTENT was not specified.
813
if (alwaysDeleteContent || (project.isOpen() && !neverDeleteContent)) {
814                 // Check to see if we are synchronized with the local file system. If we are in sync then
815
// we can short circuit this operation and delete all the files on disk, otherwise we have
816
// to recursively try and delete them doing best-effort, thus leaving only the ones which
817
// were out of sync.
818
if (!force && !isSynchronized(project, IResource.DEPTH_INFINITE)) {
819                     // we are not in sync and force is false so delete via best effort
820
success = internalDeleteProject(project, flags, monitor);
821                     if (!success) {
822                         IFileStore store = localManager.getStore(project);
823                         message = NLS.bind(Messages.resources_couldnotDelete, store.toString());
824                         IStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, project.getFullPath(), message);
825                         failed(status);
826                     }
827                     return;
828                 }
829
830                 try {
831                     IFileStore projectStore = localManager.getStore(project);
832                     // if the project is open, we must perform a best-effort deletion
833
if (project.isOpen()) {
834                         //use force because we already checked for synchronization above
835
localManager.delete(project, flags & IResource.FORCE, Policy.subMonitorFor(monitor, Policy.totalWork * 7 / 8));
836                     } else {
837                         projectStore.delete(EFS.NONE, Policy.subMonitorFor(monitor, Policy.totalWork * 7 / 8));
838                     }
839                 } catch (CoreException ce) {
840                     message = NLS.bind(Messages.localstore_couldnotDelete, project.getFullPath());
841                     MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.FAILED_DELETE_LOCAL, message, ce);
842                     if (ce.getStatus() != null)
843                         status.merge(ce.getStatus());
844                     failed(status);
845                     return;
846                 }
847             }
848
849             // Signal that the workspace tree should be updated that the project has been deleted.
850
if (success)
851                 deletedProject(project);
852             else {
853                 message = NLS.bind(Messages.localstore_couldnotDelete, project.getFullPath());
854                 IStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, project.getFullPath(), message);
855                 failed(status);
856             }
857         } finally {
858             lock.release();
859             monitor.done();
860         }
861     }
862
863     /**
864      * @see IResourceTree#standardMoveFile(IFile, IFile, int, IProgressMonitor)
865      */

866     public void standardMoveFile(IFile source, IFile destination, int flags, IProgressMonitor monitor) {
867         Assert.isLegal(isValid);
868         try {
869             lock.acquire();
870             String JavaDoc message = NLS.bind(Messages.resources_moving, source.getFullPath());
871             monitor.subTask(message);
872
873             // These pre-conditions should all be ok but just in case...
874
if (!source.exists() || destination.exists() || !destination.getParent().isAccessible())
875                 throw new IllegalArgumentException JavaDoc();
876
877             boolean force = (flags & IResource.FORCE) != 0;
878             boolean keepHistory = (flags & IResource.KEEP_HISTORY) != 0;
879             boolean isDeep = (flags & IResource.SHALLOW) == 0;
880
881             // If the file is not in sync with the local file system and force is false,
882
// then signal that we have an error.
883
if (!force && !isSynchronized(source, IResource.DEPTH_INFINITE)) {
884                 message = NLS.bind(Messages.localstore_resourceIsOutOfSync, source.getFullPath());
885                 IStatus status = new ResourceStatus(IResourceStatus.OUT_OF_SYNC_LOCAL, source.getFullPath(), message);
886                 failed(status);
887                 return;
888             }
889             monitor.worked(Policy.totalWork / 4);
890
891             // Add the file contents to the local history if requested by the user.
892
if (keepHistory)
893                 addToLocalHistory(source);
894             monitor.worked(Policy.totalWork / 4);
895
896             //for shallow move of linked resources, nothing needs to be moved in the file system
897
if (!isDeep && source.isLinked()) {
898                 movedFile(source, destination);
899                 return;
900             }
901
902             // If the file was successfully moved in the file system then the workspace
903
// tree needs to be updated accordingly. Otherwise signal that we have an error.
904
IFileStore destStore = null;
905             boolean failedDeletingSource = false;
906             try {
907                 destStore = localManager.getStore(destination);
908                 //ensure parent of destination exists
909
destStore.getParent().mkdir(EFS.NONE, Policy.subMonitorFor(monitor, 0));
910                 localManager.move(source, destStore, flags, monitor);
911             } catch (CoreException e) {
912                 failed(e.getStatus());
913                 // did the fail occur after copying to the destination?
914
failedDeletingSource = destStore != null && destStore.fetchInfo().exists();
915                 // if so, we should proceed
916
if (!failedDeletingSource)
917                     return;
918             }
919             movedFile(source, destination);
920             updateMovedFileTimestamp(destination, internalComputeTimestamp(destination));
921             if (failedDeletingSource) {
922                 //recreate source file to ensure we are not out of sync
923
try {
924                     source.refreshLocal(IResource.DEPTH_INFINITE, null);
925                 } catch (CoreException e) {
926                     //ignore secondary failure - we have already logged the main failure
927
}
928             }
929             monitor.worked(Policy.totalWork / 4);
930             return;
931         } finally {
932             lock.release();
933             monitor.done();
934         }
935     }
936
937     /**
938      * @see IResourceTree#standardMoveFolder(IFolder, IFolder, int, IProgressMonitor)
939      */

940     public void standardMoveFolder(IFolder source, IFolder destination, int flags, IProgressMonitor monitor) {
941         Assert.isLegal(isValid);
942         try {
943             lock.acquire();
944             String JavaDoc message = NLS.bind(Messages.resources_moving, source.getFullPath());
945             monitor.beginTask(message, 100);
946
947             // These pre-conditions should all be ok but just in case...
948
if (!source.exists() || destination.exists() || !destination.getParent().isAccessible())
949                 throw new IllegalArgumentException JavaDoc();
950
951             // Check to see if we are synchronized with the local file system. If we are in sync then we can
952
// short circuit this method and do a file system only move. Otherwise we have to recursively
953
// try and move all resources, doing it in a best-effort manner.
954
boolean force = (flags & IResource.FORCE) != 0;
955             if (!force && !isSynchronized(source, IResource.DEPTH_INFINITE)) {
956                 message = NLS.bind(Messages.localstore_resourceIsOutOfSync, source.getFullPath());
957                 IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message);
958                 failed(status);
959                 return;
960             }
961             monitor.worked(20);
962
963             //for linked resources, nothing needs to be moved in the file system
964
boolean isDeep = (flags & IResource.SHALLOW) == 0;
965             if (!isDeep && source.isLinked()) {
966                 movedFolderSubtree(source, destination);
967                 return;
968             }
969
970             // Move the resources in the file system. Only the FORCE flag is valid here so don't
971
// have to worry about clearing the KEEP_HISTORY flag.
972
IFileStore destStore = null;
973             boolean failedDeletingSource = false;
974             try {
975                 destStore = localManager.getStore(destination);
976                 localManager.move(source, destStore, flags, Policy.subMonitorFor(monitor, 60));
977             } catch (CoreException e) {
978                 failed(e.getStatus());
979                 // did the fail occur after copying to the destination?
980
failedDeletingSource = destStore != null && destStore.fetchInfo().exists();
981                 // if so, we should proceed
982
if (!failedDeletingSource)
983                     return;
984             }
985             movedFolderSubtree(source, destination);
986             monitor.worked(20);
987             updateTimestamps(destination, isDeep);
988             if (failedDeletingSource) {
989                 //the move could have been partially successful, so refresh to ensure we are in sync
990
try {
991                     source.refreshLocal(IResource.DEPTH_INFINITE, null);
992                     destination.refreshLocal(IResource.DEPTH_INFINITE, null);
993                 } catch (CoreException e) {
994                     //ignore secondary failures -we have already logged main failure
995
}
996             }
997         } finally {
998             lock.release();
999             monitor.done();
1000        }
1001    }
1002
1003    /**
1004     * @see IResourceTree#standardMoveProject(IProject, IProjectDescription, int, IProgressMonitor)
1005     */

1006    public void standardMoveProject(IProject source, IProjectDescription description, int flags, IProgressMonitor monitor) {
1007        Assert.isLegal(isValid);
1008        try {
1009            lock.acquire();
1010            String JavaDoc message = NLS.bind(Messages.resources_moving, source.getFullPath());
1011            monitor.beginTask(message, Policy.totalWork);
1012
1013            // Double-check this pre-condition.
1014
if (!source.isAccessible())
1015                throw new IllegalArgumentException JavaDoc();
1016
1017            // If there is nothing to do on disk then signal to make the workspace tree
1018
// changes.
1019
if (!isContentChange(source, description)) {
1020                movedProjectSubtree(source, description);
1021                return;
1022            }
1023
1024            // Check to see if we are synchronized with the local file system.
1025
boolean force = (flags & IResource.FORCE) != 0;
1026            if (!force && !isSynchronized(source, IResource.DEPTH_INFINITE)) {
1027                // FIXME: make this a best effort move?
1028
message = NLS.bind(Messages.localstore_resourceIsOutOfSync, source.getFullPath());
1029                IStatus status = new ResourceStatus(IResourceStatus.OUT_OF_SYNC_LOCAL, source.getFullPath(), message);
1030                failed(status);
1031                return;
1032            }
1033
1034            IFileStore destinationStore;
1035            try {
1036                destinationStore = computeDestinationStore(description);
1037                //destination can be non-empty on replace
1038
if ((flags & IResource.REPLACE) == 0)
1039                    if (!ensureDestinationEmpty(source, destinationStore, monitor))
1040                        return;
1041            } catch (CoreException e) {
1042                //must fail if the destination location cannot be accessd (undefined file system)
1043
message = NLS.bind(Messages.localstore_couldNotMove, source.getFullPath());
1044                IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e);
1045                failed(status);
1046                return;
1047            }
1048
1049            // Move the project content in the local file system.
1050
try {
1051                moveProjectContent(source, destinationStore, flags, Policy.subMonitorFor(monitor, Policy.totalWork * 3 / 4));
1052            } catch (CoreException e) {
1053                message = NLS.bind(Messages.localstore_couldNotMove, source.getFullPath());
1054                IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e);
1055                failed(status);
1056                //refresh the project because it might have been partially moved
1057
try {
1058                    source.refreshLocal(IResource.DEPTH_INFINITE, null);
1059                } catch (CoreException e2) {
1060                    //ignore secondary failures
1061
}
1062            }
1063
1064            // If we got this far the project content has been moved on disk (if necessary)
1065
// and we need to update the workspace tree.
1066
movedProjectSubtree(source, description);
1067            monitor.worked(Policy.totalWork * 1 / 8);
1068
1069            boolean isDeep = (flags & IResource.SHALLOW) == 0;
1070            updateTimestamps(source.getWorkspace().getRoot().getProject(description.getName()), isDeep);
1071            monitor.worked(Policy.totalWork * 1 / 8);
1072        } finally {
1073            lock.release();
1074            monitor.done();
1075        }
1076    }
1077
1078    /**
1079     * @see IResourceTree#updateMovedFileTimestamp(IFile, long)
1080     */

1081    public void updateMovedFileTimestamp(IFile file, long timestamp) {
1082        Assert.isLegal(isValid);
1083        try {
1084            lock.acquire();
1085            // Do nothing if the file doesn't exist in the workspace tree.
1086
if (!file.exists())
1087                return;
1088            // Update the timestamp in the tree.
1089
ResourceInfo info = ((Resource) file).getResourceInfo(false, true);
1090            // The info should never be null since we just checked that the resource exists in the tree.
1091
localManager.updateLocalSync(info, timestamp);
1092            //remove the linked bit since this resource has been moved in the file system
1093
info.clear(ICoreConstants.M_LINK);
1094        } finally {
1095            lock.release();
1096        }
1097    }
1098
1099    /**
1100     * Helper method to update all the timestamps in the tree to match
1101     * those in the file system. Used after a #move.
1102     */

1103    private void updateTimestamps(IResource root, final boolean isDeep) {
1104        IResourceVisitor visitor = new IResourceVisitor() {
1105            public boolean visit(IResource resource) {
1106                if (resource.isLinked()) {
1107                    if (isDeep) {
1108                        //clear the linked resource bit, if any
1109
ResourceInfo info = ((Resource) resource).getResourceInfo(false, true);
1110                        info.clear(ICoreConstants.M_LINK);
1111                    }
1112                    return true;
1113                }
1114                //only needed if underlying file system does not preserve timestamps
1115
// if (resource.getType() == IResource.FILE) {
1116
// IFile file = (IFile) resource;
1117
// updateMovedFileTimestamp(file, computeTimestamp(file));
1118
// }
1119
return true;
1120            }
1121        };
1122        try {
1123            root.accept(visitor, IResource.DEPTH_INFINITE, IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS);
1124        } catch (CoreException e) {
1125            // No exception should be thrown.
1126
}
1127    }
1128}
1129
Popular Tags