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;
48 IClasspathEntry[] newRawPath;
50 boolean canChangeResources;
52 boolean classpathWasSaved;
54 boolean needCycleCheck;
56 boolean needValidation;
60 IPath newOutputLocation;
64 boolean identicalRoots;
66 public static final IClasspathEntry[] ReuseClasspath = new IClasspathEntry[0];
68 public static final IClasspathEntry[] UpdateClasspath = new IClasspathEntry[0];
70 // if reusing output location, then also reuse clean flag
71 public static final IPath ReuseOutputLocation = new Path(
72 "Reuse Existing Output Location"); //$NON-NLS-1$
75 * When executed, this operation sets the classpath of the given project.
77 public SetClasspathOperation(JavaProject project,
78 IClasspathEntry[] oldResolvedPath, IClasspathEntry[] newRawPath,
79 IPath newOutputLocation, boolean canChangeResource,
80 boolean needValidation, boolean needSave) {
82 super(new IJavaElement[] { project });
83 this.oldResolvedPath = oldResolvedPath;
84 this.newRawPath = newRawPath;
85 this.newOutputLocation = newOutputLocation;
86 this.canChangeResources = canChangeResource;
87 this.needValidation = needValidation;
88 this.needSave = needSave;
89 this.project = project;
93 * Adds deltas for the given roots, with the specified change flag, and
94 * closes the root. Helper method for #setClasspath
96 protected void addClasspathDeltas(IPackageFragmentRoot[] roots, int flag,
97 JavaElementDelta delta) {
99 for (int i = 0; i < roots.length; i++) {
100 IPackageFragmentRoot root = roots[i];
101 delta.changed(root, flag);
102 if ((flag & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0
103 || (flag & IJavaElementDelta.F_SOURCEATTACHED) != 0
104 || (flag & IJavaElementDelta.F_SOURCEDETACHED) != 0) {
107 } catch (JavaModelException e) {
109 // force detach source on jar package fragment roots (source
110 // will be lazily computed when needed)
111 ((PackageFragmentRoot) root).setSourceAttachmentProperty(null);// loose
122 * Returns the index of the item in the list if the given list contains the
123 * specified entry. If the list does not contain the entry, -1 is returned.
124 * A helper method for #setClasspath
126 protected int classpathContains(IClasspathEntry[] list,
127 IClasspathEntry entry) {
129 IPath[] exclusionPatterns = entry.getExclusionPatterns();
130 nextEntry: for (int i = 0; i < list.length; i++) {
131 IClasspathEntry other = list[i];
132 if (other.getContentKind() == entry.getContentKind()
133 && other.getEntryKind() == entry.getEntryKind()
134 && other.isExported() == entry.isExported()
135 && other.getPath().equals(entry.getPath())) {
136 // check custom outputs
137 IPath entryOutput = entry.getOutputLocation();
138 IPath otherOutput = other.getOutputLocation();
139 if (entryOutput == null) {
140 if (otherOutput != null)
143 if (!entryOutput.equals(otherOutput))
147 // check exclusion patterns
148 IPath[] otherExcludes = other.getExclusionPatterns();
149 if (exclusionPatterns != otherExcludes) {
150 int excludeLength = exclusionPatterns.length;
151 if (otherExcludes.length != excludeLength)
153 for (int j = 0; j < excludeLength; j++) {
154 // compare toStrings instead of IPaths
155 // since IPath.equals is specified to ignore trailing
157 if (!exclusionPatterns[j].toString().equals(
158 otherExcludes[j].toString()))
169 * Recursively adds all subfolders of <code>folder</code> to the given
172 protected void collectAllSubfolders(IFolder folder, ArrayList collection)
173 throws JavaModelException {
175 IResource[] members = folder.members();
176 for (int i = 0, max = members.length; i < max; i++) {
177 IResource r = members[i];
178 if (r.getType() == IResource.FOLDER) {
180 collectAllSubfolders((IFolder) r, collection);
183 } catch (CoreException e) {
184 throw new JavaModelException(e);
189 * Returns a collection of package fragments that have been added/removed as
190 * the result of changing the output location to/from the given location.
191 * The collection is empty if no package fragments are affected.
193 // protected ArrayList determineAffectedPackageFragments(IPath location)
194 // throws JavaModelException {
195 // ArrayList fragments = new ArrayList();
196 // JavaProject project =getProject();
198 // // see if this will cause any package fragments to be affected
199 // IWorkspace workspace = ResourcesPlugin.getWorkspace();
200 // IResource resource = null;
201 // if (location != null) {
202 // resource = workspace.getRoot().findMember(location);
204 // if (resource != null && resource.getType() == IResource.FOLDER) {
205 // IFolder folder = (IFolder) resource;
206 // // only changes if it actually existed
207 // IClasspathEntry[] classpath = project.getExpandedClasspath(true);
208 // for (int i = 0; i < classpath.length; i++) {
209 // IClasspathEntry entry = classpath[i];
210 // IPath path = classpath[i].getPath();
211 // if (entry.getEntryKind() != IClasspathEntry.CPE_PROJECT &&
212 // path.isPrefixOf(location) && !path.equals(location)) {
213 // IPackageFragmentRoot[] roots =
214 // project.computePackageFragmentRoots(classpath[i]);
215 // IPackageFragmentRoot root = roots[0];
216 // // now the output location becomes a package fragment - along with any
218 // ArrayList folders = new ArrayList();
219 // folders.add(folder);
220 // collectAllSubfolders(folder, folders);
221 // Iterator elements = folders.iterator();
222 // int segments = path.segmentCount();
223 // while (elements.hasNext()) {
224 // IFolder f = (IFolder) elements.next();
225 // IPath relativePath = f.getFullPath().removeFirstSegments(segments);
226 // String name = relativePath.toOSString();
227 // name = name.replace(File.pathSeparatorChar, '.');
228 // if (name.endsWith(".")) { //$NON-NLS-1$
229 // name = name.substring(0, name.length() - 1);
231 // IPackageFragment pkg = root.getPackageFragment(name);
232 // fragments.add(pkg);
240 * Sets the classpath of the pre-specified project.
242 protected void executeOperation() throws JavaModelException {
243 // project reference updated - may throw an exception if unable to write
245 updateProjectReferencesIfNecessary();
247 // classpath file updated - may throw an exception if unable to write
249 saveClasspathIfNecessary();
251 // perform classpath and output location updates, if exception occurs in
253 // make sure the output location is updated before surfacing the
254 // exception (in case the output
255 // location update also throws an exception, give priority to the
256 // classpath update one).
257 JavaModelException originalException = null;
260 if (this.newRawPath == UpdateClasspath)
261 this.newRawPath = project.getRawClasspath();
262 if (this.newRawPath != ReuseClasspath) {
264 project.updatePackageFragmentRoots();
265 JavaModelManager.getJavaModelManager().getDeltaProcessor()
266 .addForRefresh(project);
269 } catch (JavaModelException e) {
270 originalException = e;
273 } finally { // if traversed by an exception we still need to update the
274 // output location when necessary
277 if (this.newOutputLocation != ReuseOutputLocation)
278 updateOutputLocation();
280 } catch (JavaModelException e) {
281 if (originalException != null)
282 throw originalException;
285 // ensures the project is getting rebuilt if only variable is
287 if (!this.identicalRoots && this.canChangeResources) {
289 this.project.getProject().touch(this.progressMonitor);
290 } catch (CoreException e) {
291 if (JavaModelManager.CP_RESOLVE_VERBOSE) {
294 "CPContainer INIT - FAILED to touch project: " + this.project.getElementName(), System.err); //$NON-NLS-1$
305 * Generates the delta of removed/added/reordered roots. Use three deltas in
306 * case the same root is removed/added/reordered (for instance, if it is
307 * changed from K_SOURCE to K_BINARY or vice versa)
309 protected void generateClasspathChangeDeltas() {
311 JavaModelManager manager = JavaModelManager.getJavaModelManager();
312 boolean needToUpdateDependents = false;
313 JavaElementDelta delta = new JavaElementDelta(getJavaModel());
314 boolean hasDelta = false;
315 if (this.classpathWasSaved) {
316 delta.changed(this.project, IJavaElementDelta.F_CLASSPATH_CHANGED);
319 int oldLength = oldResolvedPath.length;
320 int newLength = newResolvedPath.length;
322 // final IndexManager indexManager = manager.getIndexManager();
324 IPackageFragmentRoot[] roots = null;
325 if (project.isOpen()) {
327 roots = project.getPackageFragmentRoots();
328 } catch (JavaModelException e) {
333 if ((allRemovedRoots = manager.getDeltaProcessor().removedRoots) != null) {
334 roots = (IPackageFragmentRoot[]) allRemovedRoots.get(project);
338 oldRoots = new HashMap();
339 for (int i = 0; i < roots.length; i++) {
340 IPackageFragmentRoot root = roots[i];
341 oldRoots.put(root.getPath(), root);
344 for (int i = 0; i < oldLength; i++) {
346 int index = classpathContains(newResolvedPath, oldResolvedPath[i]);
348 // do not notify remote project changes
349 if (oldResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT) {
350 needToUpdateDependents = true;
351 this.needCycleCheck = true;
355 IPackageFragmentRoot[] pkgFragmentRoots = null;
356 if (oldRoots != null) {
357 IPackageFragmentRoot oldRoot = (IPackageFragmentRoot) oldRoots
358 .get(oldResolvedPath[i].getPath());
359 if (oldRoot != null) { // use old root if any (could be
360 // none if entry wasn't bound)
361 pkgFragmentRoots = new IPackageFragmentRoot[] { oldRoot };
364 if (pkgFragmentRoots == null) {
366 ObjectVector accumulatedRoots = new ObjectVector();
367 HashSet rootIDs = new HashSet(5);
368 rootIDs.add(project.rootID());
369 project.computePackageFragmentRoots(oldResolvedPath[i],
370 accumulatedRoots, rootIDs, true, // inside
373 false, // don't check existency
374 false); // don't retrieve exported roots
375 pkgFragmentRoots = new IPackageFragmentRoot[accumulatedRoots
377 accumulatedRoots.copyInto(pkgFragmentRoots);
378 } catch (JavaModelException e) {
379 pkgFragmentRoots = new IPackageFragmentRoot[] {};
382 addClasspathDeltas(pkgFragmentRoots,
383 IJavaElementDelta.F_REMOVED_FROM_CLASSPATH, delta);
385 int changeKind = oldResolvedPath[i].getEntryKind();
386 needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE)
387 || oldResolvedPath[i].isExported();
389 // Remove the .java files from the index for a source folder
390 // For a lib folder or a .jar file, remove the corresponding
391 // index if not shared.
392 // if (indexManager != null) {
393 // IClasspathEntry oldEntry = oldResolvedPath[i];
394 // final IPath path = oldEntry.getPath();
395 // switch (changeKind) {
396 // case IClasspathEntry.CPE_SOURCE:
397 // final char[][] inclusionPatterns = null;
398 // //((ClasspathEntry)oldEntry).fullInclusionPatternChars();
399 // final char[][] exclusionPatterns =
400 // ((ClasspathEntry)oldEntry).fullExclusionPatternChars();
401 // postAction(new IPostAction() {
402 // public String getID() {
403 // return path.toString();
405 // public void run() /* throws JavaModelException */ {
406 // indexManager.removeSourceFolderFromIndex(project, path,
407 // inclusionPatterns, exclusionPatterns);
410 // REMOVEALL_APPEND);
412 // case IClasspathEntry.CPE_LIBRARY:
413 // final DeltaProcessingState deltaState = manager.deltaState;
414 // postAction(new IPostAction() {
415 // public String getID() {
416 // return path.toString();
418 // public void run() /* throws JavaModelException */ {
419 // if (deltaState.otherRoots.get(path) == null) { // if root was
421 // indexManager.discardJobs(path.toString());
422 // indexManager.removeIndex(path);
423 // // TODO (kent) we could just remove the in-memory index and
424 // have the indexing check for timestamps
428 // REMOVEALL_APPEND);
435 // do not notify remote project changes
436 if (oldResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT) {
437 this.needCycleCheck |= (oldResolvedPath[i].isExported() != newResolvedPath[index]
441 needToUpdateDependents |= (oldResolvedPath[i].isExported() != newResolvedPath[index]
443 if (index != i) { // reordering of the classpath
444 addClasspathDeltas(project
445 .computePackageFragmentRoots(oldResolvedPath[i]),
446 IJavaElementDelta.F_REORDER, delta);
447 int changeKind = oldResolvedPath[i].getEntryKind();
448 needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE);
453 // check source attachment
454 IPath newSourcePath = newResolvedPath[index]
455 .getSourceAttachmentPath();
456 int sourceAttachmentFlags = this.getSourceAttachmentDeltaFlag(
457 oldResolvedPath[i].getSourceAttachmentPath(),
459 IPath oldRootPath = oldResolvedPath[i]
460 .getSourceAttachmentRootPath();
461 IPath newRootPath = newResolvedPath[index]
462 .getSourceAttachmentRootPath();
463 int sourceAttachmentRootFlags = getSourceAttachmentDeltaFlag(
464 oldRootPath, newRootPath);
465 int flags = sourceAttachmentFlags | sourceAttachmentRootFlags;
467 addClasspathDeltas(project
468 .computePackageFragmentRoots(oldResolvedPath[i]),
472 if (oldRootPath == null && newRootPath == null) {
473 // if source path is specified and no root path, it
474 // needs to be recomputed dynamically
475 // force detach source on jar package fragment roots
476 // (source will be lazily computed when needed)
477 IPackageFragmentRoot[] computedRoots = project
478 .computePackageFragmentRoots(oldResolvedPath[i]);
479 for (int j = 0; j < computedRoots.length; j++) {
480 IPackageFragmentRoot root = computedRoots[j];
481 // force detach source on jar package fragment roots
482 // (source will be lazily computed when needed)
485 } catch (JavaModelException e) {
488 ((PackageFragmentRoot) root)
489 .setSourceAttachmentProperty(null);// loose
501 for (int i = 0; i < newLength; i++) {
503 int index = classpathContains(oldResolvedPath, newResolvedPath[i]);
505 // do not notify remote project changes
506 if (newResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT) {
507 needToUpdateDependents = true;
508 this.needCycleCheck = true;
511 addClasspathDeltas(project
512 .computePackageFragmentRoots(newResolvedPath[i]),
513 IJavaElementDelta.F_ADDED_TO_CLASSPATH, delta);
514 int changeKind = newResolvedPath[i].getEntryKind();
517 // if (indexManager != null) {
518 // switch (changeKind) {
519 // case IClasspathEntry.CPE_LIBRARY:
520 // boolean pathHasChanged = true;
521 // final IPath newPath = newResolvedPath[i].getPath();
522 // for (int j = 0; j < oldLength; j++) {
523 // IClasspathEntry oldEntry = oldResolvedPath[j];
524 // if (oldEntry.getPath().equals(newPath)) {
525 // pathHasChanged = false;
529 // if (pathHasChanged) {
530 // postAction(new IPostAction() {
531 // public String getID() {
532 // return newPath.toString();
534 // public void run() /* throws JavaModelException */ {
535 // indexManager.indexLibrary(newPath, project.getProject());
538 // REMOVEALL_APPEND);
541 // case IClasspathEntry.CPE_SOURCE:
542 // IClasspathEntry entry = newResolvedPath[i];
543 // final IPath path = entry.getPath();
544 // final char[][] inclusionPatterns = null;
545 // //((ClasspathEntry)entry).fullInclusionPatternChars();
546 // final char[][] exclusionPatterns =
547 // ((ClasspathEntry)entry).fullExclusionPatternChars();
548 // postAction(new IPostAction() {
549 // public String getID() {
550 // return path.toString();
552 // public void run() /* throws JavaModelException */ {
553 // indexManager.indexSourceFolder(project, path,
554 // inclusionPatterns, exclusionPatterns);
557 // APPEND); // append so that a removeSourceFolder action is not
563 needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE)
564 || newResolvedPath[i].isExported();
567 } // classpath reordering has already been generated in previous
572 this.addDelta(delta);
574 this.identicalRoots = true;
576 if (needToUpdateDependents) {
577 updateAffectedProjects(project.getProject().getFullPath());
581 protected void saveClasspathIfNecessary() throws JavaModelException {
583 if (!this.canChangeResources || !this.needSave)
586 IClasspathEntry[] classpathForSave;
587 if (this.newRawPath == ReuseClasspath
588 || this.newRawPath == UpdateClasspath) {
589 classpathForSave = project.getRawClasspath();
591 classpathForSave = this.newRawPath;
593 IPath outputLocationForSave;
594 if (this.newOutputLocation == ReuseOutputLocation) {
595 outputLocationForSave = project.getOutputLocation();
597 outputLocationForSave = this.newOutputLocation;
599 // if read-only .classpath, then the classpath setting will never been
600 // performed completely
601 if (project.saveClasspath(classpathForSave, outputLocationForSave)) {
602 this.classpathWasSaved = true;
603 this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
607 protected JavaProject getProject() {
608 return ((JavaProject) getElementsToProcess()[0]);
612 * Returns the source attachment flag for the delta between the 2 give
613 * source paths. Returns either F_SOURCEATTACHED, F_SOURCEDETACHED,
614 * F_SOURCEATTACHED | F_SOURCEDETACHED or 0 if there is no difference.
616 private int getSourceAttachmentDeltaFlag(IPath oldPath, IPath newPath,
618 if (oldPath == null) {
619 if (newPath != null) {
620 return IJavaElementDelta.F_SOURCEATTACHED;
622 if (sourcePath != null) {
623 // if source path is specified and no root path, it needs to
624 // be recomputed dynamically
625 return IJavaElementDelta.F_SOURCEATTACHED
626 | IJavaElementDelta.F_SOURCEDETACHED;
631 } else if (newPath == null) {
632 return IJavaElementDelta.F_SOURCEDETACHED;
633 } else if (!oldPath.equals(newPath)) {
634 return IJavaElementDelta.F_SOURCEATTACHED
635 | IJavaElementDelta.F_SOURCEDETACHED;
642 * Returns the source attachment flag for the delta between the 2 give
643 * source paths. Returns either F_SOURCEATTACHED, F_SOURCEDETACHED,
644 * F_SOURCEATTACHED | F_SOURCEDETACHED or 0 if there is no difference.
646 private int getSourceAttachmentDeltaFlag(IPath oldPath, IPath newPath) {
647 if (oldPath == null) {
648 if (newPath != null) {
649 return IJavaElementDelta.F_SOURCEATTACHED;
653 } else if (newPath == null) {
654 return IJavaElementDelta.F_SOURCEDETACHED;
655 } else if (!oldPath.equals(newPath)) {
656 return IJavaElementDelta.F_SOURCEATTACHED
657 | IJavaElementDelta.F_SOURCEDETACHED;
664 * Returns <code>true</code> if this operation performs no resource
665 * modifications, otherwise <code>false</code>. Subclasses must override.
667 public boolean isReadOnly() {
668 return !this.canChangeResources;
671 // protected void saveClasspathIfNecessary() throws JavaModelException {
673 // if (!this.canChangeResources || !this.needSave) return;
675 // IClasspathEntry[] classpathForSave;
676 // JavaProject project = getProject();
677 // if (this.newRawPath == ReuseClasspath || this.newRawPath ==
679 // classpathForSave = project.getRawClasspath();
681 // classpathForSave = this.newRawPath;
683 // IPath outputLocationForSave;
684 // if (this.newOutputLocation == ReuseOutputLocation){
685 // outputLocationForSave = project.getOutputLocation();
687 // outputLocationForSave = this.newOutputLocation;
689 // // if read-only .classpath, then the classpath setting will never been
690 // performed completely
691 // if (project.saveClasspath(classpathForSave, outputLocationForSave)) {
692 // this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
696 public String toString() {
697 StringBuffer buffer = new StringBuffer(20);
698 buffer.append("SetClasspathOperation\n"); //$NON-NLS-1$
699 buffer.append(" - classpath : "); //$NON-NLS-1$
700 if (this.newRawPath == ReuseClasspath) {
701 buffer.append("<Reuse Existing Classpath>"); //$NON-NLS-1$
703 buffer.append("{"); //$NON-NLS-1$
704 for (int i = 0; i < this.newRawPath.length; i++) {
706 buffer.append(","); //$NON-NLS-1$
707 IClasspathEntry element = this.newRawPath[i];
708 buffer.append(" ").append(element.toString()); //$NON-NLS-1$
711 buffer.append("\n - output location : "); //$NON-NLS-1$
712 if (this.newOutputLocation == ReuseOutputLocation) {
713 buffer.append("<Reuse Existing Output Location>"); //$NON-NLS-1$
715 buffer.append(this.newOutputLocation.toString()); //$NON-NLS-1$
717 return buffer.toString();
720 // private void updateClasspath() throws JavaModelException {
722 // JavaProject project = ((JavaProject) getElementsToProcess()[0]);
724 // beginTask(Util.bind("classpath.settingProgress",
725 // project.getElementName()), 2); //$NON-NLS-1$
727 // // SIDE-EFFECT: from thereon, the classpath got modified
728 // project.setRawClasspath0(this.newRawPath);
730 // // resolve new path (asking for marker creation if problems)
731 // if (this.newResolvedPath == null) {
732 // this.newResolvedPath = project.getResolvedClasspath(true,
733 // this.canChangeResources);
736 // // if (this.oldResolvedPath != null) {
737 // // generateClasspathChangeDeltas(
738 // // this.oldResolvedPath,
739 // // this.newResolvedPath,
742 // this.needCycleCheck = true;
743 // updateAffectedProjects(project.getProject().getFullPath());
746 // updateCycleMarkersIfNecessary(newResolvedPath);
748 private void updateClasspath() throws JavaModelException {
751 "classpath.settingProgress", project.getElementName()), 2); //$NON-NLS-1$
753 // SIDE-EFFECT: from thereon, the classpath got modified
754 project.getPerProjectInfo().updateClasspathInformation(this.newRawPath);
756 // resolve new path (asking for marker creation if problems)
757 if (this.newResolvedPath == null) {
758 this.newResolvedPath = project
759 .getResolvedClasspath(true, this.canChangeResources, false/*
761 * returnResolutionInProgress
765 if (this.oldResolvedPath != null) {
766 generateClasspathChangeDeltas();
768 this.needCycleCheck = true;
769 updateAffectedProjects(project.getProject().getFullPath());
772 updateCycleMarkersIfNecessary();
776 * Update projects which are affected by this classpath change: those which
777 * refers to the current project as source
779 protected void updateAffectedProjects(IPath prerequisiteProjectPath) {
782 IJavaModel model = JavaModelManager.getJavaModelManager()
784 IJavaProject originatingProject = getProject();
785 IJavaProject[] projects = model.getJavaProjects();
786 for (int i = 0, projectCount = projects.length; i < projectCount; i++) {
788 JavaProject project = (JavaProject) projects[i];
789 if (project.equals(originatingProject))
790 continue; // skip itself
792 // consider ALL dependents (even indirect ones), since they
794 // flush their respective namelookup caches (all pkg
797 IClasspathEntry[] classpath = project
798 .getExpandedClasspath(true);
799 for (int j = 0, entryCount = classpath.length; j < entryCount; j++) {
800 IClasspathEntry entry = classpath[j];
801 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT
802 && entry.getPath().equals(
803 prerequisiteProjectPath)) {
804 project.setRawClasspath(UpdateClasspath,
805 SetClasspathOperation.ReuseOutputLocation,
806 this.progressMonitor,
807 this.canChangeResources, project
808 .getResolvedClasspath(true), false, // updating
812 false); // updating only - no need to save
816 } catch (JavaModelException e) {
819 } catch (JavaModelException e) {
825 * Update cycle markers
827 protected void updateCycleMarkersIfNecessary() {
829 if (!this.needCycleCheck)
831 if (!this.canChangeResources)
834 if (!project.hasCycleMarker()
835 && !project.hasClasspathCycle(newResolvedPath)) {
839 postAction(new IPostAction() {
840 public String getID() {
841 return "updateCycleMarkers"; //$NON-NLS-1$
844 public void run() throws JavaModelException {
845 JavaProject.updateAllCycleMarkers();
847 }, REMOVEALL_APPEND);
851 // * Update cycle markers
853 // protected void updateCycleMarkersIfNecessary(IClasspathEntry[]
854 // newResolvedPath) {
856 // if (!this.needCycleCheck) return;
857 // if (!this.canChangeResources) return;
860 // JavaProject project = getProject();
861 // if (!project.hasCycleMarker() &&
862 // !project.hasClasspathCycle(project.getResolvedClasspath(true))){
867 // new IPostAction() {
868 // public String getID() {
869 // return "updateCycleMarkers"; //$NON-NLS-1$
871 // public void run() throws JavaModelException {
872 // JavaProject.updateAllCycleMarkers();
875 // REMOVEALL_APPEND);
876 // } catch(JavaModelException e){
881 * Sets the output location of the pre-specified project.
884 * This can cause changes in package fragments, in case either the old or
885 * new output location folder are considered as a package fragment.
887 protected void updateOutputLocation() throws JavaModelException {
889 JavaProject project = ((JavaProject) getElementsToProcess()[0]);
894 "classpath.settingOutputLocationProgress", project.getElementName()), 2); //$NON-NLS-1$
896 IPath oldLocation = project.getOutputLocation();
898 // see if this will cause any package fragments to be added
899 boolean deltaToFire = false;
900 JavaElementDelta delta = newJavaElementDelta();
901 // ArrayList added= determineAffectedPackageFragments(oldLocation);
902 // Iterator iter = added.iterator();
903 // while (iter.hasNext()){
904 // IPackageFragment frag= (IPackageFragment)iter.next();
905 // ((IPackageFragmentRoot)frag.getParent()).close();
906 // if (!ProjectPrefUtil.isExcluded(frag)) {
907 // delta.added(frag);
908 // deltaToFire = true;
912 // see if this will cause any package fragments to be removed
913 // ArrayList removed=
914 // determineAffectedPackageFragments(this.newOutputLocation);
915 // iter = removed.iterator();
916 // while (iter.hasNext()){
917 // IPackageFragment frag= (IPackageFragment)iter.next();
918 // ((IPackageFragmentRoot)frag.getParent()).close();
919 // if (!ProjectPrefUtil.isExcluded(frag)) {
920 // delta.removed(frag);
921 // deltaToFire = true;
925 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager
926 .getJavaModelManager().getPerProjectInfoCheckExistence(
927 project.getProject());
928 synchronized (perProjectInfo) {
929 perProjectInfo.outputLocation = this.newOutputLocation;
939 * Update projects references so that the build order is consistent with the
942 protected void updateProjectReferencesIfNecessary()
943 throws JavaModelException {
945 if (!this.canChangeResources)
947 if (this.newRawPath == ReuseClasspath
948 || this.newRawPath == UpdateClasspath)
951 JavaProject jproject = getProject();
952 String[] oldRequired = jproject
953 .projectPrerequisites(this.oldResolvedPath);
955 if (this.newResolvedPath == null) {
956 this.newResolvedPath = jproject
957 .getResolvedClasspath(this.newRawPath, null, true,
958 this.needValidation, null /* no reverse map */);
960 String[] newRequired = jproject
961 .projectPrerequisites(this.newResolvedPath);
964 IProject project = jproject.getProject();
965 IProjectDescription description = project.getDescription();
967 IProject[] projectReferences = description.getReferencedProjects();
969 HashSet oldReferences = new HashSet(projectReferences.length);
970 for (int i = 0; i < projectReferences.length; i++) {
971 String projectName = projectReferences[i].getName();
972 oldReferences.add(projectName);
974 HashSet newReferences = (HashSet) oldReferences.clone();
976 for (int i = 0; i < oldRequired.length; i++) {
977 String projectName = oldRequired[i];
978 newReferences.remove(projectName);
980 for (int i = 0; i < newRequired.length; i++) {
981 String projectName = newRequired[i];
982 newReferences.add(projectName);
986 int newSize = newReferences.size();
989 if (oldReferences.size() == newSize) {
990 iter = newReferences.iterator();
991 while (iter.hasNext()) {
992 if (!oldReferences.contains(iter.next())) {
999 String[] requiredProjectNames = new String[newSize];
1001 iter = newReferences.iterator();
1002 while (iter.hasNext()) {
1003 requiredProjectNames[index++] = (String) iter.next();
1005 Util.sort(requiredProjectNames); // ensure that if changed, the
1006 // order is consistent
1008 IProject[] requiredProjectArray = new IProject[newSize];
1009 IWorkspaceRoot wksRoot = project.getWorkspace().getRoot();
1010 for (int i = 0; i < newSize; i++) {
1011 requiredProjectArray[i] = wksRoot
1012 .getProject(requiredProjectNames[i]);
1015 description.setReferencedProjects(requiredProjectArray);
1016 project.setDescription(description, this.progressMonitor);
1018 } catch (CoreException e) {
1019 throw new JavaModelException(e);
1023 public IJavaModelStatus verify() {
1025 IJavaModelStatus status = super.verify();
1026 if (!status.isOK()) {
1030 if (needValidation) {
1031 IJavaProject project = (IJavaProject) getElementToProcess();
1032 // retrieve classpath
1033 IClasspathEntry[] entries = this.newRawPath;
1034 if (entries == ReuseClasspath) {
1036 entries = project.getRawClasspath();
1037 } catch (JavaModelException e) {
1038 return e.getJavaModelStatus();
1041 // retrieve output location
1042 IPath outputLocation = this.newOutputLocation;
1043 if (outputLocation == ReuseOutputLocation) {
1045 outputLocation = project.getOutputLocation();
1046 } catch (JavaModelException e) {
1047 return e.getJavaModelStatus();
1051 // perform validation
1052 // return JavaConventions.validateClasspath(
1058 return JavaModelStatus.VERIFIED_OK;