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;
 
  14 import java.util.ArrayList;
 
  15 import java.util.HashMap;
 
  16 import java.util.HashSet;
 
  17 import java.util.Iterator;
 
  20 import net.sourceforge.phpdt.core.IClasspathEntry;
 
  21 import net.sourceforge.phpdt.core.IJavaElement;
 
  22 import net.sourceforge.phpdt.core.IJavaElementDelta;
 
  23 import net.sourceforge.phpdt.core.IJavaModel;
 
  24 import net.sourceforge.phpdt.core.IJavaModelStatus;
 
  25 import net.sourceforge.phpdt.core.IJavaProject;
 
  26 import net.sourceforge.phpdt.core.IPackageFragment;
 
  27 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
 
  28 import net.sourceforge.phpdt.core.JavaModelException;
 
  29 import net.sourceforge.phpdt.internal.compiler.util.ObjectVector;
 
  31 import org.eclipse.core.resources.IFolder;
 
  32 import org.eclipse.core.resources.IProject;
 
  33 import org.eclipse.core.resources.IProjectDescription;
 
  34 import org.eclipse.core.resources.IResource;
 
  35 import org.eclipse.core.resources.IWorkspace;
 
  36 import org.eclipse.core.resources.IWorkspaceRoot;
 
  37 import org.eclipse.core.resources.ResourcesPlugin;
 
  38 import org.eclipse.core.runtime.CoreException;
 
  39 import org.eclipse.core.runtime.IPath;
 
  40 import org.eclipse.core.runtime.Path;
 
  43  * This operation sets an <code>IJavaProject</code>'s classpath.
 
  47 public class SetClasspathOperation extends JavaModelOperation {
 
  49         IClasspathEntry[] oldResolvedPath, newResolvedPath;
 
  50         IClasspathEntry[] newRawPath;
 
  51         boolean canChangeResource;
 
  52         boolean needCycleCheck;
 
  53         boolean needValidation;
 
  55         IPath newOutputLocation;
 
  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.canChangeResource = canChangeResource;
 
  79                 this.needValidation = needValidation;
 
  80                 this.needSave = needSave;
 
  84          * Adds deltas for the given roots, with the specified change flag,
 
  85          * and closes the root. Helper method for #setClasspath
 
  87         protected void addClasspathDeltas(
 
  88                 IPackageFragmentRoot[] roots,
 
  90                 JavaElementDelta delta) {
 
  92                 for (int i = 0; i < roots.length; i++) {
 
  93                         IPackageFragmentRoot root = roots[i];
 
  94                         delta.changed(root, flag);
 
  95                         if ((flag & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0 
 
  96                                         || (flag & IJavaElementDelta.F_SOURCEATTACHED) != 0
 
  97                                         || (flag & IJavaElementDelta.F_SOURCEDETACHED) != 0){
 
 100                                 } catch (JavaModelException e) {
 
 102                                 // force detach source on jar package fragment roots (source will be lazily computed when needed)
 
 103                                 ((PackageFragmentRoot) root).setSourceAttachmentProperty(null);// loose info - will be recomputed
 
 111          * Returns the index of the item in the list if the given list contains the specified entry. If the list does
 
 112          * not contain the entry, -1 is returned.
 
 113          * A helper method for #setClasspath
 
 115         protected int classpathContains(
 
 116                 IClasspathEntry[] list,
 
 117                 IClasspathEntry entry) {
 
 119                 IPath[] exclusionPatterns = entry.getExclusionPatterns();
 
 120                 nextEntry: for (int i = 0; i < list.length; i++) {
 
 121                         IClasspathEntry other = list[i];
 
 122                         if (other.getContentKind() == entry.getContentKind()
 
 123                                 && other.getEntryKind() == entry.getEntryKind()
 
 124                                 && other.isExported() == entry.isExported()
 
 125                                 && other.getPath().equals(entry.getPath())) {
 
 126                                         // check custom outputs
 
 127                                         IPath entryOutput = entry.getOutputLocation();
 
 128                                         IPath otherOutput = other.getOutputLocation();
 
 129                                         if (entryOutput == null) {
 
 130                                                 if (otherOutput != null)
 
 133                                                 if (!entryOutput.equals(otherOutput))
 
 137                                         // check exclusion patterns
 
 138                                         IPath[] otherExcludes = other.getExclusionPatterns();
 
 139                                         if (exclusionPatterns != otherExcludes) {
 
 140                                                 int excludeLength = exclusionPatterns.length;
 
 141                                                 if (otherExcludes.length != excludeLength)
 
 143                                                 for (int j = 0; j < excludeLength; j++) {
 
 144                                                         // compare toStrings instead of IPaths 
 
 145                                                         // since IPath.equals is specified to ignore trailing separators
 
 146                                                         if (!exclusionPatterns[j].toString().equals(otherExcludes[j].toString()))
 
 157          * Recursively adds all subfolders of <code>folder</code> to the given collection.
 
 159         protected void collectAllSubfolders(IFolder folder, ArrayList collection) throws JavaModelException {
 
 161                         IResource[] members= folder.members();
 
 162                         for (int i = 0, max = members.length; i < max; i++) {
 
 163                                 IResource r= members[i];
 
 164                                 if (r.getType() == IResource.FOLDER) {
 
 166                                         collectAllSubfolders((IFolder)r, collection);
 
 169                 } catch (CoreException e) {
 
 170                         throw new JavaModelException(e);
 
 175          * Returns a collection of package fragments that have been added/removed
 
 176          * as the result of changing the output location to/from the given
 
 177          * location. The collection is empty if no package fragments are
 
 180 //      protected ArrayList determineAffectedPackageFragments(IPath location) throws JavaModelException {
 
 181 //              ArrayList fragments = new ArrayList();
 
 182 //              JavaProject project =getProject();
 
 184 //              // see if this will cause any package fragments to be affected
 
 185 //              IWorkspace workspace = ResourcesPlugin.getWorkspace();
 
 186 //              IResource resource = null;
 
 187 //              if (location != null) {
 
 188 //                      resource = workspace.getRoot().findMember(location);
 
 190 //              if (resource != null && resource.getType() == IResource.FOLDER) {
 
 191 //                      IFolder folder = (IFolder) resource;
 
 192 //                      // only changes if it actually existed
 
 193 //                      IClasspathEntry[] classpath = project.getExpandedClasspath(true);
 
 194 //                      for (int i = 0; i < classpath.length; i++) {
 
 195 //                              IClasspathEntry entry = classpath[i];
 
 196 //                              IPath path = classpath[i].getPath();
 
 197 //                              if (entry.getEntryKind() != IClasspathEntry.CPE_PROJECT && path.isPrefixOf(location) && !path.equals(location)) {
 
 198 //                                      IPackageFragmentRoot[] roots = project.computePackageFragmentRoots(classpath[i]);
 
 199 //                                      IPackageFragmentRoot root = roots[0];
 
 200 //                                      // now the output location becomes a package fragment - along with any subfolders
 
 201 //                                      ArrayList folders = new ArrayList();
 
 202 //                                      folders.add(folder);
 
 203 //                                      collectAllSubfolders(folder, folders);
 
 204 //                                      Iterator elements = folders.iterator();
 
 205 //                                      int segments = path.segmentCount();
 
 206 //                                      while (elements.hasNext()) {
 
 207 //                                              IFolder f = (IFolder) elements.next();
 
 208 //                                              IPath relativePath = f.getFullPath().removeFirstSegments(segments);
 
 209 //                                              String name = relativePath.toOSString();
 
 210 //                                              name = name.replace(File.pathSeparatorChar, '.');
 
 211 //                                              if (name.endsWith(".")) { //$NON-NLS-1$
 
 212 //                                                      name = name.substring(0, name.length() - 1);
 
 214 //                                              IPackageFragment pkg = root.getPackageFragment(name);
 
 215 //                                              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                         JavaProject project = getProject();
 
 240                         if (this.newRawPath == UpdateClasspath) this.newRawPath = project.getRawClasspath();
 
 241                         if (this.newRawPath != ReuseClasspath){
 
 243 //                              project.updatePackageFragmentRoots();
 
 244                                 JavaModelManager.getJavaModelManager().deltaProcessor.addForRefresh(project);
 
 247                 } catch(JavaModelException e){
 
 248                         originalException = e;
 
 251                 } finally { // if traversed by an exception we still need to update the output location when necessary
 
 254                                 if (this.newOutputLocation != ReuseOutputLocation) updateOutputLocation();
 
 256                         } catch(JavaModelException e){
 
 257                                 if (originalException != null) throw originalException; 
 
 265          * Generates the delta of removed/added/reordered roots.
 
 266          * Use three deltas in case the same root is removed/added/reordered (for
 
 267          * instance, if it is changed from K_SOURCE to K_BINARY or vice versa)
 
 269 //      protected void generateClasspathChangeDeltas(
 
 270 //              IClasspathEntry[] oldResolvedPath,
 
 271 //              IClasspathEntry[] newResolvedPath,
 
 272 //              final JavaProject project) {
 
 274 //              JavaModelManager manager = JavaModelManager.getJavaModelManager();
 
 275 //              boolean needToUpdateDependents = false;
 
 276 //              JavaElementDelta delta = new JavaElementDelta(getJavaModel());
 
 277 //              boolean hasDelta = false;
 
 278 //              int oldLength = oldResolvedPath.length;
 
 279 //              int newLength = newResolvedPath.length;
 
 281 //              final IndexManager indexManager = manager.getIndexManager();
 
 282 //              Map oldRoots = null;
 
 283 //              IPackageFragmentRoot[] roots = null;
 
 284 //              if (project.isOpen()) {
 
 286 //                              roots = project.getPackageFragmentRoots();
 
 287 //                      } catch (JavaModelException e) {
 
 290 //                      Map allRemovedRoots ;
 
 291 //                      if ((allRemovedRoots = manager.deltaProcessor.removedRoots) != null) {
 
 292 //                              roots = (IPackageFragmentRoot[]) allRemovedRoots.get(project);
 
 295 //              if (roots != null) {
 
 296 //                      oldRoots = new HashMap();
 
 297 //                      for (int i = 0; i < roots.length; i++) {
 
 298 //                              IPackageFragmentRoot root = roots[i];
 
 299 //                              oldRoots.put(root.getPath(), root);
 
 302 //              for (int i = 0; i < oldLength; i++) {
 
 304 //                      int index = classpathContains(newResolvedPath, oldResolvedPath[i]);
 
 305 //                      if (index == -1) {
 
 306 //                              // do not notify remote project changes
 
 307 //                              if (oldResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){
 
 308 //                                      needToUpdateDependents = true;
 
 309 //                                      this.needCycleCheck = true;
 
 313 //                              IPackageFragmentRoot[] pkgFragmentRoots = null;
 
 314 //                              if (oldRoots != null) {
 
 315 //                                      IPackageFragmentRoot oldRoot = (IPackageFragmentRoot)  oldRoots.get(oldResolvedPath[i].getPath());
 
 316 //                                      if (oldRoot != null) { // use old root if any (could be none if entry wasn't bound)
 
 317 //                                              pkgFragmentRoots = new IPackageFragmentRoot[] { oldRoot };
 
 320 //                              if (pkgFragmentRoots == null) {
 
 322 //                                              ObjectVector accumulatedRoots = new ObjectVector();
 
 323 //                                              HashSet rootIDs = new HashSet(5);
 
 324 //                                              rootIDs.add(project.rootID());
 
 325 //                                              project.computePackageFragmentRoots(
 
 326 //                                                      oldResolvedPath[i], 
 
 329 //                                                      true, // inside original project
 
 330 //                                                      false, // don't check existency
 
 331 //                                                      false); // don't retrieve exported roots
 
 332 //                                              pkgFragmentRoots = new IPackageFragmentRoot[accumulatedRoots.size()];
 
 333 //                                              accumulatedRoots.copyInto(pkgFragmentRoots);
 
 334 //                                      } catch (JavaModelException e) {
 
 335 //                                              pkgFragmentRoots =  new IPackageFragmentRoot[] {};
 
 338 //                              addClasspathDeltas(pkgFragmentRoots, IJavaElementDelta.F_REMOVED_FROM_CLASSPATH, delta);
 
 340 //                              int changeKind = oldResolvedPath[i].getEntryKind();
 
 341 //                              needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE) || oldResolvedPath[i].isExported();
 
 343 //                              // Remove the .java files from the index for a source folder
 
 344 //                              // For a lib folder or a .jar file, remove the corresponding index if not shared.
 
 345 //                              if (indexManager != null) {
 
 346 //                                      IClasspathEntry oldEntry = oldResolvedPath[i];
 
 347 //                                      final IPath path = oldEntry.getPath();
 
 348 //                                      switch (changeKind) {
 
 349 //                                              case IClasspathEntry.CPE_SOURCE:
 
 350 //                                                      final char[][] exclusionPatterns = ((ClasspathEntry)oldEntry).fullExclusionPatternChars();
 
 351 //                                                      postAction(new IPostAction() {
 
 352 //                                                              public String getID() {
 
 353 //                                                                      return path.toString();
 
 355 //                                                              public void run() throws JavaModelException {
 
 356 //                                                                      indexManager.removeSourceFolderFromIndex(project, path, exclusionPatterns);
 
 359 //                                                      REMOVEALL_APPEND);
 
 361 //                                              case IClasspathEntry.CPE_LIBRARY:
 
 362 //                                                      final DeltaProcessor deltaProcessor = manager.deltaProcessor;
 
 363 //                                                      postAction(new IPostAction() {
 
 364 //                                                              public String getID() {
 
 365 //                                                                      return path.toString();
 
 367 //                                                              public void run() throws JavaModelException {
 
 368 //                                                                      if (deltaProcessor.otherRoots.get(path) == null) { // if root was not shared
 
 369 //                                                                              indexManager.discardJobs(path.toString());
 
 370 //                                                                              indexManager.removeIndex(path);
 
 371 //                                                                              // TODO: we could just remove the in-memory index and have the indexing check for timestamps
 
 375 //                                                      REMOVEALL_APPEND);
 
 382 //                              // do not notify remote project changes
 
 383 //                              if (oldResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){
 
 384 //                                      this.needCycleCheck |= (oldResolvedPath[i].isExported() != newResolvedPath[index].isExported());
 
 387 //                              needToUpdateDependents |= (oldResolvedPath[i].isExported() != newResolvedPath[index].isExported());
 
 388 //                              if (index != i) { //reordering of the classpath
 
 389 //                                              addClasspathDeltas(
 
 390 //                                                      project.computePackageFragmentRoots(oldResolvedPath[i]),
 
 391 //                                                      IJavaElementDelta.F_REORDER,
 
 393 //                                              int changeKind = oldResolvedPath[i].getEntryKind();
 
 394 //                                              needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE);
 
 399 //                              // check source attachment
 
 400 //                              IPath newSourcePath = newResolvedPath[index].getSourceAttachmentPath();
 
 401 //                              int sourceAttachmentFlags = 
 
 402 //                                      this.getSourceAttachmentDeltaFlag(
 
 403 //                                              oldResolvedPath[i].getSourceAttachmentPath(),
 
 405 //                                              null/*not a source root path*/);
 
 406 //                              int sourceAttachmentRootFlags = 
 
 407 //                                      this.getSourceAttachmentDeltaFlag(
 
 408 //                                              oldResolvedPath[i].getSourceAttachmentRootPath(),
 
 409 //                                              newResolvedPath[index].getSourceAttachmentRootPath(),
 
 410 //                                              newSourcePath/*in case both root paths are null*/);
 
 411 //                              int flags = sourceAttachmentFlags | sourceAttachmentRootFlags;
 
 413 //                                      addClasspathDeltas(
 
 414 //                                              project.computePackageFragmentRoots(oldResolvedPath[i]),
 
 422 //              for (int i = 0; i < newLength; i++) {
 
 424 //                      int index = classpathContains(oldResolvedPath, newResolvedPath[i]);
 
 425 //                      if (index == -1) {
 
 426 //                              // do not notify remote project changes
 
 427 //                              if (newResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){
 
 428 //                                      needToUpdateDependents = true;
 
 429 //                                      this.needCycleCheck = true;
 
 432 //                              addClasspathDeltas(
 
 433 //                                      project.computePackageFragmentRoots(newResolvedPath[i]),
 
 434 //                                      IJavaElementDelta.F_ADDED_TO_CLASSPATH,
 
 436 //                              int changeKind = newResolvedPath[i].getEntryKind();
 
 438 //                              // Request indexing
 
 439 //                              if (indexManager != null) {
 
 440 //                                      switch (changeKind) {
 
 441 //                                              case IClasspathEntry.CPE_LIBRARY:
 
 442 //                                                      boolean pathHasChanged = true;
 
 443 //                                                      final IPath newPath = newResolvedPath[i].getPath();
 
 444 //                                                      for (int j = 0; j < oldLength; j++) {
 
 445 //                                                              IClasspathEntry oldEntry = oldResolvedPath[j];
 
 446 //                                                              if (oldEntry.getPath().equals(newPath)) {
 
 447 //                                                                      pathHasChanged = false;
 
 451 //                                                      if (pathHasChanged) {
 
 452 //                                                              postAction(new IPostAction() {
 
 453 //                                                                      public String getID() {
 
 454 //                                                                              return newPath.toString();
 
 456 //                                                                      public void run() throws JavaModelException {
 
 457 //                                                                              indexManager.indexLibrary(newPath, project.getProject());
 
 460 //                                                              REMOVEALL_APPEND);
 
 463 //                                              case IClasspathEntry.CPE_SOURCE:
 
 464 //                                                      IClasspathEntry entry = newResolvedPath[i];
 
 465 //                                                      final IPath path = entry.getPath();
 
 466 //                                                      final char[][] exclusionPatterns = ((ClasspathEntry)entry).fullExclusionPatternChars();
 
 467 //                                                      postAction(new IPostAction() {
 
 468 //                                                              public String getID() {
 
 469 //                                                                      return path.toString();
 
 471 //                                                              public void run() throws JavaModelException {
 
 472 //                                                                      indexManager.indexSourceFolder(project, path, exclusionPatterns);
 
 475 //                                                      APPEND); // append so that a removeSourceFolder action is not removed
 
 480 //                              needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE) || newResolvedPath[i].isExported();
 
 483 //                      } // classpath reordering has already been generated in previous loop
 
 487 //                      this.addDelta(delta);
 
 489 //              if (needToUpdateDependents){
 
 490 //                      updateAffectedProjects(project.getProject().getFullPath());
 
 494         protected JavaProject getProject() {
 
 495                 return ((JavaProject) getElementsToProcess()[0]);
 
 499          * Returns the source attachment flag for the delta between the 2 give source paths.
 
 500          * Returns either F_SOURCEATTACHED, F_SOURCEDETACHED, F_SOURCEATTACHED | F_SOURCEDETACHED
 
 501          * or 0 if there is no difference.
 
 503         private int getSourceAttachmentDeltaFlag(IPath oldPath, IPath newPath, IPath sourcePath) {
 
 504                 if (oldPath == null) {
 
 505                         if (newPath != null) {
 
 506                                 return IJavaElementDelta.F_SOURCEATTACHED;
 
 508                                 if (sourcePath != null) {
 
 509                                         // if source path is specified and no root path, it needs to be recomputed dynamically
 
 510                                         return IJavaElementDelta.F_SOURCEATTACHED | IJavaElementDelta.F_SOURCEDETACHED;
 
 515                 } else if (newPath == null) {
 
 516                         return IJavaElementDelta.F_SOURCEDETACHED;
 
 517                 } else if (!oldPath.equals(newPath)) {
 
 518                         return IJavaElementDelta.F_SOURCEATTACHED | IJavaElementDelta.F_SOURCEDETACHED;
 
 525          * Returns <code>true</code> if this operation performs no resource modifications,
 
 526          * otherwise <code>false</code>. Subclasses must override.
 
 528         public boolean isReadOnly() {
 
 529                 return !this.canChangeResource;
 
 532         protected void saveClasspathIfNecessary() throws JavaModelException {
 
 534                 if (!this.canChangeResource || !this.needSave) return;
 
 536                 IClasspathEntry[] classpathForSave;
 
 537                 JavaProject project = getProject();
 
 538                 if (this.newRawPath == ReuseClasspath || this.newRawPath == UpdateClasspath){
 
 539                         classpathForSave = project.getRawClasspath();
 
 541                         classpathForSave = this.newRawPath;
 
 543                 IPath outputLocationForSave;
 
 544                 if (this.newOutputLocation == ReuseOutputLocation){
 
 545                         outputLocationForSave = project.getOutputLocation();
 
 547                         outputLocationForSave = this.newOutputLocation;
 
 549                 // if read-only .classpath, then the classpath setting will never been performed completely
 
 550                 if (project.saveClasspath(classpathForSave, outputLocationForSave)) {
 
 551                         this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 
 555         public String toString(){
 
 556                 StringBuffer buffer = new StringBuffer(20);
 
 557                 buffer.append("SetClasspathOperation\n"); //$NON-NLS-1$
 
 558                 buffer.append(" - classpath : "); //$NON-NLS-1$
 
 559                 if (this.newRawPath == ReuseClasspath){
 
 560                         buffer.append("<Reuse Existing Classpath>"); //$NON-NLS-1$
 
 562                         buffer.append("{"); //$NON-NLS-1$
 
 563                         for (int i = 0; i < this.newRawPath.length; i++) {
 
 564                                 if (i > 0) buffer.append(","); //$NON-NLS-1$
 
 565                                 IClasspathEntry element = this.newRawPath[i];
 
 566                                 buffer.append(" ").append(element.toString()); //$NON-NLS-1$
 
 569                 buffer.append("\n - output location : ");  //$NON-NLS-1$
 
 570                 if (this.newOutputLocation == ReuseOutputLocation){
 
 571                         buffer.append("<Reuse Existing Output Location>"); //$NON-NLS-1$
 
 573                         buffer.append(this.newOutputLocation.toString()); //$NON-NLS-1$
 
 575                 return buffer.toString();
 
 578         private void updateClasspath() throws JavaModelException {
 
 580                 JavaProject project = ((JavaProject) getElementsToProcess()[0]);
 
 582                 beginTask(Util.bind("classpath.settingProgress", project.getElementName()), 2); //$NON-NLS-1$
 
 584                 // SIDE-EFFECT: from thereon, the classpath got modified
 
 585                 project.setRawClasspath0(this.newRawPath);
 
 587                 // resolve new path (asking for marker creation if problems)
 
 588                 if (this.newResolvedPath == null) {
 
 589                         this.newResolvedPath = project.getResolvedClasspath(true, this.canChangeResource);
 
 592 //              if (this.oldResolvedPath != null) {
 
 593 //                      generateClasspathChangeDeltas(
 
 594 //                              this.oldResolvedPath,
 
 595 //                              this.newResolvedPath,
 
 598                         this.needCycleCheck = true;
 
 599                         updateAffectedProjects(project.getProject().getFullPath());
 
 602                 updateCycleMarkersIfNecessary(newResolvedPath);
 
 606          * Update projects which are affected by this classpath change:
 
 607          * those which refers to the current project as source
 
 609         protected void updateAffectedProjects(IPath prerequisiteProjectPath) {
 
 612                         IJavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
 
 613                         IJavaProject originatingProject = getProject();
 
 614                         IJavaProject[] projects = model.getJavaProjects();
 
 615                         for (int i = 0, projectCount = projects.length; i < projectCount; i++) {
 
 617                                         JavaProject project = (JavaProject) projects[i];
 
 618                                         if (project.equals(originatingProject)) continue; // skip itself
 
 620                                         // consider ALL dependents (even indirect ones), since they may need to
 
 621                                         // flush their respective namelookup caches (all pkg fragment roots).
 
 623                                         IClasspathEntry[] classpath = project.getExpandedClasspath(true);
 
 624                                         for (int j = 0, entryCount = classpath.length; j < entryCount; j++) {
 
 625                                                 IClasspathEntry entry = classpath[j];
 
 626                                                 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT
 
 627                                                         && entry.getPath().equals(prerequisiteProjectPath)) {
 
 628                                                         project.setRawClasspath(
 
 630                                                                 SetClasspathOperation.ReuseOutputLocation, 
 
 632                                                                 this.canChangeResource,  
 
 633                                                                 project.getResolvedClasspath(true), 
 
 634                                                                 false, // updating only - no validation
 
 635                                                                 false); // updating only - no need to save
 
 639                                 } catch (JavaModelException e) {
 
 642                 } catch (JavaModelException e) {
 
 648          * Update cycle markers
 
 650         protected void updateCycleMarkersIfNecessary(IClasspathEntry[] newResolvedPath) {
 
 652                 if (!this.needCycleCheck) return;
 
 653                 if (!this.canChangeResource) return;
 
 656                         JavaProject project = getProject();
 
 657                         if (!project.hasCycleMarker() && !project.hasClasspathCycle(project.getResolvedClasspath(true))){
 
 663                                         public String getID() {
 
 664                                                 return "updateCycleMarkers";  //$NON-NLS-1$
 
 666                                         public void run() throws JavaModelException {
 
 667                                                 JavaProject.updateAllCycleMarkers();
 
 671                 } catch(JavaModelException e){
 
 676          * Sets the output location of the pre-specified project.
 
 678          * <p>This can cause changes in package fragments, in case either  the
 
 679          * old or new output location folder are considered as a package fragment.
 
 681         protected void updateOutputLocation() throws JavaModelException {
 
 683                 JavaProject project= ((JavaProject) getElementsToProcess()[0]);
 
 685                 beginTask(Util.bind("classpath.settingOutputLocationProgress", project.getElementName()), 2); //$NON-NLS-1$
 
 687                 IPath oldLocation= project.getOutputLocation();
 
 689                 // see if this will cause any package fragments to be added
 
 690                 boolean deltaToFire= false;
 
 691                 JavaElementDelta delta = newJavaElementDelta();
 
 692 //              ArrayList added= determineAffectedPackageFragments(oldLocation);
 
 693 //              Iterator iter = added.iterator();
 
 694 //              while (iter.hasNext()){
 
 695 //                      IPackageFragment frag= (IPackageFragment)iter.next();
 
 696 //                      ((IPackageFragmentRoot)frag.getParent()).close();
 
 697 //                      if (!Util.isExcluded(frag)) {
 
 698 //                              delta.added(frag);
 
 699 //                              deltaToFire = true;
 
 703                 // see if this will cause any package fragments to be removed
 
 704 //              ArrayList removed= determineAffectedPackageFragments(this.newOutputLocation);
 
 705 //              iter = removed.iterator();
 
 706 //              while (iter.hasNext()){
 
 707 //                      IPackageFragment frag= (IPackageFragment)iter.next();
 
 708 //                      ((IPackageFragmentRoot)frag.getParent()).close(); 
 
 709 //                      if (!Util.isExcluded(frag)) {
 
 710 //                              delta.removed(frag);
 
 711 //                              deltaToFire = true;
 
 715                 JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project.getProject());
 
 716                 synchronized (perProjectInfo) {
 
 717                         perProjectInfo.outputLocation = this.newOutputLocation;
 
 727          * Update projects references so that the build order is consistent with the classpath
 
 729         protected void updateProjectReferencesIfNecessary() throws JavaModelException {
 
 731                 if (!this.canChangeResource) return;
 
 732                 if (this.newRawPath == ReuseClasspath || this.newRawPath == UpdateClasspath) return;
 
 734                 JavaProject jproject = getProject();
 
 735                 String[] oldRequired = jproject.projectPrerequisites(this.oldResolvedPath);
 
 737                 if (this.newResolvedPath == null) {
 
 738                         this.newResolvedPath = jproject.getResolvedClasspath(this.newRawPath, null, true, this.needValidation, null /*no reverse map*/);
 
 740                 String[] newRequired = jproject.projectPrerequisites(this.newResolvedPath);
 
 743                         IProject project = jproject.getProject();
 
 744                         IProjectDescription description = project.getDescription();
 
 746                         IProject[] projectReferences = description.getReferencedProjects();
 
 748                         HashSet oldReferences = new HashSet(projectReferences.length);
 
 749                         for (int i = 0; i < projectReferences.length; i++){
 
 750                                 String projectName = projectReferences[i].getName();
 
 751                                 oldReferences.add(projectName);
 
 753                         HashSet newReferences = (HashSet)oldReferences.clone();
 
 755                         for (int i = 0; i < oldRequired.length; i++){
 
 756                                 String projectName = oldRequired[i];
 
 757                                 newReferences.remove(projectName);
 
 759                         for (int i = 0; i < newRequired.length; i++){
 
 760                                 String projectName = newRequired[i];
 
 761                                 newReferences.add(projectName);
 
 765                         int newSize = newReferences.size();
 
 768                                 if (oldReferences.size() == newSize){
 
 769                                         iter = newReferences.iterator();
 
 770                                         while (iter.hasNext()){
 
 771                                                 if (!oldReferences.contains(iter.next())){
 
 778                         String[] requiredProjectNames = new String[newSize];
 
 780                         iter = newReferences.iterator();
 
 781                         while (iter.hasNext()){
 
 782                                 requiredProjectNames[index++] = (String)iter.next();
 
 784                         Util.sort(requiredProjectNames); // ensure that if changed, the order is consistent
 
 786                         IProject[] requiredProjectArray = new IProject[newSize];
 
 787                         IWorkspaceRoot wksRoot = project.getWorkspace().getRoot();
 
 788                         for (int i = 0; i < newSize; i++){
 
 789                                 requiredProjectArray[i] = wksRoot.getProject(requiredProjectNames[i]);
 
 792                         description.setReferencedProjects(requiredProjectArray);
 
 793                         project.setDescription(description, this.fMonitor);
 
 795                 } catch(CoreException e){
 
 796                         throw new JavaModelException(e);
 
 800         public IJavaModelStatus verify() {
 
 802                 IJavaModelStatus status = super.verify();
 
 803                 if (!status.isOK()) {
 
 807                 if (needValidation) {
 
 808                         IJavaProject project = (IJavaProject) getElementToProcess();
 
 809                         // retrieve classpath 
 
 810                         IClasspathEntry[] entries = this.newRawPath;
 
 811                         if (entries == ReuseClasspath){
 
 813                                         entries = project.getRawClasspath();                    
 
 814                                 } catch (JavaModelException e) {
 
 815                                         return e.getJavaModelStatus();
 
 818                         // retrieve output location
 
 819                         IPath outputLocation = this.newOutputLocation;
 
 820                         if (outputLocation == ReuseOutputLocation){
 
 822                                         outputLocation = project.getOutputLocation();
 
 823                                 } catch (JavaModelException e) {
 
 824                                         return e.getJavaModelStatus();
 
 828                         // perform validation
 
 829 //                      return JavaConventions.validateClasspath(
 
 835                 return JavaModelStatus.VERIFIED_OK;