/******************************************************************************* * Copyright (c) 2000, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.core; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.IClasspathContainer; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.core.util.Util; public class SetContainerOperation extends ChangeClasspathOperation { IPath containerPath; IJavaProject[] affectedProjects; IClasspathContainer[] respectiveContainers; /* * Creates a new SetContainerOperation. */ public SetContainerOperation(IPath containerPath, IJavaProject[] affectedProjects, IClasspathContainer[] respectiveContainers) { super(new IJavaElement[] {JavaModelManager.getJavaModelManager().getJavaModel()}, !ResourcesPlugin.getWorkspace().isTreeLocked()); this.containerPath = containerPath; this.affectedProjects = affectedProjects; this.respectiveContainers = respectiveContainers; } protected void executeOperation() throws JavaModelException { checkCanceled(); try { beginTask("", 1); //$NON-NLS-1$ if (JavaModelManager.CP_RESOLVE_VERBOSE) verbose_set_container(); if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED) verbose_set_container_invocation_trace(); JavaModelManager manager = JavaModelManager.getJavaModelManager(); if (manager.containerPutIfInitializingWithSameEntries(this.containerPath, this.affectedProjects, this.respectiveContainers)) return; final int projectLength = this.affectedProjects.length; final IJavaProject[] modifiedProjects; System.arraycopy(this.affectedProjects, 0, modifiedProjects = new IJavaProject[projectLength], 0, projectLength); // filter out unmodified project containers int remaining = 0; for (int i = 0; i < projectLength; i++){ if (isCanceled()) return; JavaProject affectedProject = (JavaProject) this.affectedProjects[i]; IClasspathContainer newContainer = this.respectiveContainers[i]; if (newContainer == null) newContainer = JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS; // 30920 - prevent infinite loop boolean found = false; if (JavaProject.hasJavaNature(affectedProject.getProject())){ IClasspathEntry[] rawClasspath = affectedProject.getRawClasspath(); for (int j = 0, cpLength = rawClasspath.length; j <cpLength; j++) { IClasspathEntry entry = rawClasspath[j]; if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER && entry.getPath().equals(this.containerPath)){ found = true; break; } } } if (!found) { modifiedProjects[i] = null; // filter out this project - does not reference the container path, or isnt't yet Java project manager.containerPut(affectedProject, this.containerPath, newContainer); continue; } IClasspathContainer oldContainer = manager.containerGet(affectedProject, this.containerPath); if (oldContainer == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) { oldContainer = null; } if ((oldContainer != null && oldContainer.equals(this.respectiveContainers[i])) || (oldContainer == this.respectiveContainers[i])/*handle case where old and new containers are null (see bug 149043*/) { modifiedProjects[i] = null; // filter out this project - container did not change continue; } remaining++; manager.containerPut(affectedProject, this.containerPath, newContainer); } if (remaining == 0) return; // trigger model refresh try { for(int i = 0; i < projectLength; i++){ if (isCanceled()) return; JavaProject affectedProject = (JavaProject)modifiedProjects[i]; if (affectedProject == null) continue; // was filtered out if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED) verbose_update_project(affectedProject); // force resolved classpath to be recomputed ClasspathChange classpathChange = affectedProject.getPerProjectInfo().resetResolvedClasspath(); // if needed, generate delta, update project ref, create markers, ... classpathChanged(classpathChange, i==0/*refresh external linked folder only once*/); if (this.canChangeResources) { // touch project to force a build if needed try { affectedProject.getProject().touch(this.progressMonitor); } catch (CoreException e) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=148970 if (!ExternalJavaProject.EXTERNAL_PROJECT_NAME.equals(affectedProject.getElementName())) throw e; } } } } catch(CoreException e) { if (JavaModelManager.CP_RESOLVE_VERBOSE || JavaModelManager.CP_RESOLVE_VERBOSE_FAILURE) verbose_failure(e); if (e instanceof JavaModelException) { throw (JavaModelException)e; } else { throw new JavaModelException(e); } } finally { for (int i = 0; i < projectLength; i++) { if (this.respectiveContainers[i] == null) { manager.containerPut(this.affectedProjects[i], this.containerPath, null); // reset init in progress marker } } } } finally { done(); } } private void verbose_failure(CoreException e) { Util.verbose( "CPContainer SET - FAILED DUE TO EXCEPTION\n" + //$NON-NLS-1$ " container path: " + this.containerPath, //$NON-NLS-1$ System.err); e.printStackTrace(); } private void verbose_update_project(JavaProject affectedProject) { Util.verbose( "CPContainer SET - updating affected project due to setting container\n" + //$NON-NLS-1$ " project: " + affectedProject.getElementName() + '\n' + //$NON-NLS-1$ " container path: " + this.containerPath); //$NON-NLS-1$ } private void verbose_set_container() { Util.verbose( "CPContainer SET - setting container\n" + //$NON-NLS-1$ " container path: " + this.containerPath + '\n' + //$NON-NLS-1$ " projects: {" +//$NON-NLS-1$ org.eclipse.jdt.internal.compiler.util.Util.toString( this.affectedProjects, new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ public String displayString(Object o) { return ((IJavaProject) o).getElementName(); } }) + "}\n values: {\n" +//$NON-NLS-1$ org.eclipse.jdt.internal.compiler.util.Util.toString( this.respectiveContainers, new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ public String displayString(Object o) { StringBuffer buffer = new StringBuffer(" "); //$NON-NLS-1$ if (o == null) { buffer.append("<null>"); //$NON-NLS-1$ return buffer.toString(); } IClasspathContainer container = (IClasspathContainer) o; buffer.append(container.getDescription()); buffer.append(" {\n"); //$NON-NLS-1$ IClasspathEntry[] entries = container.getClasspathEntries(); if (entries != null){ for (int i = 0; i < entries.length; i++){ buffer.append(" "); //$NON-NLS-1$ buffer.append(entries[i]); buffer.append('\n'); } } buffer.append(" }"); //$NON-NLS-1$ return buffer.toString(); } }) + "\n }");//$NON-NLS-1$ } private void verbose_set_container_invocation_trace() { Util.verbose( "CPContainer SET - setting container\n" + //$NON-NLS-1$ " invocation stack trace:"); //$NON-NLS-1$ new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$ } }