1 /******************************************************************************* 2 * Copyright (c) 2000, 2019 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.jdt.internal.core; 15 16 import org.eclipse.core.resources.ResourcesPlugin; 17 import org.eclipse.core.runtime.CoreException; 18 import org.eclipse.core.runtime.IPath; 19 import org.eclipse.core.runtime.OperationCanceledException; 20 import org.eclipse.jdt.core.IClasspathContainer; 21 import org.eclipse.jdt.core.IClasspathEntry; 22 import org.eclipse.jdt.core.IJavaElement; 23 import org.eclipse.jdt.core.IJavaModelStatusConstants; 24 import org.eclipse.jdt.core.IJavaProject; 25 import org.eclipse.jdt.core.JavaModelException; 26 import org.eclipse.jdt.internal.core.util.Util; 27 28 public class SetContainerOperation extends ChangeClasspathOperation { 29 30 IPath containerPath; 31 IJavaProject[] affectedProjects; 32 IClasspathContainer[] respectiveContainers; 33 34 /* 35 * Creates a new SetContainerOperation. 36 */ SetContainerOperation(IPath containerPath, IJavaProject[] affectedProjects, IClasspathContainer[] respectiveContainers)37 public SetContainerOperation(IPath containerPath, IJavaProject[] affectedProjects, IClasspathContainer[] respectiveContainers) { 38 super(new IJavaElement[] {JavaModelManager.getJavaModelManager().getJavaModel()}, !ResourcesPlugin.getWorkspace().isTreeLocked()); 39 this.containerPath = containerPath; 40 this.affectedProjects = affectedProjects; 41 this.respectiveContainers = respectiveContainers; 42 } 43 44 @Override executeOperation()45 protected void executeOperation() throws JavaModelException { 46 checkCanceled(); 47 try { 48 beginTask("", 1); //$NON-NLS-1$ 49 if (JavaModelManager.CP_RESOLVE_VERBOSE) 50 verbose_set_container(); 51 if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED) 52 verbose_set_container_invocation_trace(); 53 54 JavaModelManager manager = JavaModelManager.getJavaModelManager(); 55 if (manager.containerPutIfInitializingWithSameEntries(this.containerPath, this.affectedProjects, this.respectiveContainers)) 56 return; 57 58 final int projectLength = this.affectedProjects.length; 59 final IJavaProject[] modifiedProjects; 60 System.arraycopy(this.affectedProjects, 0, modifiedProjects = new IJavaProject[projectLength], 0, projectLength); 61 62 // filter out unmodified project containers 63 int remaining = 0; 64 for (int i = 0; i < projectLength; i++){ 65 if (isCanceled()) 66 return; 67 JavaProject affectedProject = (JavaProject) this.affectedProjects[i]; 68 IClasspathContainer newContainer = this.respectiveContainers[i]; 69 if (newContainer == null) newContainer = JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS; // 30920 - prevent infinite loop 70 boolean found = false; 71 if (JavaProject.hasJavaNature(affectedProject.getProject())){ 72 IClasspathEntry[] rawClasspath = affectedProject.getRawClasspath(); 73 for (int j = 0, cpLength = rawClasspath.length; j <cpLength; j++) { 74 IClasspathEntry entry = rawClasspath[j]; 75 if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER && entry.getPath().equals(this.containerPath)){ 76 found = true; 77 break; 78 } 79 } 80 } 81 if (!found) { 82 modifiedProjects[i] = null; // filter out this project - does not reference the container path, or isnt't yet Java project 83 manager.containerPut(affectedProject, this.containerPath, newContainer); 84 continue; 85 } 86 IClasspathContainer oldContainer = manager.containerGet(affectedProject, this.containerPath); 87 if (oldContainer == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) { 88 oldContainer = null; 89 } 90 if ((oldContainer != null && oldContainer.equals(this.respectiveContainers[i])) 91 || (oldContainer == this.respectiveContainers[i])/*handle case where old and new containers are null (see bug 149043*/) { 92 modifiedProjects[i] = null; // filter out this project - container did not change 93 continue; 94 } 95 remaining++; 96 manager.containerPut(affectedProject, this.containerPath, newContainer); 97 } 98 99 if (remaining == 0) return; 100 101 // trigger model refresh 102 try { 103 for(int i = 0; i < projectLength; i++){ 104 this.progressMonitor.setWorkRemaining(projectLength - i); 105 if (isCanceled()) 106 return; 107 108 JavaProject affectedProject = (JavaProject)modifiedProjects[i]; 109 if (affectedProject == null) continue; // was filtered out 110 if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED) 111 verbose_update_project(affectedProject); 112 113 // force resolved classpath to be recomputed 114 ClasspathChange classpathChange = affectedProject.getPerProjectInfo().resetResolvedClasspath(); 115 116 // if needed, generate delta, update project ref, create markers, ... 117 classpathChanged(classpathChange, i==0/*refresh external linked folder only once*/); 118 119 if (this.canChangeResources) { 120 // touch project to force a build if needed 121 try { 122 affectedProject.getProject().touch(this.progressMonitor.split(1)); 123 } catch (CoreException e) { 124 // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=148970 125 if (!ExternalJavaProject.EXTERNAL_PROJECT_NAME.equals(affectedProject.getElementName())) 126 throw e; 127 } catch (OperationCanceledException ex) { 128 throw new JavaModelException(ex, IJavaModelStatusConstants.EVALUATION_ERROR); 129 } 130 } 131 } 132 } catch(CoreException e) { 133 if (JavaModelManager.CP_RESOLVE_VERBOSE || JavaModelManager.CP_RESOLVE_VERBOSE_FAILURE) 134 verbose_failure(e); 135 if (e instanceof JavaModelException) { 136 throw (JavaModelException)e; 137 } else { 138 throw new JavaModelException(e); 139 } 140 } finally { 141 for (int i = 0; i < projectLength; i++) { 142 if (this.respectiveContainers[i] == null) { 143 manager.containerPut(this.affectedProjects[i], this.containerPath, null); // reset init in progress marker 144 } 145 } 146 } 147 } finally { 148 done(); 149 } 150 } 151 verbose_failure(CoreException e)152 private void verbose_failure(CoreException e) { 153 Util.verbose( 154 "CPContainer SET - FAILED DUE TO EXCEPTION\n" + //$NON-NLS-1$ 155 " container path: " + this.containerPath, //$NON-NLS-1$ 156 System.err); 157 e.printStackTrace(); 158 } 159 verbose_update_project(JavaProject affectedProject)160 private void verbose_update_project(JavaProject affectedProject) { 161 Util.verbose( 162 "CPContainer SET - updating affected project due to setting container\n" + //$NON-NLS-1$ 163 " project: " + affectedProject.getElementName() + '\n' + //$NON-NLS-1$ 164 " container path: " + this.containerPath); //$NON-NLS-1$ 165 } 166 verbose_set_container()167 private void verbose_set_container() { 168 Util.verbose( 169 "CPContainer SET - setting container\n" + //$NON-NLS-1$ 170 " container path: " + this.containerPath + '\n' + //$NON-NLS-1$ 171 " projects: {" +//$NON-NLS-1$ 172 org.eclipse.jdt.internal.compiler.util.Util.toString( 173 this.affectedProjects, 174 new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 175 @Override 176 public String displayString(Object o) { return ((IJavaProject) o).getElementName(); } 177 }) + 178 "}\n values: {\n" +//$NON-NLS-1$ 179 org.eclipse.jdt.internal.compiler.util.Util.toString( 180 this.respectiveContainers, 181 new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 182 @Override 183 public String displayString(Object o) { 184 StringBuffer buffer = new StringBuffer(" "); //$NON-NLS-1$ 185 if (o == null) { 186 buffer.append("<null>"); //$NON-NLS-1$ 187 return buffer.toString(); 188 } 189 IClasspathContainer container = (IClasspathContainer) o; 190 buffer.append(container.getDescription()); 191 buffer.append(" {\n"); //$NON-NLS-1$ 192 IClasspathEntry[] entries = container.getClasspathEntries(); 193 if (entries != null){ 194 for (int i = 0; i < entries.length; i++){ 195 buffer.append(" "); //$NON-NLS-1$ 196 buffer.append(entries[i]); 197 buffer.append('\n'); 198 } 199 } 200 buffer.append(" }"); //$NON-NLS-1$ 201 return buffer.toString(); 202 } 203 }) + 204 "\n }");//$NON-NLS-1$ 205 } 206 verbose_set_container_invocation_trace()207 private void verbose_set_container_invocation_trace() { 208 Util.verbose( 209 "CPContainer SET - setting container\n" + //$NON-NLS-1$ 210 " invocation stack trace:"); //$NON-NLS-1$ 211 new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$ 212 } 213 214 } 215