KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.util.*;
15 import org.eclipse.core.filesystem.EFS;
16 import org.eclipse.core.filesystem.IFileStore;
17 import org.eclipse.core.internal.events.LifecycleEvent;
18 import org.eclipse.core.internal.utils.*;
19 import org.eclipse.core.resources.*;
20 import org.eclipse.core.resources.team.IMoveDeleteHook;
21 import org.eclipse.core.runtime.*;
22 import org.eclipse.core.runtime.content.IContentTypeMatcher;
23 import org.eclipse.core.runtime.jobs.ISchedulingRule;
24 import org.eclipse.osgi.util.NLS;
25
26 public class Project extends Container implements IProject {
27
28     protected Project(IPath path, Workspace container) {
29         super(path, container);
30     }
31
32     /*
33      * If the creation boolean is true then this method is being called on project creation.
34      * Otherwise it is being called via #setDescription. The difference is that we don't allow
35      * some description fields to change value after project creation. (e.g. project location)
36      */

37     protected MultiStatus basicSetDescription(ProjectDescription description, int updateFlags) {
38         String JavaDoc message = Messages.resources_projectDesc;
39         MultiStatus result = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.FAILED_WRITE_METADATA, message, null);
40         ProjectDescription current = internalGetDescription();
41         current.setComment(description.getComment());
42         // set the build order before setting the references or the natures
43
current.setBuildSpec(description.getBuildSpec(true));
44
45         // set the references before the natures
46
boolean flushOrder = false;
47         IProject[] oldReferences = current.getReferencedProjects();
48         IProject[] newReferences = description.getReferencedProjects();
49         if (!Arrays.equals(oldReferences, newReferences)) {
50             current.setReferencedProjects(newReferences);
51             flushOrder = true;
52         }
53         oldReferences = current.getDynamicReferences();
54         newReferences = description.getDynamicReferences();
55         if (!Arrays.equals(oldReferences, newReferences)) {
56             current.setDynamicReferences(newReferences);
57             flushOrder = true;
58         }
59
60         if (flushOrder)
61             workspace.flushBuildOrder();
62
63         // the natures last as this may cause recursive calls to setDescription.
64
if ((updateFlags & IResource.AVOID_NATURE_CONFIG) == 0)
65             workspace.getNatureManager().configureNatures(this, current, description, result);
66         else
67             current.setNatureIds(description.getNatureIds(false));
68         return result;
69     }
70
71     /* (non-Javadoc)
72      * @see IProject#build(int, IProgressMonitor)
73      */

74     public void build(int trigger, IProgressMonitor monitor) throws CoreException {
75         internalBuild(trigger, null, null, monitor);
76     }
77
78     /* (non-Javadoc)
79      * @see IProject#build(int, String, Map, IProgressMonitor)
80      */

81     public void build(int trigger, String JavaDoc builderName, Map args, IProgressMonitor monitor) throws CoreException {
82         Assert.isNotNull(builderName);
83         internalBuild(trigger, builderName, args, monitor);
84     }
85
86     /**
87      * Checks that this resource is accessible. Typically this means that it
88      * exists. In the case of projects, they must also be open.
89      * If phantom is true, phantom resources are considered.
90      *
91      * @exception CoreException if this resource is not accessible
92      */

93     public void checkAccessible(int flags) throws CoreException {
94         super.checkAccessible(flags);
95         if (!isOpen(flags)) {
96             String JavaDoc message = NLS.bind(Messages.resources_mustBeOpen, getFullPath());
97             throw new ResourceException(IResourceStatus.PROJECT_NOT_OPEN, getFullPath(), message, null);
98         }
99     }
100
101     /**
102      * Checks validity of the given project description.
103      */

104     protected void checkDescription(IProject project, IProjectDescription desc, boolean moving) throws CoreException {
105         URI JavaDoc location = desc.getLocationURI();
106         if (location == null)
107             return;
108         String JavaDoc message = Messages.resources_invalidProjDesc;
109         MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.INVALID_VALUE, message, null);
110         status.merge(workspace.validateName(desc.getName(), IResource.PROJECT));
111         if (moving) {
112             // if we got here from a move call then we should check the location in the description since
113
// its possible that we want to do a rename without moving the contents. (and we shouldn't
114
// throw an Overlapping mapping exception in this case) So if the source description's location
115
// is null (we are using the default) or if the locations aren't equal, then validate the location
116
// of the new description. Otherwise both locations aren't null and they are equal so ignore validation.
117
URI JavaDoc sourceLocation = internalGetDescription().getLocationURI();
118             if (sourceLocation == null || !sourceLocation.equals(location))
119                 status.merge(workspace.validateProjectLocationURI(project, location));
120         } else
121             // otherwise continue on like before
122
status.merge(workspace.validateProjectLocationURI(project, location));
123         if (!status.isOK())
124             throw new ResourceException(status);
125     }
126
127     /* (non-Javadoc)
128      * @see IProject#close(IProgressMonitor)
129      */

130     public void close(IProgressMonitor monitor) throws CoreException {
131         monitor = Policy.monitorFor(monitor);
132         try {
133             String JavaDoc msg = NLS.bind(Messages.resources_closing_1, getName());
134             monitor.beginTask(msg, Policy.totalWork);
135             final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(this);
136             try {
137                 // Do this before the prepare to allow lifecycle participants to change the tree.
138
workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_CLOSE, this));
139                 workspace.prepareOperation(rule, monitor);
140                 ResourceInfo info = getResourceInfo(false, false);
141                 int flags = getFlags(info);
142                 checkExists(flags, true);
143                 monitor.subTask(msg);
144                 if (!isOpen(flags))
145                     return;
146                 // Signal that this resource is about to be closed. Do this at the very
147
// beginning so that infrastructure pieces have a chance to do clean up
148
// while the resources still exist.
149
workspace.beginOperation(true);
150                 // flush the build order early in case there is a problem
151
workspace.flushBuildOrder();
152                 IProgressMonitor sub = Policy.subMonitorFor(monitor, Policy.opWork / 2, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL);
153                 IStatus saveStatus = workspace.getSaveManager().save(ISaveContext.PROJECT_SAVE, this, sub);
154                 internalClose();
155                 monitor.worked(Policy.opWork / 2);
156                 if (saveStatus != null && !saveStatus.isOK())
157                     throw new ResourceException(saveStatus);
158             } catch (OperationCanceledException e) {
159                 workspace.getWorkManager().operationCanceled();
160                 throw e;
161             } finally {
162                 workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.endOpWork));
163             }
164         } finally {
165             monitor.done();
166         }
167     }
168
169     /* (non-Javadoc)
170      * @see IResource#copy(IPath, int, IProgressMonitor)
171      */

172     public void copy(IPath destination, int updateFlags, IProgressMonitor monitor) throws CoreException {
173         // FIXME - the logic here for copying projects needs to be moved to Resource.copy
174
// so that IResource.copy(IPath,int,IProgressMonitor) works properly for
175
// projects and honours all update flags
176
monitor = Policy.monitorFor(monitor);
177         if (destination.segmentCount() == 1) {
178             // copy project to project
179
String JavaDoc projectName = destination.segment(0);
180             IProjectDescription desc = getDescription();
181             desc.setName(projectName);
182             desc.setLocation(null);
183             internalCopy(desc, updateFlags, monitor);
184         } else {
185             // will fail since we're trying to copy a project to a non-project
186
checkCopyRequirements(destination, IResource.PROJECT, updateFlags);
187         }
188     }
189
190     /* (non-Javadoc)
191      * @see IResource#copy(IProjectDescription, int, IProgressMonitor)
192      */

193     public void copy(IProjectDescription destination, int updateFlags, IProgressMonitor monitor) throws CoreException {
194         // FIXME - the logic here for copying projects needs to be moved to Resource.copy
195
// so that IResource.copy(IProjectDescription,int,IProgressMonitor) works properly for
196
// projects and honours all update flags
197
Assert.isNotNull(destination);
198         internalCopy(destination, updateFlags, monitor);
199     }
200
201     protected void copyMetaArea(IProject source, IProject destination, IProgressMonitor monitor) throws CoreException {
202         IFileStore oldMetaArea = EFS.getFileSystem(EFS.SCHEME_FILE).getStore(workspace.getMetaArea().locationFor(source));
203         IFileStore newMetaArea = EFS.getFileSystem(EFS.SCHEME_FILE).getStore(workspace.getMetaArea().locationFor(destination));
204         oldMetaArea.copy(newMetaArea, EFS.NONE, monitor);
205     }
206
207     /* (non-Javadoc)
208      * @see IProject#create(IProgressMonitor)
209      */

210     public void create(IProgressMonitor monitor) throws CoreException {
211         create(null, monitor);
212     }
213
214     /* (non-Javadoc)
215      * @see IProject#create(IProjectDescription, IProgressMonitor)
216      */

217     public void create(IProjectDescription description, IProgressMonitor monitor) throws CoreException {
218         monitor = Policy.monitorFor(monitor);
219         try {
220             monitor.beginTask(Messages.resources_create, Policy.totalWork);
221             checkValidPath(path, PROJECT, false);
222             final ISchedulingRule rule = workspace.getRuleFactory().createRule(this);
223             try {
224                 workspace.prepareOperation(rule, monitor);
225                 checkDoesNotExist();
226                 if (description != null)
227                     checkDescription(this, description, false);
228                 workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_CREATE, this));
229                 workspace.beginOperation(true);
230                 workspace.createResource(this, false);
231                 workspace.getMetaArea().create(this);
232                 ProjectInfo info = (ProjectInfo) getResourceInfo(false, true);
233
234                 // setup description to obtain project location
235
ProjectDescription desc;
236                 if (description == null) {
237                     desc = new ProjectDescription();
238                 } else {
239                     desc = (ProjectDescription) ((ProjectDescription) description).clone();
240                     desc.setLocationURI(FileUtil.canonicalURI(description.getLocationURI()));
241                 }
242                 desc.setName(getName());
243                 internalSetDescription(desc, false);
244                 // see if there potentially are already contents on disk
245
final boolean hasSavedDescription = getLocalManager().hasSavedDescription(this);
246                 boolean hasContent = hasSavedDescription;
247                 //if there is no project description, there might still be content on disk
248
if (!hasSavedDescription)
249                     hasContent = getLocalManager().hasSavedContent(this);
250                 try {
251                     // look for a description on disk
252
if (hasSavedDescription) {
253                         updateDescription();
254                         //make sure the .location file is written
255
workspace.getMetaArea().writePrivateDescription(this);
256                     } else {
257                         //write out the project
258
writeDescription(IResource.FORCE);
259                     }
260                 } catch (CoreException e) {
261                     workspace.deleteResource(this);
262                     throw e;
263                 }
264                 // inaccessible projects have a null modification stamp.
265
// set this after setting the description as #setDescription
266
// updates the stamp
267
info.clearModificationStamp();
268                 //if a project already had content on disk, mark the project as having unknown children
269
if (hasContent)
270                     info.set(ICoreConstants.M_CHILDREN_UNKNOWN);
271                 workspace.getSaveManager().requestSnapshot();
272             } catch (OperationCanceledException e) {
273                 workspace.getWorkManager().operationCanceled();
274                 throw e;
275             } finally {
276                 workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.endOpWork));
277             }
278         } finally {
279             monitor.done();
280         }
281     }
282
283     /* (non-Javadoc)
284      * @see IProject#delete(boolean, boolean, IProgressMonitor)
285      */

286     public void delete(boolean deleteContent, boolean force, IProgressMonitor monitor) throws CoreException {
287         int updateFlags = force ? IResource.FORCE : IResource.NONE;
288         updateFlags |= deleteContent ? IResource.ALWAYS_DELETE_PROJECT_CONTENT : IResource.NEVER_DELETE_PROJECT_CONTENT;
289         delete(updateFlags, monitor);
290     }
291
292     /* (non-Javadoc)
293      * @see IResource#delete(boolean, IProgressMonitor)
294      */

295     public void delete(boolean force, IProgressMonitor monitor) throws CoreException {
296         int updateFlags = force ? IResource.FORCE : IResource.NONE;
297         delete(updateFlags, monitor);
298     }
299
300     public void deleteResource(boolean convertToPhantom, MultiStatus status) throws CoreException {
301         super.deleteResource(convertToPhantom, status);
302         // Delete the project metadata.
303
workspace.getMetaArea().delete(this);
304         // Clear the history store.
305
clearHistory(null);
306     }
307
308     protected void fixupAfterMoveSource() {
309         workspace.deleteResource(this);
310     }
311
312     /*
313      * (non-Javadoc)
314      * @see IProject#getContentTypeMatcher
315      */

316     public IContentTypeMatcher getContentTypeMatcher() throws CoreException {
317         return workspace.getContentDescriptionManager().getContentTypeMatcher(this);
318     }
319
320     /* (non-Javadoc)
321      * @see IContainer#getDefaultCharset(boolean)
322      */

323     public String JavaDoc getDefaultCharset(boolean checkImplicit) {
324         // non-existing resources default to parent's charset
325
if (!exists())
326             return checkImplicit ? ResourcesPlugin.getEncoding() : null;
327         return workspace.getCharsetManager().getCharsetFor(getFullPath(), checkImplicit);
328     }
329
330     /* (non-Javadoc)
331      * @see IProject#getDescription()
332      */

333     public IProjectDescription getDescription() throws CoreException {
334         ResourceInfo info = getResourceInfo(false, false);
335         checkAccessible(getFlags(info));
336         ProjectDescription description = ((ProjectInfo) info).getDescription();
337         //if the project is currently in the middle of being created, the description might not be available yet
338
if (description == null)
339             checkAccessible(NULL_FLAG);
340         return (IProjectDescription) description.clone();
341     }
342
343     /* (non-Javadoc)
344      * @see IProject#getNature(String)
345      */

346     public IProjectNature getNature(String JavaDoc natureID) throws CoreException {
347         // Has it already been initialized?
348
ProjectInfo info = (ProjectInfo) getResourceInfo(false, false);
349         checkAccessible(getFlags(info));
350         IProjectNature nature = info.getNature(natureID);
351         if (nature == null) {
352             // Not initialized yet. Does this project have the nature?
353
if (!hasNature(natureID))
354                 return null;
355             nature = workspace.getNatureManager().createNature(this, natureID);
356             info.setNature(natureID, nature);
357         }
358         return nature;
359     }
360
361     /* (non-Javadoc)
362      * @see IResource#getParent()
363      */

364     public IContainer getParent() {
365         return workspace.getRoot();
366     }
367
368     /** (non-Javadoc)
369      * @see IProject#getPluginWorkingLocation(IPluginDescriptor)
370      * @deprecated
371      */

372     public IPath getPluginWorkingLocation(IPluginDescriptor plugin) {
373         if (plugin == null)
374             return null;
375         return getWorkingLocation(plugin.getUniqueIdentifier());
376     }
377
378     /* (non-Javadoc)
379      * @see IResource#getProject()
380      */

381     public IProject getProject() {
382         return this;
383     }
384
385     /* (non-Javadoc)
386      * @see IResource#getProjectRelativePath()
387      */

388     public IPath getProjectRelativePath() {
389         return Path.EMPTY;
390     }
391
392     /* (non-Javadoc)
393      * @see IResource#getRawLocation()
394      */

395     public IPath getRawLocation() {
396         ProjectDescription description = internalGetDescription();
397         return description == null ? null : description.getLocation();
398     }
399
400     /* (non-Javadoc)
401      * @see IResource#getRawLocation()
402      */

403     public URI JavaDoc getRawLocationURI() {
404         ProjectDescription description = internalGetDescription();
405         return description == null ? null : description.getLocationURI();
406     }
407
408     /* (non-Javadoc)
409      * @see IProject#getReferencedProjects()
410      */

411     public IProject[] getReferencedProjects() throws CoreException {
412         ResourceInfo info = getResourceInfo(false, false);
413         checkAccessible(getFlags(info));
414         ProjectDescription description = ((ProjectInfo) info).getDescription();
415         //if the project is currently in the middle of being created, the description might not be available yet
416
if (description == null)
417             checkAccessible(NULL_FLAG);
418         return description.getAllReferences(true);
419     }
420
421     /* (non-Javadoc)
422      * @see IProject#getReferencingProjects()
423      */

424     public IProject[] getReferencingProjects() {
425         IProject[] projects = workspace.getRoot().getProjects();
426         List result = new ArrayList(projects.length);
427         for (int i = 0; i < projects.length; i++) {
428             Project project = (Project) projects[i];
429             if (!project.isAccessible())
430                 continue;
431             ProjectDescription description = project.internalGetDescription();
432             if (description == null)
433                 continue;
434             IProject[] references = description.getAllReferences(false);
435             for (int j = 0; j < references.length; j++)
436                 if (references[j].equals(this)) {
437                     result.add(projects[i]);
438                     break;
439                 }
440         }
441         return (IProject[]) result.toArray(new IProject[result.size()]);
442     }
443
444     /* (non-Javadoc)
445      * @see IResource#getType()
446      */

447     public int getType() {
448         return PROJECT;
449     }
450
451     /*
452      * (non-Javadoc)
453      * @see IProject#getWorkingLocation(String)
454      */

455     public IPath getWorkingLocation(String JavaDoc id) {
456         if (id == null || !exists())
457             return null;
458         IPath result = workspace.getMetaArea().getWorkingLocation(this, id);
459         result.toFile().mkdirs();
460         return result;
461     }
462
463     /* (non-Javadoc)
464      * @see IProject#hasNature(String)
465      */

466     public boolean hasNature(String JavaDoc natureID) throws CoreException {
467         checkAccessible(getFlags(getResourceInfo(false, false)));
468         // use #internal method to avoid copy but still throw an
469
// exception if the resource doesn't exist.
470
IProjectDescription desc = internalGetDescription();
471         if (desc == null)
472             checkAccessible(NULL_FLAG);
473         return desc.hasNature(natureID);
474     }
475
476     /**
477      * Implements all build methods on IProject.
478      */

479     protected void internalBuild(int trigger, String JavaDoc builderName, Map args, IProgressMonitor monitor) throws CoreException {
480         monitor = Policy.monitorFor(monitor);
481         final ISchedulingRule rule = workspace.getRuleFactory().buildRule();
482         try {
483             monitor.beginTask("", Policy.opWork); //$NON-NLS-1$
484
try {
485                 workspace.prepareOperation(rule, monitor);
486                 ResourceInfo info = getResourceInfo(false, false);
487                 int flags = getFlags(info);
488                 if (!exists(flags, true) || !isOpen(flags))
489                     return;
490                 workspace.beginOperation(true);
491                 workspace.aboutToBuild(this, trigger);
492                 IStatus result;
493                 try {
494                     result = workspace.getBuildManager().build(this, trigger, builderName, args, Policy.subMonitorFor(monitor, Policy.opWork));
495                 } finally {
496                     //must fire POST_BUILD if PRE_BUILD has occurred
497
workspace.broadcastBuildEvent(this, IResourceChangeEvent.POST_BUILD, trigger);
498                 }
499                 if (!result.isOK())
500                     throw new ResourceException(result);
501             } finally {
502                 //building may close the tree, but we are still inside an operation so open it
503
if (workspace.getElementTree().isImmutable())
504                     workspace.newWorkingTree();
505                 workspace.endOperation(rule, false, Policy.subMonitorFor(monitor, Policy.endOpWork));
506             }
507         } finally {
508             monitor.done();
509         }
510     }
511
512     /**
513      * Closes the project. This is called during restore when there is a failure
514      * to read the project description. Since it is called during workspace restore,
515      * it cannot start any operations.
516      */

517     protected void internalClose() throws CoreException {
518         workspace.flushBuildOrder();
519         getMarkerManager().removeMarkers(this, IResource.DEPTH_INFINITE);
520         // remove each member from the resource tree.
521
// DO NOT use resource.delete() as this will delete it from disk as well.
522
IResource[] members = members(IContainer.INCLUDE_PHANTOMS | IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS);
523         for (int i = 0; i < members.length; i++) {
524             Resource member = (Resource) members[i];
525             workspace.deleteResource(member);
526         }
527         // finally mark the project as closed.
528
ResourceInfo info = getResourceInfo(false, true);
529         info.clear(M_OPEN);
530         info.clearSessionProperties();
531         info.clearModificationStamp();
532         info.setSyncInfo(null);
533     }
534
535     protected void internalCopy(IProjectDescription destDesc, int updateFlags, IProgressMonitor monitor) throws CoreException {
536         monitor = Policy.monitorFor(monitor);
537         try {
538             String JavaDoc message = NLS.bind(Messages.resources_copying, getFullPath());
539             monitor.beginTask(message, Policy.totalWork);
540             String JavaDoc destName = destDesc.getName();
541             IPath destPath = new Path(destName).makeAbsolute();
542             Project destination = (Project) workspace.getRoot().getProject(destName);
543             final ISchedulingRule rule = workspace.getRuleFactory().copyRule(this, destination);
544             try {
545                 workspace.prepareOperation(rule, monitor);
546                 // The following assert method throws CoreExceptions as stated in the IProject.copy API
547
// and assert for programming errors. See checkCopyRequirements for more information.
548
assertCopyRequirements(destPath, IResource.PROJECT, updateFlags);
549                 checkDescription(destination, destDesc, false);
550                 workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_COPY, this, destination, updateFlags));
551
552                 workspace.beginOperation(true);
553                 getLocalManager().refresh(this, DEPTH_INFINITE, true, Policy.subMonitorFor(monitor, Policy.opWork * 20 / 100));
554
555                 // close the property store so incorrect info is not copied to the destination
556
getPropertyManager().closePropertyStore(this);
557                 getLocalManager().getHistoryStore().closeHistoryStore(this);
558
559                 // copy the meta area for the project
560
copyMetaArea(this, destination, Policy.subMonitorFor(monitor, Policy.opWork * 5 / 100));
561
562                 // copy just the project and not its children yet (tree node, properties)
563
internalCopyProjectOnly(destination, Policy.subMonitorFor(monitor, Policy.opWork * 5 / 100));
564
565                 // set the description
566
destination.internalSetDescription(destDesc, false);
567
568                 //create the directory for the new project
569
destination.getStore().mkdir(EFS.NONE, Policy.subMonitorFor(monitor, Policy.opWork * 5 / 100));
570
571                 // call super.copy for each child (excluding project description file)
572
//make it a best effort copy
573
message = Messages.resources_copyProblem;
574                 MultiStatus problems = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.INTERNAL_ERROR, message, null);
575
576                 IResource[] children = members(IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS);
577                 final int childCount = children.length;
578                 final int childWork = childCount > 1 ? Policy.opWork * 50 / 100 / (childCount - 1) : 0;
579                 for (int i = 0; i < childCount; i++) {
580                     IResource child = children[i];
581                     if (!isProjectDescriptionFile(child)) {
582                         try {
583                             child.copy(destPath.append(child.getName()), updateFlags, Policy.subMonitorFor(monitor, childWork));
584                         } catch (CoreException e) {
585                             problems.merge(e.getStatus());
586                         }
587                     }
588                 }
589
590                 // write out the new project description to the meta area
591
try {
592                     destination.writeDescription(IResource.FORCE);
593                 } catch (CoreException e) {
594                     try {
595                         destination.delete((updateFlags & IResource.FORCE) != 0, null);
596                     } catch (CoreException e2) {
597                         // ignore and rethrow the exception that got us here
598
}
599                     throw e;
600                 }
601                 monitor.worked(Policy.opWork * 5 / 100);
602
603                 // refresh local
604
monitor.subTask(Messages.resources_updating);
605                 getLocalManager().refresh(destination, DEPTH_INFINITE, true, Policy.subMonitorFor(monitor, Policy.opWork * 10 / 100));
606                 if (!problems.isOK())
607                     throw new ResourceException(problems);
608             } catch (OperationCanceledException e) {
609                 workspace.getWorkManager().operationCanceled();
610                 throw e;
611             } finally {
612                 workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.endOpWork));
613             }
614         } finally {
615             monitor.done();
616         }
617     }
618
619     /*
620      * Copies just the project and no children. Does NOT copy the meta area.
621      */

622     protected void internalCopyProjectOnly(IResource destination, IProgressMonitor monitor) throws CoreException {
623         // close the property store so bogus values aren't copied to the destination
624
getPropertyManager().closePropertyStore(this);
625         getLocalManager().getHistoryStore().closeHistoryStore(this);
626         // copy the tree and properties
627
workspace.copyTree(this, destination.getFullPath(), IResource.DEPTH_ZERO, IResource.NONE, false);
628         getPropertyManager().copy(this, destination, IResource.DEPTH_ZERO);
629
630         ProjectInfo info = (ProjectInfo) ((Resource) destination).getResourceInfo(false, true);
631
632         //clear properties, markers, and description for the new project, because they shouldn't be copied.
633
info.description = null;
634         info.natures = null;
635         info.setMarkers(null);
636         info.clearSessionProperties();
637     }
638
639     /**
640      * This is an internal helper method. This implementation is different from the API
641      * method getDescription(). This one does not check the project accessibility. It exists
642      * in order to prevent "chicken and egg" problems in places like the project creation.
643      * It may return null.
644      */

645     public ProjectDescription internalGetDescription() {
646         ProjectInfo info = (ProjectInfo) getResourceInfo(false, false);
647         if (info == null)
648             return null;
649         return info.getDescription();
650     }
651
652     /**
653      * Sets this project's description to the given value. This is the body of the
654      * corresponding API method but is needed separately since it is used
655      * during workspace restore (i.e., when you cannot do an operation)
656      */

657     void internalSetDescription(IProjectDescription value, boolean incrementContentId) {
658         ProjectInfo info = (ProjectInfo) getResourceInfo(false, true);
659         info.setDescription((ProjectDescription) value);
660         getLocalManager().setLocation(this, info, value.getLocationURI());
661         if (incrementContentId) {
662             info.incrementContentId();
663             //if the project is not accessible, stamp will be null and should remain null
664
if (info.getModificationStamp() != NULL_STAMP)
665                 workspace.updateModificationStamp(info);
666         }
667     }
668
669     public void internalSetLocal(boolean flag, int depth) throws CoreException {
670         // do nothing for projects, but call for its children
671
if (depth == IResource.DEPTH_ZERO)
672             return;
673         if (depth == IResource.DEPTH_ONE)
674             depth = IResource.DEPTH_ZERO;
675         // get the children via the workspace since we know that this
676
// resource exists (it is local).
677
IResource[] children = getChildren(IResource.NONE);
678         for (int i = 0; i < children.length; i++)
679             ((Resource) children[i]).internalSetLocal(flag, depth);
680     }
681
682     /* (non-Javadoc)
683      * @see IResource#isAccessible()
684      */

685     public boolean isAccessible() {
686         return isOpen();
687     }
688
689     public boolean isLinked(int options) {
690         return false;//projects are never linked
691
}
692
693     /**
694      * @see IResource#isLocal(int)
695      * @deprecated
696      */

697     public boolean isLocal(int depth) {
698         // the flags parameter is ignored for projects so pass anything
699
return isLocal(-1, depth);
700     }
701
702     /**
703      * @see IResource#isLocal(int)
704      * @deprecated
705      */

706     public boolean isLocal(int flags, int depth) {
707         // don't check the flags....projects are always local
708
if (depth == DEPTH_ZERO)
709             return true;
710         if (depth == DEPTH_ONE)
711             depth = DEPTH_ZERO;
712         // get the children via the workspace since we know that this
713
// resource exists (it is local).
714
IResource[] children = getChildren(IResource.NONE);
715         for (int i = 0; i < children.length; i++)
716             if (!children[i].isLocal(depth))
717                 return false;
718         return true;
719     }
720
721     /* (non-Javadoc)
722      * @see IProject#isNatureEnabled(String)
723      */

724     public boolean isNatureEnabled(String JavaDoc natureId) throws CoreException {
725         checkAccessible(getFlags(getResourceInfo(false, false)));
726         return workspace.getNatureManager().isNatureEnabled(this, natureId);
727     }
728
729     /* (non-Javadoc)
730      * @see IProject#isOpen()
731      */

732     public boolean isOpen() {
733         ResourceInfo info = getResourceInfo(false, false);
734         return isOpen(getFlags(info));
735     }
736
737     /* (non-Javadoc)
738      * @see IProject#isOpen()
739      */

740     public boolean isOpen(int flags) {
741         return flags != NULL_FLAG && ResourceInfo.isSet(flags, M_OPEN);
742     }
743
744     /**
745      * Returns true if this resource represents the project description file, and
746      * false otherwise.
747      */

748     protected boolean isProjectDescriptionFile(IResource resource) {
749         return resource.getType() == IResource.FILE && resource.getFullPath().segmentCount() == 2 && resource.getName().equals(IProjectDescription.DESCRIPTION_FILE_NAME);
750     }
751
752     /* (non-Javadoc)
753      * @see IProject#move(IProjectDescription, boolean, IProgressMonitor)
754      */

755     public void move(IProjectDescription destination, boolean force, IProgressMonitor monitor) throws CoreException {
756         Assert.isNotNull(destination);
757         move(destination, force ? IResource.FORCE : IResource.NONE, monitor);
758     }
759
760     /* (non-Javadoc)
761      * @see IResource#move(IProjectDescription, int, IProgressMonitor)
762      */

763     public void move(IProjectDescription description, int updateFlags, IProgressMonitor monitor) throws CoreException {
764         Assert.isNotNull(description);
765         monitor = Policy.monitorFor(monitor);
766         try {
767             String JavaDoc message = NLS.bind(Messages.resources_moving, getFullPath());
768             monitor.beginTask(message, Policy.totalWork);
769             IProject destination = workspace.getRoot().getProject(description.getName());
770             final ISchedulingRule rule = workspace.getRuleFactory().moveRule(this, destination);
771             try {
772                 workspace.prepareOperation(rule, monitor);
773                 // The following assert method throws CoreExceptions as stated in the IResource.move API
774
// and assert for programming errors. See checkMoveRequirements for more information.
775
if (!getName().equals(description.getName())) {
776                     IPath destPath = Path.ROOT.append(description.getName());
777                     assertMoveRequirements(destPath, IResource.PROJECT, updateFlags);
778                 }
779                 checkDescription(destination, description, true);
780                 workspace.beginOperation(true);
781                 message = Messages.resources_moveProblem;
782                 MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, null);
783                 WorkManager workManager = workspace.getWorkManager();
784                 ResourceTree tree = new ResourceTree(getLocalManager(), workManager.getLock(), status, updateFlags);
785                 IMoveDeleteHook hook = workspace.getMoveDeleteHook();
786                 workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_MOVE, this, destination, updateFlags));
787                 int depth = 0;
788                 try {
789                     depth = workManager.beginUnprotected();
790                     if (!hook.moveProject(tree, this, description, updateFlags, Policy.subMonitorFor(monitor, Policy.opWork / 2)))
791                         tree.standardMoveProject(this, description, updateFlags, Policy.subMonitorFor(monitor, Policy.opWork / 2));
792                 } finally {
793                     workManager.endUnprotected(depth);
794                 }
795                 // Invalidate the tree for further use by clients.
796
tree.makeInvalid();
797                 if (!tree.getStatus().isOK())
798                     throw new ResourceException(tree.getStatus());
799             } catch (OperationCanceledException e) {
800                 workspace.getWorkManager().operationCanceled();
801                 throw e;
802             } finally {
803                 workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.endOpWork));
804             }
805         } finally {
806             monitor.done();
807         }
808     }
809
810     /* (non-Javadoc)
811      * @see IProject#open(IProgressMonitor)
812      */

813     public void open(int updateFlags, IProgressMonitor monitor) throws CoreException {
814         monitor = Policy.monitorFor(monitor);
815         try {
816             String JavaDoc msg = NLS.bind(Messages.resources_opening_1, getName());
817             monitor.beginTask(msg, Policy.totalWork);
818             monitor.subTask(msg);
819             final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(this);
820             try {
821                 workspace.prepareOperation(rule, monitor);
822                 ProjectInfo info = (ProjectInfo) getResourceInfo(false, false);
823                 int flags = getFlags(info);
824                 checkExists(flags, true);
825                 if (isOpen(flags))
826                     return;
827
828                 workspace.beginOperation(true);
829                 // flush the build order early in case there is a problem
830
workspace.flushBuildOrder();
831                 info = (ProjectInfo) getResourceInfo(false, true);
832                 info.set(M_OPEN);
833                 //clear the unknown children immediately to avoid background refresh
834
boolean unknownChildren = info.isSet(M_CHILDREN_UNKNOWN);
835                 if (unknownChildren)
836                     info.clear(M_CHILDREN_UNKNOWN);
837                 // the M_USED flag is used to indicate the difference between opening a project
838
// for the first time and opening it from a previous close (restoring it from disk)
839
boolean used = info.isSet(M_USED);
840                 if (used) {
841                     workspace.getSaveManager().restore(this, Policy.subMonitorFor(monitor, Policy.opWork * 20 / 100));
842                 } else {
843                     info.set(M_USED);
844                     //reconcile any links in the project description
845
IStatus result = reconcileLinks(info.getDescription());
846                     if (!result.isOK())
847                         throw new CoreException(result);
848                     workspace.updateModificationStamp(info);
849                     monitor.worked(Policy.opWork * 20 / 100);
850                 }
851                 startup();
852                 //request a refresh if the project has unknown members on disk
853
if (!used && unknownChildren) {
854                     //refresh either in background or foreground
855
if ((updateFlags & IResource.BACKGROUND_REFRESH) != 0) {
856                         workspace.refreshManager.refresh(this);
857                         monitor.worked(Policy.opWork * 80 / 100);
858                     } else {
859                         refreshLocal(IResource.DEPTH_INFINITE, Policy.subMonitorFor(monitor, Policy.opWork * 80 / 100));
860                     }
861                 }
862                 //creation of this project may affect overlapping resources
863
workspace.getAliasManager().updateAliases(this, getStore(), IResource.DEPTH_INFINITE, monitor);
864             } catch (OperationCanceledException e) {
865                 workspace.getWorkManager().operationCanceled();
866                 throw e;
867             } finally {
868                 workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.endOpWork));
869             }
870         } finally {
871             monitor.done();
872         }
873     }
874
875     /* (non-Javadoc)
876      * @see IProject#open(IProgressMonitor)
877      */

878     public void open(IProgressMonitor monitor) throws CoreException {
879         open(IResource.NONE, monitor);
880     }
881
882     /**
883      * The project description file has changed on disk, resulting in a changed
884      * set of linked resources. Perform the necessary creations and deletions of
885      * links to bring the links in sync with those described in the project description.
886      * @param newDescription the new project description that may have
887      * changed link descriptions.
888      * @return status ok if everything went well, otherwise an ERROR multi-status
889      * describing the problems encountered.
890      */

891     public IStatus reconcileLinks(ProjectDescription newDescription) {
892         HashMap newLinks = newDescription.getLinks();
893         String JavaDoc msg = Messages.links_errorLinkReconcile;
894         MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.OPERATION_FAILED, msg, null);
895         //walk over old linked resources and remove those that are no longer defined
896
ProjectDescription oldDescription = internalGetDescription();
897         if (oldDescription != null) {
898             HashMap oldLinks = oldDescription.getLinks();
899             if (oldLinks != null) {
900                 for (Iterator it = oldLinks.values().iterator(); it.hasNext();) {
901                     LinkDescription oldLink = (LinkDescription) it.next();
902                     Resource oldLinkResource = (Resource) findMember(oldLink.getProjectRelativePath());
903                     if (oldLinkResource == null || !oldLinkResource.isLinked())
904                         continue;
905                     LinkDescription newLink = null;
906                     if (newLinks != null)
907                         newLink = (LinkDescription) newLinks.get(oldLink.getProjectRelativePath());
908                     //if the new link is missing, or has different location or gender, then remove old link
909
if (newLink == null || !newLink.getLocationURI().equals(oldLinkResource.getLocationURI()) || newLink.getType() != oldLinkResource.getType()) {
910                         try {
911                             oldLinkResource.delete(IResource.NONE, null);
912                             //refresh the resource, because removing a link can reveal a previously hidden resource in parent
913
oldLinkResource.refreshLocal(IResource.DEPTH_INFINITE, null);
914                         } catch (CoreException e) {
915                             status.merge(e.getStatus());
916                         }
917                     }
918                 }
919             }
920         }
921         //walk over new links and create if necessary
922
if (newLinks == null)
923             return status;
924         //sort links to avoid creating nested links before their parents
925
List sortedLinks = new ArrayList(newLinks.values());
926         Collections.sort(sortedLinks);
927         for (Iterator it = sortedLinks.iterator(); it.hasNext();) {
928             LinkDescription newLink = (LinkDescription) it.next();
929             try {
930                 Resource toLink = workspace.newResource(getFullPath().append(newLink.getProjectRelativePath()), newLink.getType());
931                 IContainer parent = toLink.getParent();
932                 if (parent != null && !parent.exists() && parent.getType() == FOLDER)
933                     ((Folder) parent).ensureExists(Policy.monitorFor(null));
934                 toLink.createLink(newLink.getLocationURI(), IResource.REPLACE | IResource.ALLOW_MISSING_LOCAL, null);
935             } catch (CoreException e) {
936                 status.merge(e.getStatus());
937             }
938         }
939         return status;
940     }
941
942     /* (non-Javadoc)
943      * @see IProject#setDescription(IProjectDescription, int, IProgressMonitor)
944      */

945     public void setDescription(IProjectDescription description, int updateFlags, IProgressMonitor monitor) throws CoreException {
946         // FIXME - update flags should be honored:
947
// KEEP_HISTORY means capture .project file in local history
948
// FORCE means overwrite any existing .project file
949
monitor = Policy.monitorFor(monitor);
950         try {
951             monitor.beginTask(Messages.resources_setDesc, Policy.totalWork);
952             final ISchedulingRule rule = workspace.getRoot();
953             try {
954                 //need to use root rule because nature configuration calls third party code
955
workspace.prepareOperation(rule, monitor);
956                 ResourceInfo info = getResourceInfo(false, false);
957                 checkAccessible(getFlags(info));
958                 //if nothing has changed, we don't need to do anything
959
ProjectDescription oldDescription = internalGetDescription();
960                 ProjectDescription newDescription = (ProjectDescription) description;
961                 boolean hasPublicChanges = oldDescription.hasPublicChanges(newDescription);
962                 boolean hasPrivateChanges = oldDescription.hasPrivateChanges(newDescription);
963                 if (!hasPublicChanges && !hasPrivateChanges)
964                     return;
965                 checkDescription(this, newDescription, false);
966                 //If we're out of sync and !FORCE, then fail.
967
//If the file is missing, we want to write the new description then throw an exception.
968
boolean hadSavedDescription = true;
969                 if (((updateFlags & IResource.FORCE) == 0)) {
970                     hadSavedDescription = getLocalManager().hasSavedDescription(this);
971                     if (hadSavedDescription && !getLocalManager().isDescriptionSynchronized(this)) {
972                         String JavaDoc message = NLS.bind(Messages.resources_projectDescSync, getName());
973                         throw new ResourceException(IResourceStatus.OUT_OF_SYNC_LOCAL, getFullPath(), message, null);
974                     }
975                 }
976                 //see if we have an old .prj file
977
if (!hadSavedDescription)
978                     hadSavedDescription = workspace.getMetaArea().hasSavedProject(this);
979                 workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_CHANGE, this));
980                 workspace.beginOperation(true);
981                 MultiStatus status = basicSetDescription(newDescription, updateFlags);
982                 if (hadSavedDescription && !status.isOK())
983                     throw new CoreException(status);
984                 //write the new description to the .project file
985
writeDescription(oldDescription, updateFlags, hasPublicChanges, hasPrivateChanges);
986                 //increment the content id even for private changes
987
info = getResourceInfo(false, true);
988                 info.incrementContentId();
989                 workspace.updateModificationStamp(info);
990                 if (!hadSavedDescription) {
991                     String JavaDoc msg = NLS.bind(Messages.resources_missingProjectMetaRepaired, getName());
992                     status.merge(new ResourceStatus(IResourceStatus.MISSING_DESCRIPTION_REPAIRED, getFullPath(), msg));
993                 }
994                 if (!status.isOK())
995                     throw new CoreException(status);
996             } finally {
997                 workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.endOpWork));
998             }
999         } finally {
1000            monitor.done();
1001        }
1002    }
1003
1004    /* (non-Javadoc)
1005     * @see IProject#setDescription(IProjectDescription, IProgressMonitor)
1006     */

1007    public void setDescription(IProjectDescription description, IProgressMonitor monitor) throws CoreException {
1008        // funnel all operations to central method
1009
setDescription(description, IResource.KEEP_HISTORY, monitor);
1010    }
1011
1012    /**
1013     * Restore the non-persisted state for the project. For example, read and set
1014     * the description from the local meta area. Also, open the property store etc.
1015     * This method is used when an open project is restored and so emulates
1016     * the behaviour of open().
1017     */

1018    protected void startup() throws CoreException {
1019        if (!isOpen())
1020            return;
1021        workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_OPEN, this));
1022    }
1023
1024    /* (non-Javadoc)
1025     * @see IResource#touch(IProgressMonitor)
1026     */

1027    public void touch(IProgressMonitor monitor) throws CoreException {
1028        monitor = Policy.monitorFor(monitor);
1029        try {
1030            String JavaDoc message = NLS.bind(Messages.resources_touch, getFullPath());
1031            monitor.beginTask(message, Policy.totalWork);
1032            final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(this);
1033            try {
1034                workspace.prepareOperation(rule, monitor);
1035                workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_CHANGE, this));
1036                workspace.beginOperation(true);
1037                super.touch(Policy.subMonitorFor(monitor, Policy.opWork));
1038            } catch (OperationCanceledException e) {
1039                workspace.getWorkManager().operationCanceled();
1040                throw e;
1041            } finally {
1042                workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.endOpWork));
1043            }
1044        } finally {
1045            monitor.done();
1046        }
1047    }
1048
1049    /**
1050     * The project description file on disk is better than the description in memory.
1051     * Make sure the project description in memory is synchronized with the
1052     * description file contents.
1053     */

1054    protected void updateDescription() throws CoreException {
1055        if (ProjectDescription.isWriting)
1056            return;
1057        ProjectDescription.isReading = true;
1058        try {
1059            workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_CHANGE, this));
1060            ProjectDescription description = getLocalManager().read(this, false);
1061            //links can only be created if the project is open
1062
IStatus result = null;
1063            if (isOpen())
1064                result = reconcileLinks(description);
1065            internalSetDescription(description, true);
1066            if (result != null && !result.isOK())
1067                throw new CoreException(result);
1068        } finally {
1069            ProjectDescription.isReading = false;
1070        }
1071    }
1072
1073    /**
1074     * Writes the project's current description file to disk.
1075     */

1076    public void writeDescription(int updateFlags) throws CoreException {
1077        writeDescription(internalGetDescription(), updateFlags, true, true);
1078    }
1079
1080    /**
1081     * Writes the project description file to disk. This is the only method
1082     * that should ever be writing the description, because it ensures that
1083     * the description isn't then immediately discovered as an incoming
1084     * change and read back from disk.
1085     * @param description The description to write
1086     * @param updateFlags The write operation update flags
1087     * @param hasPublicChanges Whether the public sections of the description have changed
1088     * @param hasPrivateChanges Whether the private sections of the description have changed
1089     * @exception CoreException On failure to write the description
1090     */

1091    public void writeDescription(IProjectDescription description, int updateFlags, boolean hasPublicChanges, boolean hasPrivateChanges) throws CoreException {
1092        if (ProjectDescription.isReading)
1093            return;
1094        ProjectDescription.isWriting = true;
1095        try {
1096            getLocalManager().internalWrite(this, description, updateFlags, hasPublicChanges, hasPrivateChanges);
1097        } finally {
1098            ProjectDescription.isWriting = false;
1099        }
1100    }
1101}
1102
Popular Tags