1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.Iterator;
19 import net.sourceforge.phpdt.core.IClasspathEntry;
20 import net.sourceforge.phpdt.core.IJavaElement;
21 import net.sourceforge.phpdt.core.IJavaElementDelta;
22 import net.sourceforge.phpdt.core.IJavaModel;
23 import net.sourceforge.phpdt.core.IJavaModelStatus;
24 import net.sourceforge.phpdt.core.IJavaProject;
25 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
26 import net.sourceforge.phpdt.core.JavaModelException;
27 import net.sourceforge.phpdt.internal.compiler.util.ObjectVector;
28 import net.sourceforge.phpdt.internal.core.util.Util;
30 import org.eclipse.core.resources.IFolder;
31 import org.eclipse.core.resources.IProject;
32 import org.eclipse.core.resources.IProjectDescription;
33 import org.eclipse.core.resources.IResource;
34 import org.eclipse.core.resources.IWorkspaceRoot;
35 import org.eclipse.core.runtime.CoreException;
36 import org.eclipse.core.runtime.IPath;
37 import org.eclipse.core.runtime.Path;
40 * This operation sets an <code>IJavaProject</code>'s classpath.
44 public class SetClasspathOperation extends JavaModelOperation {
46 IClasspathEntry[] oldResolvedPath, newResolvedPath;
47 IClasspathEntry[] newRawPath;
48 boolean canChangeResources;
49 boolean classpathWasSaved;
50 boolean needCycleCheck;
51 boolean needValidation;
53 IPath newOutputLocation;
55 boolean identicalRoots;
57 public static final IClasspathEntry[] ReuseClasspath = new IClasspathEntry[0];
58 public static final IClasspathEntry[] UpdateClasspath = new IClasspathEntry[0];
59 // if reusing output location, then also reuse clean flag
60 public static final IPath ReuseOutputLocation = new Path("Reuse Existing Output Location"); //$NON-NLS-1$
63 * When executed, this operation sets the classpath of the given project.
65 public SetClasspathOperation(
67 IClasspathEntry[] oldResolvedPath,
68 IClasspathEntry[] newRawPath,
69 IPath newOutputLocation,
70 boolean canChangeResource,
71 boolean needValidation,
74 super(new IJavaElement[] { project });
75 this.oldResolvedPath = oldResolvedPath;
76 this.newRawPath = newRawPath;
77 this.newOutputLocation = newOutputLocation;
78 this.canChangeResources = canChangeResource;
79 this.needValidation = needValidation;
80 this.needSave = needSave;
81 this.project = project;
85 * Adds deltas for the given roots, with the specified change flag,
86 * and closes the root. Helper method for #setClasspath
88 protected void addClasspathDeltas(
89 IPackageFragmentRoot[] roots,
91 JavaElementDelta delta) {
93 for (int i = 0; i < roots.length; i++) {
94 IPackageFragmentRoot root = roots[i];
95 delta.changed(root, flag);
96 if ((flag & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0
97 || (flag & IJavaElementDelta.F_SOURCEATTACHED) != 0
98 || (flag & IJavaElementDelta.F_SOURCEDETACHED) != 0){
101 } catch (JavaModelException e) {
103 // force detach source on jar package fragment roots (source will be lazily computed when needed)
104 ((PackageFragmentRoot) root).setSourceAttachmentProperty(null);// loose info - will be recomputed
112 * Returns the index of the item in the list if the given list contains the specified entry. If the list does
113 * not contain the entry, -1 is returned.
114 * A helper method for #setClasspath
116 protected int classpathContains(
117 IClasspathEntry[] list,
118 IClasspathEntry entry) {
120 IPath[] exclusionPatterns = entry.getExclusionPatterns();
121 nextEntry: for (int i = 0; i < list.length; i++) {
122 IClasspathEntry other = list[i];
123 if (other.getContentKind() == entry.getContentKind()
124 && other.getEntryKind() == entry.getEntryKind()
125 && other.isExported() == entry.isExported()
126 && other.getPath().equals(entry.getPath())) {
127 // check custom outputs
128 IPath entryOutput = entry.getOutputLocation();
129 IPath otherOutput = other.getOutputLocation();
130 if (entryOutput == null) {
131 if (otherOutput != null)
134 if (!entryOutput.equals(otherOutput))
138 // check exclusion patterns
139 IPath[] otherExcludes = other.getExclusionPatterns();
140 if (exclusionPatterns != otherExcludes) {
141 int excludeLength = exclusionPatterns.length;
142 if (otherExcludes.length != excludeLength)
144 for (int j = 0; j < excludeLength; j++) {
145 // compare toStrings instead of IPaths
146 // since IPath.equals is specified to ignore trailing separators
147 if (!exclusionPatterns[j].toString().equals(otherExcludes[j].toString()))
158 * Recursively adds all subfolders of <code>folder</code> to the given collection.
160 protected void collectAllSubfolders(IFolder folder, ArrayList collection) throws JavaModelException {
162 IResource[] members= folder.members();
163 for (int i = 0, max = members.length; i < max; i++) {
164 IResource r= members[i];
165 if (r.getType() == IResource.FOLDER) {
167 collectAllSubfolders((IFolder)r, collection);
170 } catch (CoreException e) {
171 throw new JavaModelException(e);
176 * Returns a collection of package fragments that have been added/removed
177 * as the result of changing the output location to/from the given
178 * location. The collection is empty if no package fragments are
181 // protected ArrayList determineAffectedPackageFragments(IPath location) throws JavaModelException {
182 // ArrayList fragments = new ArrayList();
183 // JavaProject project =getProject();
185 // // see if this will cause any package fragments to be affected
186 // IWorkspace workspace = ResourcesPlugin.getWorkspace();
187 // IResource resource = null;
188 // if (location != null) {
189 // resource = workspace.getRoot().findMember(location);
191 // if (resource != null && resource.getType() == IResource.FOLDER) {
192 // IFolder folder = (IFolder) resource;
193 // // only changes if it actually existed
194 // IClasspathEntry[] classpath = project.getExpandedClasspath(true);
195 // for (int i = 0; i < classpath.length; i++) {
196 // IClasspathEntry entry = classpath[i];
197 // IPath path = classpath[i].getPath();
198 // if (entry.getEntryKind() != IClasspathEntry.CPE_PROJECT && path.isPrefixOf(location) && !path.equals(location)) {
199 // IPackageFragmentRoot[] roots = project.computePackageFragmentRoots(classpath[i]);
200 // IPackageFragmentRoot root = roots[0];
201 // // now the output location becomes a package fragment - along with any subfolders
202 // ArrayList folders = new ArrayList();
203 // folders.add(folder);
204 // collectAllSubfolders(folder, folders);
205 // Iterator elements = folders.iterator();
206 // int segments = path.segmentCount();
207 // while (elements.hasNext()) {
208 // IFolder f = (IFolder) elements.next();
209 // IPath relativePath = f.getFullPath().removeFirstSegments(segments);
210 // String name = relativePath.toOSString();
211 // name = name.replace(File.pathSeparatorChar, '.');
212 // if (name.endsWith(".")) { //$NON-NLS-1$
213 // name = name.substring(0, name.length() - 1);
215 // IPackageFragment pkg = root.getPackageFragment(name);
216 // fragments.add(pkg);
224 * Sets the classpath of the pre-specified project.
226 protected void executeOperation() throws JavaModelException {
227 // project reference updated - may throw an exception if unable to write .project file
228 updateProjectReferencesIfNecessary();
230 // classpath file updated - may throw an exception if unable to write .classpath file
231 saveClasspathIfNecessary();
233 // perform classpath and output location updates, if exception occurs in classpath update,
234 // make sure the output location is updated before surfacing the exception (in case the output
235 // location update also throws an exception, give priority to the classpath update one).
236 JavaModelException originalException = null;
239 if (this.newRawPath == UpdateClasspath) this.newRawPath = project.getRawClasspath();
240 if (this.newRawPath != ReuseClasspath){
242 project.updatePackageFragmentRoots();
243 JavaModelManager.getJavaModelManager().getDeltaProcessor().addForRefresh(project);
246 } catch(JavaModelException e){
247 originalException = e;
250 } finally { // if traversed by an exception we still need to update the output location when necessary
253 if (this.newOutputLocation != ReuseOutputLocation) updateOutputLocation();
255 } catch(JavaModelException e){
256 if (originalException != null) throw originalException;
259 // ensures the project is getting rebuilt if only variable is modified
260 if (!this.identicalRoots && this.canChangeResources) {
262 this.project.getProject().touch(this.progressMonitor);
263 } catch (CoreException e) {
264 if (JavaModelManager.CP_RESOLVE_VERBOSE){
265 Util.verbose("CPContainer INIT - FAILED to touch project: "+ this.project.getElementName(), System.err); //$NON-NLS-1$
276 * Generates the delta of removed/added/reordered roots.
277 * Use three deltas in case the same root is removed/added/reordered (for
278 * instance, if it is changed from K_SOURCE to K_BINARY or vice versa)
280 protected void generateClasspathChangeDeltas() {
282 JavaModelManager manager = JavaModelManager.getJavaModelManager();
283 boolean needToUpdateDependents = false;
284 JavaElementDelta delta = new JavaElementDelta(getJavaModel());
285 boolean hasDelta = false;
286 if (this.classpathWasSaved) {
287 delta.changed(this.project, IJavaElementDelta.F_CLASSPATH_CHANGED);
290 int oldLength = oldResolvedPath.length;
291 int newLength = newResolvedPath.length;
293 // final IndexManager indexManager = manager.getIndexManager();
295 IPackageFragmentRoot[] roots = null;
296 if (project.isOpen()) {
298 roots = project.getPackageFragmentRoots();
299 } catch (JavaModelException e) {
303 Map allRemovedRoots ;
304 if ((allRemovedRoots = manager.getDeltaProcessor().removedRoots) != null) {
305 roots = (IPackageFragmentRoot[]) allRemovedRoots.get(project);
309 oldRoots = new HashMap();
310 for (int i = 0; i < roots.length; i++) {
311 IPackageFragmentRoot root = roots[i];
312 oldRoots.put(root.getPath(), root);
315 for (int i = 0; i < oldLength; i++) {
317 int index = classpathContains(newResolvedPath, oldResolvedPath[i]);
319 // do not notify remote project changes
320 if (oldResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){
321 needToUpdateDependents = true;
322 this.needCycleCheck = true;
326 IPackageFragmentRoot[] pkgFragmentRoots = null;
327 if (oldRoots != null) {
328 IPackageFragmentRoot oldRoot = (IPackageFragmentRoot) oldRoots.get(oldResolvedPath[i].getPath());
329 if (oldRoot != null) { // use old root if any (could be none if entry wasn't bound)
330 pkgFragmentRoots = new IPackageFragmentRoot[] { oldRoot };
333 if (pkgFragmentRoots == null) {
335 ObjectVector accumulatedRoots = new ObjectVector();
336 HashSet rootIDs = new HashSet(5);
337 rootIDs.add(project.rootID());
338 project.computePackageFragmentRoots(
342 true, // inside original project
343 false, // don't check existency
344 false); // don't retrieve exported roots
345 pkgFragmentRoots = new IPackageFragmentRoot[accumulatedRoots.size()];
346 accumulatedRoots.copyInto(pkgFragmentRoots);
347 } catch (JavaModelException e) {
348 pkgFragmentRoots = new IPackageFragmentRoot[] {};
351 addClasspathDeltas(pkgFragmentRoots, IJavaElementDelta.F_REMOVED_FROM_CLASSPATH, delta);
353 int changeKind = oldResolvedPath[i].getEntryKind();
354 needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE) || oldResolvedPath[i].isExported();
356 // Remove the .java files from the index for a source folder
357 // For a lib folder or a .jar file, remove the corresponding index if not shared.
358 // if (indexManager != null) {
359 // IClasspathEntry oldEntry = oldResolvedPath[i];
360 // final IPath path = oldEntry.getPath();
361 // switch (changeKind) {
362 // case IClasspathEntry.CPE_SOURCE:
363 // final char[][] inclusionPatterns = null; //((ClasspathEntry)oldEntry).fullInclusionPatternChars();
364 // final char[][] exclusionPatterns = ((ClasspathEntry)oldEntry).fullExclusionPatternChars();
365 // postAction(new IPostAction() {
366 // public String getID() {
367 // return path.toString();
369 // public void run() /* throws JavaModelException */ {
370 // indexManager.removeSourceFolderFromIndex(project, path, inclusionPatterns, exclusionPatterns);
373 // REMOVEALL_APPEND);
375 // case IClasspathEntry.CPE_LIBRARY:
376 // final DeltaProcessingState deltaState = manager.deltaState;
377 // postAction(new IPostAction() {
378 // public String getID() {
379 // return path.toString();
381 // public void run() /* throws JavaModelException */ {
382 // if (deltaState.otherRoots.get(path) == null) { // if root was not shared
383 // indexManager.discardJobs(path.toString());
384 // indexManager.removeIndex(path);
385 // // TODO (kent) we could just remove the in-memory index and have the indexing check for timestamps
389 // REMOVEALL_APPEND);
396 // do not notify remote project changes
397 if (oldResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){
398 this.needCycleCheck |= (oldResolvedPath[i].isExported() != newResolvedPath[index].isExported());
401 needToUpdateDependents |= (oldResolvedPath[i].isExported() != newResolvedPath[index].isExported());
402 if (index != i) { //reordering of the classpath
404 project.computePackageFragmentRoots(oldResolvedPath[i]),
405 IJavaElementDelta.F_REORDER,
407 int changeKind = oldResolvedPath[i].getEntryKind();
408 needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE);
413 // check source attachment
414 IPath newSourcePath = newResolvedPath[index].getSourceAttachmentPath();
415 int sourceAttachmentFlags =
416 this.getSourceAttachmentDeltaFlag(
417 oldResolvedPath[i].getSourceAttachmentPath(),
419 IPath oldRootPath = oldResolvedPath[i].getSourceAttachmentRootPath();
420 IPath newRootPath = newResolvedPath[index].getSourceAttachmentRootPath();
421 int sourceAttachmentRootFlags = getSourceAttachmentDeltaFlag(oldRootPath, newRootPath);
422 int flags = sourceAttachmentFlags | sourceAttachmentRootFlags;
424 addClasspathDeltas(project.computePackageFragmentRoots(oldResolvedPath[i]), flags, delta);
427 if (oldRootPath == null && newRootPath == null) {
428 // if source path is specified and no root path, it needs to be recomputed dynamically
429 // force detach source on jar package fragment roots (source will be lazily computed when needed)
430 IPackageFragmentRoot[] computedRoots = project.computePackageFragmentRoots(oldResolvedPath[i]);
431 for (int j = 0; j < computedRoots.length; j++) {
432 IPackageFragmentRoot root = computedRoots[j];
433 // force detach source on jar package fragment roots (source will be lazily computed when needed)
436 } catch (JavaModelException e) {
439 ((PackageFragmentRoot) root).setSourceAttachmentProperty(null);// loose info - will be recomputed
446 for (int i = 0; i < newLength; i++) {
448 int index = classpathContains(oldResolvedPath, newResolvedPath[i]);
450 // do not notify remote project changes
451 if (newResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){
452 needToUpdateDependents = true;
453 this.needCycleCheck = true;
457 project.computePackageFragmentRoots(newResolvedPath[i]),
458 IJavaElementDelta.F_ADDED_TO_CLASSPATH,
460 int changeKind = newResolvedPath[i].getEntryKind();
463 // if (indexManager != null) {
464 // switch (changeKind) {
465 // case IClasspathEntry.CPE_LIBRARY:
466 // boolean pathHasChanged = true;
467 // final IPath newPath = newResolvedPath[i].getPath();
468 // for (int j = 0; j < oldLength; j++) {
469 // IClasspathEntry oldEntry = oldResolvedPath[j];
470 // if (oldEntry.getPath().equals(newPath)) {
471 // pathHasChanged = false;
475 // if (pathHasChanged) {
476 // postAction(new IPostAction() {
477 // public String getID() {
478 // return newPath.toString();
480 // public void run() /* throws JavaModelException */ {
481 // indexManager.indexLibrary(newPath, project.getProject());
484 // REMOVEALL_APPEND);
487 // case IClasspathEntry.CPE_SOURCE:
488 // IClasspathEntry entry = newResolvedPath[i];
489 // final IPath path = entry.getPath();
490 // final char[][] inclusionPatterns = null; //((ClasspathEntry)entry).fullInclusionPatternChars();
491 // final char[][] exclusionPatterns = ((ClasspathEntry)entry).fullExclusionPatternChars();
492 // postAction(new IPostAction() {
493 // public String getID() {
494 // return path.toString();
496 // public void run() /* throws JavaModelException */ {
497 // indexManager.indexSourceFolder(project, path, inclusionPatterns, exclusionPatterns);
500 // APPEND); // append so that a removeSourceFolder action is not removed
505 needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE) || newResolvedPath[i].isExported();
508 } // classpath reordering has already been generated in previous loop
512 this.addDelta(delta);
514 this.identicalRoots = true;
516 if (needToUpdateDependents){
517 updateAffectedProjects(project.getProject().getFullPath());
520 protected void saveClasspathIfNecessary() throws JavaModelException {
522 if (!this.canChangeResources || !this.needSave) return;
524 IClasspathEntry[] classpathForSave;
525 if (this.newRawPath == ReuseClasspath || this.newRawPath == UpdateClasspath){
526 classpathForSave = project.getRawClasspath();
528 classpathForSave = this.newRawPath;
530 IPath outputLocationForSave;
531 if (this.newOutputLocation == ReuseOutputLocation){
532 outputLocationForSave = project.getOutputLocation();
534 outputLocationForSave = this.newOutputLocation;
536 // if read-only .classpath, then the classpath setting will never been performed completely
537 if (project.saveClasspath(classpathForSave, outputLocationForSave)) {
538 this.classpathWasSaved = true;
539 this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
542 protected JavaProject getProject() {
543 return ((JavaProject) getElementsToProcess()[0]);
547 * Returns the source attachment flag for the delta between the 2 give source paths.
548 * Returns either F_SOURCEATTACHED, F_SOURCEDETACHED, F_SOURCEATTACHED | F_SOURCEDETACHED
549 * or 0 if there is no difference.
551 private int getSourceAttachmentDeltaFlag(IPath oldPath, IPath newPath, IPath sourcePath) {
552 if (oldPath == null) {
553 if (newPath != null) {
554 return IJavaElementDelta.F_SOURCEATTACHED;
556 if (sourcePath != null) {
557 // if source path is specified and no root path, it needs to be recomputed dynamically
558 return IJavaElementDelta.F_SOURCEATTACHED | IJavaElementDelta.F_SOURCEDETACHED;
563 } else if (newPath == null) {
564 return IJavaElementDelta.F_SOURCEDETACHED;
565 } else if (!oldPath.equals(newPath)) {
566 return IJavaElementDelta.F_SOURCEATTACHED | IJavaElementDelta.F_SOURCEDETACHED;
573 * Returns the source attachment flag for the delta between the 2 give source paths.
574 * Returns either F_SOURCEATTACHED, F_SOURCEDETACHED, F_SOURCEATTACHED | F_SOURCEDETACHED
575 * or 0 if there is no difference.
577 private int getSourceAttachmentDeltaFlag(IPath oldPath, IPath newPath) {
578 if (oldPath == null) {
579 if (newPath != null) {
580 return IJavaElementDelta.F_SOURCEATTACHED;
584 } else if (newPath == null) {
585 return IJavaElementDelta.F_SOURCEDETACHED;
586 } else if (!oldPath.equals(newPath)) {
587 return IJavaElementDelta.F_SOURCEATTACHED | IJavaElementDelta.F_SOURCEDETACHED;
594 * Returns <code>true</code> if this operation performs no resource modifications,
595 * otherwise <code>false</code>. Subclasses must override.
597 public boolean isReadOnly() {
598 return !this.canChangeResources;
601 // protected void saveClasspathIfNecessary() throws JavaModelException {
603 // if (!this.canChangeResources || !this.needSave) return;
605 // IClasspathEntry[] classpathForSave;
606 // JavaProject project = getProject();
607 // if (this.newRawPath == ReuseClasspath || this.newRawPath == UpdateClasspath){
608 // classpathForSave = project.getRawClasspath();
610 // classpathForSave = this.newRawPath;
612 // IPath outputLocationForSave;
613 // if (this.newOutputLocation == ReuseOutputLocation){
614 // outputLocationForSave = project.getOutputLocation();
616 // outputLocationForSave = this.newOutputLocation;
618 // // if read-only .classpath, then the classpath setting will never been performed completely
619 // if (project.saveClasspath(classpathForSave, outputLocationForSave)) {
620 // this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
624 public String toString(){
625 StringBuffer buffer = new StringBuffer(20);
626 buffer.append("SetClasspathOperation\n"); //$NON-NLS-1$
627 buffer.append(" - classpath : "); //$NON-NLS-1$
628 if (this.newRawPath == ReuseClasspath){
629 buffer.append("<Reuse Existing Classpath>"); //$NON-NLS-1$
631 buffer.append("{"); //$NON-NLS-1$
632 for (int i = 0; i < this.newRawPath.length; i++) {
633 if (i > 0) buffer.append(","); //$NON-NLS-1$
634 IClasspathEntry element = this.newRawPath[i];
635 buffer.append(" ").append(element.toString()); //$NON-NLS-1$
638 buffer.append("\n - output location : "); //$NON-NLS-1$
639 if (this.newOutputLocation == ReuseOutputLocation){
640 buffer.append("<Reuse Existing Output Location>"); //$NON-NLS-1$
642 buffer.append(this.newOutputLocation.toString()); //$NON-NLS-1$
644 return buffer.toString();
647 // private void updateClasspath() throws JavaModelException {
649 // JavaProject project = ((JavaProject) getElementsToProcess()[0]);
651 // beginTask(Util.bind("classpath.settingProgress", project.getElementName()), 2); //$NON-NLS-1$
653 // // SIDE-EFFECT: from thereon, the classpath got modified
654 // project.setRawClasspath0(this.newRawPath);
656 // // resolve new path (asking for marker creation if problems)
657 // if (this.newResolvedPath == null) {
658 // this.newResolvedPath = project.getResolvedClasspath(true, this.canChangeResources);
661 //// if (this.oldResolvedPath != null) {
662 //// generateClasspathChangeDeltas(
663 //// this.oldResolvedPath,
664 //// this.newResolvedPath,
667 // this.needCycleCheck = true;
668 // updateAffectedProjects(project.getProject().getFullPath());
671 // updateCycleMarkersIfNecessary(newResolvedPath);
673 private void updateClasspath() throws JavaModelException {
675 beginTask(Util.bind("classpath.settingProgress", project.getElementName()), 2); //$NON-NLS-1$
677 // SIDE-EFFECT: from thereon, the classpath got modified
678 project.getPerProjectInfo().updateClasspathInformation(this.newRawPath);
680 // resolve new path (asking for marker creation if problems)
681 if (this.newResolvedPath == null) {
682 this.newResolvedPath = project.getResolvedClasspath(true, this.canChangeResources, false/*don't returnResolutionInProgress*/);
685 if (this.oldResolvedPath != null) {
686 generateClasspathChangeDeltas();
688 this.needCycleCheck = true;
689 updateAffectedProjects(project.getProject().getFullPath());
692 updateCycleMarkersIfNecessary();
696 * Update projects which are affected by this classpath change:
697 * those which refers to the current project as source
699 protected void updateAffectedProjects(IPath prerequisiteProjectPath) {
702 IJavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
703 IJavaProject originatingProject = getProject();
704 IJavaProject[] projects = model.getJavaProjects();
705 for (int i = 0, projectCount = projects.length; i < projectCount; i++) {
707 JavaProject project = (JavaProject) projects[i];
708 if (project.equals(originatingProject)) continue; // skip itself
710 // consider ALL dependents (even indirect ones), since they may need to
711 // flush their respective namelookup caches (all pkg fragment roots).
713 IClasspathEntry[] classpath = project.getExpandedClasspath(true);
714 for (int j = 0, entryCount = classpath.length; j < entryCount; j++) {
715 IClasspathEntry entry = classpath[j];
716 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT
717 && entry.getPath().equals(prerequisiteProjectPath)) {
718 project.setRawClasspath(
720 SetClasspathOperation.ReuseOutputLocation,
721 this.progressMonitor,
722 this.canChangeResources,
723 project.getResolvedClasspath(true),
724 false, // updating only - no validation
725 false); // updating only - no need to save
729 } catch (JavaModelException e) {
732 } catch (JavaModelException e) {
738 * Update cycle markers
740 protected void updateCycleMarkersIfNecessary() {
742 if (!this.needCycleCheck) return;
743 if (!this.canChangeResources) return;
745 if (!project.hasCycleMarker() && !project.hasClasspathCycle(newResolvedPath)){
751 public String getID() {
752 return "updateCycleMarkers"; //$NON-NLS-1$
754 public void run() throws JavaModelException {
755 JavaProject.updateAllCycleMarkers();
761 // * Update cycle markers
763 // protected void updateCycleMarkersIfNecessary(IClasspathEntry[] newResolvedPath) {
765 // if (!this.needCycleCheck) return;
766 // if (!this.canChangeResources) return;
769 // JavaProject project = getProject();
770 // if (!project.hasCycleMarker() && !project.hasClasspathCycle(project.getResolvedClasspath(true))){
775 // new IPostAction() {
776 // public String getID() {
777 // return "updateCycleMarkers"; //$NON-NLS-1$
779 // public void run() throws JavaModelException {
780 // JavaProject.updateAllCycleMarkers();
783 // REMOVEALL_APPEND);
784 // } catch(JavaModelException e){
789 * Sets the output location of the pre-specified project.
791 * <p>This can cause changes in package fragments, in case either the
792 * old or new output location folder are considered as a package fragment.
794 protected void updateOutputLocation() throws JavaModelException {
796 JavaProject project= ((JavaProject) getElementsToProcess()[0]);
798 beginTask(Util.bind("classpath.settingOutputLocationProgress", project.getElementName()), 2); //$NON-NLS-1$
800 IPath oldLocation= project.getOutputLocation();
802 // see if this will cause any package fragments to be added
803 boolean deltaToFire= false;
804 JavaElementDelta delta = newJavaElementDelta();
805 // ArrayList added= determineAffectedPackageFragments(oldLocation);
806 // Iterator iter = added.iterator();
807 // while (iter.hasNext()){
808 // IPackageFragment frag= (IPackageFragment)iter.next();
809 // ((IPackageFragmentRoot)frag.getParent()).close();
810 // if (!ProjectPrefUtil.isExcluded(frag)) {
811 // delta.added(frag);
812 // deltaToFire = true;
816 // see if this will cause any package fragments to be removed
817 // ArrayList removed= determineAffectedPackageFragments(this.newOutputLocation);
818 // iter = removed.iterator();
819 // while (iter.hasNext()){
820 // IPackageFragment frag= (IPackageFragment)iter.next();
821 // ((IPackageFragmentRoot)frag.getParent()).close();
822 // if (!ProjectPrefUtil.isExcluded(frag)) {
823 // delta.removed(frag);
824 // deltaToFire = true;
828 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project.getProject());
829 synchronized (perProjectInfo) {
830 perProjectInfo.outputLocation = this.newOutputLocation;
840 * Update projects references so that the build order is consistent with the classpath
842 protected void updateProjectReferencesIfNecessary() throws JavaModelException {
844 if (!this.canChangeResources) return;
845 if (this.newRawPath == ReuseClasspath || this.newRawPath == UpdateClasspath) return;
847 JavaProject jproject = getProject();
848 String[] oldRequired = jproject.projectPrerequisites(this.oldResolvedPath);
850 if (this.newResolvedPath == null) {
851 this.newResolvedPath = jproject.getResolvedClasspath(this.newRawPath, null, true, this.needValidation, null /*no reverse map*/);
853 String[] newRequired = jproject.projectPrerequisites(this.newResolvedPath);
856 IProject project = jproject.getProject();
857 IProjectDescription description = project.getDescription();
859 IProject[] projectReferences = description.getReferencedProjects();
861 HashSet oldReferences = new HashSet(projectReferences.length);
862 for (int i = 0; i < projectReferences.length; i++){
863 String projectName = projectReferences[i].getName();
864 oldReferences.add(projectName);
866 HashSet newReferences = (HashSet)oldReferences.clone();
868 for (int i = 0; i < oldRequired.length; i++){
869 String projectName = oldRequired[i];
870 newReferences.remove(projectName);
872 for (int i = 0; i < newRequired.length; i++){
873 String projectName = newRequired[i];
874 newReferences.add(projectName);
878 int newSize = newReferences.size();
881 if (oldReferences.size() == newSize){
882 iter = newReferences.iterator();
883 while (iter.hasNext()){
884 if (!oldReferences.contains(iter.next())){
891 String[] requiredProjectNames = new String[newSize];
893 iter = newReferences.iterator();
894 while (iter.hasNext()){
895 requiredProjectNames[index++] = (String)iter.next();
897 Util.sort(requiredProjectNames); // ensure that if changed, the order is consistent
899 IProject[] requiredProjectArray = new IProject[newSize];
900 IWorkspaceRoot wksRoot = project.getWorkspace().getRoot();
901 for (int i = 0; i < newSize; i++){
902 requiredProjectArray[i] = wksRoot.getProject(requiredProjectNames[i]);
905 description.setReferencedProjects(requiredProjectArray);
906 project.setDescription(description, this.progressMonitor);
908 } catch(CoreException e){
909 throw new JavaModelException(e);
913 public IJavaModelStatus verify() {
915 IJavaModelStatus status = super.verify();
916 if (!status.isOK()) {
920 if (needValidation) {
921 IJavaProject project = (IJavaProject) getElementToProcess();
922 // retrieve classpath
923 IClasspathEntry[] entries = this.newRawPath;
924 if (entries == ReuseClasspath){
926 entries = project.getRawClasspath();
927 } catch (JavaModelException e) {
928 return e.getJavaModelStatus();
931 // retrieve output location
932 IPath outputLocation = this.newOutputLocation;
933 if (outputLocation == ReuseOutputLocation){
935 outputLocation = project.getOutputLocation();
936 } catch (JavaModelException e) {
937 return e.getJavaModelStatus();
941 // perform validation
942 // return JavaConventions.validateClasspath(
948 return JavaModelStatus.VERIFIED_OK;