1 /*******************************************************************************
2  * Copyright (c) 2000, 2018 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.core.tests.model;
15 
16 import java.io.IOException;
17 import java.util.HashMap;
18 import java.util.Map;
19 import java.util.concurrent.atomic.AtomicInteger;
20 import java.util.concurrent.atomic.AtomicReference;
21 
22 import org.eclipse.core.resources.*;
23 import org.eclipse.core.runtime.*;
24 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
25 import org.eclipse.core.runtime.preferences.InstanceScope;
26 import org.eclipse.jdt.core.*;
27 import org.eclipse.jdt.core.tests.model.Semaphore.TimeOutException;
28 import org.eclipse.jdt.internal.core.ClasspathEntry;
29 import org.eclipse.jdt.internal.core.JavaModelManager;
30 import org.eclipse.jdt.internal.core.JavaModelStatus;
31 import org.eclipse.jdt.internal.core.JavaProject;
32 import org.eclipse.jdt.internal.core.UserLibrary;
33 import org.eclipse.jdt.internal.core.UserLibraryClasspathContainer;
34 
35 import junit.framework.Test;
36 
37 @SuppressWarnings({"rawtypes", "unchecked"})
38 public class ClasspathInitializerTests extends ModifyingResourceTests {
39 
40 public static class DefaultVariableInitializer implements VariablesInitializer.ITestInitializer {
41 	Map variableValues;
42 
43 	/*
44 	 * values is [<var name>, <var value>]*
45 	 */
DefaultVariableInitializer(String[] values)46 	public DefaultVariableInitializer(String[] values) {
47 		this.variableValues = new HashMap();
48 		for (int i = 0; i < values.length; i+=2) {
49 			this.variableValues.put(values[i], new Path(values[i+1]));
50 		}
51 	}
52 
53 	@Override
initialize(String variable)54 	public void initialize(String variable) throws JavaModelException {
55 		if (this.variableValues == null) return;
56 		JavaCore.setClasspathVariable(
57 			variable,
58 			(IPath)this.variableValues.get(variable),
59 			null);
60 	}
61 }
62 
63 // Simple container initializer, which keeps setting container to null
64 // (30920 - stackoverflow when setting container to null)
65 public class NullContainerInitializer implements ContainerInitializer.ITestInitializer {
66 	public boolean hasRun = false;
67 	@Override
allowFailureContainer()68 	public boolean allowFailureContainer() {
69 		return false; // allow the initializer to run again
70 	}
71 	@Override
initialize(IPath containerPath, IJavaProject project)72 	public void initialize(IPath containerPath, IJavaProject project) throws CoreException {
73 		this.hasRun = true;
74 		JavaCore.setClasspathContainer(
75 			containerPath,
76 			new IJavaProject[] {project},
77 			new IClasspathContainer[] { null },
78 			null);
79 	}
80 }
81 
ClasspathInitializerTests(String name)82 public ClasspathInitializerTests(String name) {
83 	super(name);
84 }
suite()85 public static Test suite() {
86 	return buildModelTestSuite(ClasspathInitializerTests.class);
87 }
88 // Use this static initializer to specify subset for tests
89 // All specified tests which do not belong to the class are skipped...
90 static {
91 	// Names of tests to run: can be "testBugXXXX" or "BugXXXX")
92 //		TESTS_NAMES = new String[] { "testBug346002" };
93 	// Numbers of tests to run: "test<number>" will be run for each number of this array
94 //		TESTS_NUMBERS = new int[] { 2, 12 };
95 	// Range numbers of tests to run: all tests between "test<first>" and "test<last>" will be run for { first, last }
96 //		TESTS_RANGE = new int[] { 16, -1 };
97 }
98 @Override
tearDown()99 protected void tearDown() throws Exception {
100 	// Cleanup caches
101 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
102 	manager.containers = new HashMap(5);
103 	manager.variables = new HashMap(5);
104 
105 	super.tearDown();
106 }
107 
testContainerInitializer01()108 public void testContainerInitializer01() throws CoreException {
109 	try {
110 		createProject("P1");
111 		createFile("/P1/lib.jar", "");
112 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar"}));
113 		IJavaProject p2 = createJavaProject(
114 				"P2",
115 				new String[] {},
116 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
117 				"");
118 		IPackageFragmentRoot root = p2.getPackageFragmentRoot(getFile("/P1/lib.jar"));
119 		assertTrue("/P1/lib.jar should exist", root.exists());
120 	} finally {
121 		stopDeltas();
122 		deleteProject("P1");
123 		deleteProject("P2");
124 	}
125 }
testContainerInitializer02()126 public void testContainerInitializer02() throws CoreException {
127 	try {
128 		createProject("P1");
129 		createFile("/P1/lib.jar", "");
130 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar"}));
131 		IJavaProject p2 = createJavaProject(
132 				"P2",
133 				new String[] {},
134 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
135 				"");
136 
137 		// simulate state on startup
138 		simulateExitRestart();
139 
140 		startDeltas();
141 		p2.getResolvedClasspath(true);
142 
143 		assertDeltas(
144 			"Unexpected delta on startup",
145 			""
146 		);
147 	} finally {
148 		stopDeltas();
149 		deleteProject("P1");
150 		deleteProject("P2");
151 	}
152 }
testContainerInitializer03()153 public void testContainerInitializer03() throws CoreException {
154 	try {
155 		createProject("P1");
156 		createFile("/P1/lib.jar", "");
157 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar"}));
158 		createJavaProject(
159 				"P2",
160 				new String[] {},
161 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
162 				"");
163 
164 		// change value of TEST_CONTAINER
165 		createFile("/P1/lib2.jar", "");
166 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib2.jar"}));
167 
168 		// simulate state on startup
169 		simulateExitRestart();
170 
171 		startDeltas();
172 		getJavaProject("P2").getResolvedClasspath(true);
173 
174 		assertDeltas(
175 			"Unexpected delta on startup",
176 			"P2[*]: {CHILDREN | RESOLVED CLASSPATH CHANGED}\n" +
177 			"	/P1/lib.jar[*]: {REMOVED FROM CLASSPATH}\n" +
178 			"	/P1/lib2.jar[*]: {ADDED TO CLASSPATH}"
179 		);
180 	} finally {
181 		stopDeltas();
182 		deleteProject("P1");
183 		deleteProject("P2");
184 	}
185 }
186 /* Ensure that initializer is not callled when resource tree is locked.
187  * (regression test for bug 29585 Core Exception as resource tree is locked initializing classpath container)
188  */
testContainerInitializer04()189 public void testContainerInitializer04() throws CoreException {
190 	try {
191 		createProject("P1");
192 		createFile("/P1/lib.jar", "");
193 		DefaultContainerInitializer initializer = new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar"});
194 		ContainerInitializer.setInitializer(initializer);
195 		createJavaProject(
196 				"P2",
197 				new String[] {""},
198 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
199 				"");
200 
201 		// simulate state on startup
202 		simulateExitRestart();
203 
204 		startDeltas();
205 		createFile("/P2/X.java", "public class X {}");
206 
207 		assertEquals("Should not get exception", null, initializer.exception);
208 
209 		assertDeltas(
210 			"Unexpected delta on startup",
211 			"P2[*]: {CHILDREN}\n" +
212 			"	<project root>[*]: {CHILDREN}\n" +
213 			"		<default>[*]: {CHILDREN}\n" +
214 			"			X.java[+]: {}"
215 		);
216 	} finally {
217 		stopDeltas();
218 		deleteProject("P1");
219 		deleteProject("P2");
220 	}
221 }
222 /*
223  * 30920 - Stack overflow when container resolved to null
224  */
testContainerInitializer05()225 public void testContainerInitializer05() throws CoreException {
226 	try {
227 		NullContainerInitializer nullInitializer = new NullContainerInitializer();
228 		ContainerInitializer.setInitializer(nullInitializer);
229 		createJavaProject(
230 				"P1",
231 				new String[] {""},
232 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
233 				"");
234 
235 		// simulate state on startup
236 		simulateExitRestart();
237 
238 		startDeltas();
239 
240 		// will trigger classpath resolution (with null container value)
241 		createFile("/P1/X.java", "public class X {}");
242 		assertDeltas(
243 			"Unexpected delta on startup",
244 			"P1[*]: {CHILDREN}\n" +
245 			"	<project root>[*]: {CHILDREN}\n" +
246 			"		<default>[*]: {CHILDREN}\n" +
247 			"			X.java[+]: {}"
248 		);
249 		assertTrue("initializer did not run", nullInitializer.hasRun);
250 
251 		// next cp resolution request will rerun the initializer
252 		waitForAutoBuild();
253 		nullInitializer.hasRun = false; // reset
254 		getJavaProject("P1").getResolvedClasspath(true);
255 		assertTrue("initializer did not run", nullInitializer.hasRun); // initializer should have run again (since keep setting to null)
256 
257 		// assigning new (non-null) value to container
258 		waitForAutoBuild();
259 		createFile("/P1/lib.jar", "");
260 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P1", "/P1/lib.jar"}));
261 		clearDeltas();
262 		getJavaProject("P1").getResolvedClasspath(true);
263 		assertDeltas(
264 			"Unexpected delta after setting container",
265 			"P1[*]: {CHILDREN | RESOLVED CLASSPATH CHANGED}\n" +
266 			"	lib.jar[*]: {ADDED TO CLASSPATH}"
267 		);
268 
269 	} catch (StackOverflowError e) {
270 		e.printStackTrace();
271 		assertTrue("stack overflow assigning container", false);
272 	} finally {
273 		stopDeltas();
274 		deleteProject("P1");
275 	}
276 }
277 /*
278  * Ensures that running the initializer during a reconcile operation just after workspace startup
279  * doesn't throw a NPE
280  * (regression test for bug 48818 NPE in delta processor)
281   */
testContainerInitializer06()282 public void testContainerInitializer06() throws CoreException {
283     ICompilationUnit workingCopy = null;
284 	try {
285 		createProject("P1");
286 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", ""}));
287 		createJavaProject(
288 				"P2",
289 				new String[] {"src"},
290 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
291 				"bin");
292 		createFile(
293 			"/P2/src/X,java",
294 			"public class X {\n" +
295 			"}"
296 		);
297 
298 		// change value of TEST_CONTAINER
299 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1"}));
300 
301 		// simulate state on startup
302 		simulateExitRestart();
303 
304 		startDeltas();
305 		workingCopy = getCompilationUnit("/P2/src/X.java");
306 		workingCopy.becomeWorkingCopy(null);
307 
308 		assertWorkingCopyDeltas(
309 			"Unexpected delta on startup",
310 			"P2[*]: {CHILDREN}\n" +
311 			"	src[*]: {CHILDREN}\n" +
312 			"		<default>[*]: {CHILDREN}\n" +
313 			"			[Working copy] X.java[+]: {PRIMARY WORKING COPY}"
314 		);
315 	} finally {
316 		stopDeltas();
317 		if (workingCopy != null) workingCopy.discardWorkingCopy();
318 		deleteProject("P1");
319 		deleteProject("P2");
320 	}
321 }
322 /*
323  * Ensure that an OperationCanceledException goes through
324  * (regression test for bug 59363 Should surface cancellation exceptions)
325  */
testContainerInitializer07()326 public void testContainerInitializer07() throws CoreException {
327 	try {
328 		boolean gotException = false;
329 		try {
330 			ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P1", "/P1/lib.jar"}) {
331 				@Override
332 				public void initialize(IPath containerPath, IJavaProject project) throws CoreException {
333 					throw new OperationCanceledException("test");
334 				}});
335 			IJavaProject p1 = createJavaProject(
336 					"P1",
337 					new String[] {},
338 					new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
339 					"");
340 			p1.getResolvedClasspath(true);
341 		} catch (OperationCanceledException e) {
342 			gotException = true;
343 		}
344 		assertTrue("Should get an OperationCanceledException", gotException);
345 	} finally {
346 		stopDeltas();
347 		deleteProject("P1");
348 	}
349 }
350 /*
351  * Ensure that the stack doesn't blow up if initializer is missbehaving
352  * (regression test for bug 61052 Flatten cp container initialization)
353  */
testContainerInitializer08()354 public void testContainerInitializer08() throws CoreException {
355 	final int projectLength = 10;
356 	final String[] projects = new String[projectLength];
357 	for (int i = 0; i < projectLength; i++) {
358 		projects[i] = "P" + i;
359 	}
360 	try {
361 		String[] projectRefs = new String[(projectLength-1) * 2];
362 		for (int i = 0; i < projectLength-1; i++) {
363 			projectRefs[i*2] = "P" + i;
364 			projectRefs[(i*2)+1] = "/P" + i + "/test.jar";
365 		}
366 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(projectRefs) {
367 			void foo(int n) {
368 				if (n > 0) {
369 					foo(n-1);
370 					return;
371 				}
372 				IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
373 				for (int i = 0; i < projectLength-1; i++) {
374 					try {
375 						JavaCore.create(root.getProject(projects[i])).getResolvedClasspath(true);
376 					} catch (JavaModelException e) {
377 						// project doesn't exist: ignore
378 					}
379 				}
380 			}
381 			@Override
382 			public void initialize(IPath containerPath, IJavaProject project) throws CoreException {
383 				foo(500);
384 				super.initialize(containerPath, project);
385 			}
386 		});
387 		JavaCore.run(new IWorkspaceRunnable() {
388 			public void run(IProgressMonitor monitor) throws CoreException {
389 				for (int i = 0; i < projectLength; i++) {
390 					createProject(projects[i]);
391 					editFile(
392 						"/" + projects[i] + "/.project",
393 						"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
394 						"<projectDescription>\n" +
395 						"	<name>" + projects[i] + "</name>\n" +
396 						"	<comment></comment>\n" +
397 						"	<projects>\n" +
398 						(i == 0 ? "" : "<project>" + projects[i-1] + "</project>\n") +
399 						"	</projects>\n" +
400 						"	<buildSpec>\n" +
401 						"		<buildCommand>\n" +
402 						"			<name>org.eclipse.jdt.core.javabuilder</name>\n" +
403 						"			<arguments>\n" +
404 						"			</arguments>\n" +
405 						"		</buildCommand>\n" +
406 						"	</buildSpec>\n" +
407 						"	<natures>\n" +
408 						"		<nature>org.eclipse.jdt.core.javanature</nature>\n" +
409 						"	</natures>\n" +
410 						"</projectDescription>"
411 					);
412 					createFile(
413 						"/" + projects[i] + "/.classpath",
414 						"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
415 						"<classpath>\n" +
416 						(i == 0 ? "" : "<classpathentry kind=\"src\" path=\"/" + projects[i-1] + "\"/>\n") +
417 						"	<classpathentry kind=\"con\" path=\"org.eclipse.jdt.core.tests.model.TEST_CONTAINER\"/>\n" +
418 						"	<classpathentry kind=\"output\" path=\"\"/>\n" +
419 						"</classpath>"
420 					);
421 				}
422 			}
423 		}, null);
424 		getJavaProject("P0").getResolvedClasspath(true);
425 	} finally {
426 		stopDeltas();
427 		deleteProjects(projects);
428 	}
429 }
430 /*
431  * Ensure that a StackOverFlowError is not thrown if the initializer asks for the resolved classpath
432  * that is being resolved.
433  * (regression test for bug 61040 Should add protect for reentrance to #getResolvedClasspath)
434  */
testContainerInitializer09()435 public void testContainerInitializer09() throws CoreException {
436 	try {
437 		DefaultContainerInitializer initializer = new DefaultContainerInitializer(new String[] {"P1", "/P1/lib.jar"}) {
438 			@Override
439 			protected DefaultContainer newContainer(char[][] libPaths) {
440 				return new DefaultContainer(libPaths) {
441 					@Override
442 					public IClasspathEntry[] getClasspathEntries() {
443 						try {
444 							getJavaProject("P1").getResolvedClasspath(true);
445 						} catch (JavaModelException e) {
446 							// project doesn't exist: ignore
447 						}
448 						return super.getClasspathEntries();
449 					}
450 				};
451 			}
452 		};
453 		ContainerInitializer.setInitializer(initializer);
454 		JavaCore.run(new IWorkspaceRunnable() {
455 			public void run(IProgressMonitor monitor) throws CoreException {
456 				createProject("P1");
457 				editFile(
458 					"/P1/.project",
459 					"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
460 					"<projectDescription>\n" +
461 					"	<name>P1</name>\n" +
462 					"	<comment></comment>\n" +
463 					"	<projects>\n" +
464 					"	</projects>\n" +
465 					"	<buildSpec>\n" +
466 					"		<buildCommand>\n" +
467 					"			<name>org.eclipse.jdt.core.javabuilder</name>\n" +
468 					"			<arguments>\n" +
469 					"			</arguments>\n" +
470 					"		</buildCommand>\n" +
471 					"	</buildSpec>\n" +
472 					"	<natures>\n" +
473 					"		<nature>org.eclipse.jdt.core.javanature</nature>\n" +
474 					"	</natures>\n" +
475 					"</projectDescription>"
476 				);
477 				createFile(
478 					"/P1/.classpath",
479 					"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
480 					"<classpath>\n" +
481 					"	<classpathentry kind=\"con\" path=\"org.eclipse.jdt.core.tests.model.TEST_CONTAINER\"/>\n" +
482 					"	<classpathentry kind=\"output\" path=\"\"/>\n" +
483 					"</classpath>"
484 				);
485 			}
486 		}, null);
487 		getJavaProject("P1").getResolvedClasspath(true);
488 	} finally {
489 		stopDeltas();
490 		ContainerInitializer.setInitializer(null);
491 		deleteProject("P1");
492 	}
493 }
494 /*
495  * Ensure that creating a Java project initializes a container and refreshes the external jar at the same time
496  * without throwing a ConcurrentModificationException
497  * (regression test for bug 63534 ConcurrentModificationException after "catching up")
498  */
testContainerInitializer10()499 public void testContainerInitializer10() throws CoreException {
500 	class LogListener implements ILogListener {
501     	IStatus loggedStatus;
502         public void logging(IStatus status, String plugin) {
503             this.loggedStatus = status;
504         }
505 	}
506 	LogListener listener = new LogListener();
507 	try {
508 		Platform.addLogListener(listener);
509 		final IJavaProject p1 = createJavaProject("P1");
510 		final IJavaProject p2 = createJavaProject("P2");
511 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P3", "/P1"}) {
512 			@Override
513 	        public void initialize(IPath containerPath, IJavaProject project) throws CoreException {
514 	            super.initialize(containerPath, project);
515 	            getJavaModel().refreshExternalArchives(new IJavaElement[] {p1}, null);
516 	        }
517 		});
518 		getWorkspace().run(new IWorkspaceRunnable() {
519             public void run(IProgressMonitor monitor) throws CoreException {
520                 p2.setRawClasspath(new IClasspathEntry[] {JavaCore.newSourceEntry(new Path("/P2/src"))}, new Path("/P2/bin"), null);
521 				createProject("P3");
522                 editFile(
523                 	"/P3/.project",
524                 	"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
525                 	"<projectDescription>\n" +
526                 	"	<name>P3</name>\n" +
527                 	"	<comment></comment>\n" +
528                 	"	<projects>\n" +
529                 	"	</projects>\n" +
530                 	"	<buildSpec>\n" +
531                 	"		<buildCommand>\n" +
532                 	"			<name>org.eclipse.jdt.core.javabuilder</name>\n" +
533                 	"			<arguments>\n" +
534                 	"			</arguments>\n" +
535                 	"		</buildCommand>\n" +
536                 	"	</buildSpec>\n" +
537                 	"	<natures>\n" +
538                 	"		<nature>org.eclipse.jdt.core.javanature</nature>\n" +
539                 	"	</natures>\n" +
540                 	"</projectDescription>\n"
541                 );
542                 createFile(
543                 	"/P3/.classpath",
544                 	"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
545                 	"<classpath>\n" +
546                 	"	<classpathentry kind=\"src\" path=\"\"/>\n" +
547                 	"	<classpathentry kind=\"var\" path=\"JCL_LIB\"/>\n" +
548                 	"	<classpathentry kind=\"con\" path=\"org.eclipse.jdt.core.tests.model.TEST_CONTAINER\"/>\n" +
549                 	"	<classpathentry kind=\"output\" path=\"\"/>\n" +
550                 	"</classpath>"
551                 );
552              }
553         }, null);
554 
555 		assertEquals("Should not get any exception in log", null, listener.loggedStatus);
556 	} finally {
557 	    Platform.removeLogListener(listener);
558 		deleteProject("P1");
559 		deleteProject("P2");
560 		deleteProject("P3");
561 	}
562 }
563 /*
564  * Ensure that a classpath initializer is not run on shutdown
565  * (regression test for bug 93941 Classpath initialization on shutdown)
566  */
testContainerInitializer11()567 public void testContainerInitializer11() throws CoreException {
568 	boolean hasExited = false;
569 	try {
570 		ContainerInitializer.setInitializer(null);
571 		createJavaProject(
572 			"P",
573 			new String[] {},
574 			new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
575 			"");
576 		simulateExitRestart();
577 		DefaultContainerInitializer initializer = new DefaultContainerInitializer(new String[] {}) {
578 			@Override
579 			public void initialize(IPath containerPath,IJavaProject project) throws CoreException {
580 				assertTrue("Should not initialize container on shutdown", false);
581 			}
582 		};
583 		ContainerInitializer.setInitializer(initializer);
584 		simulateExit();
585 		hasExited = true;
586 	} finally {
587 		ContainerInitializer.setInitializer(null);
588 		if (hasExited)
589 			simulateRestart();
590 		deleteProject("P");
591 	}
592 }
593 
594 /*
595  * Ensure that the initializer is removed from the cache when the project is deleted
596  * (regression test for bug 116072 cached classpath containers not removed when project deleted)
597  */
testContainerInitializer12()598 public void testContainerInitializer12() throws CoreException {
599 	try {
600 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P1", "/P1/lib.jar"}));
601 		IJavaProject project =  createJavaProject(
602 			"P1",
603 			new String[] {},
604 			new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
605 			"");
606 		createFile("/P1/lib.jar", "");
607 		IPackageFragmentRoot root = project.getPackageFragmentRoot(getFile("/P1/lib.jar"));
608 		assertTrue("/P1/lib.jar should exist", root.exists());
609 		deleteProject("P1");
610 
611 		class Initializer extends DefaultContainerInitializer {
612 			boolean initialized;
613 			public Initializer(String[] args) {
614 				super(args);
615 			}
616 			@Override
617 			public void initialize(IPath containerPath, IJavaProject p) throws CoreException {
618 				super.initialize(containerPath, p);
619 				this.initialized = true;
620 			}
621 		}
622 		Initializer initializer = new Initializer(new String[] {"P1", "/P1/lib.jar"});
623 		ContainerInitializer.setInitializer(initializer);
624 		createJavaProject(
625 			"P1",
626 			new String[] {},
627 			new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
628 			"");
629 		createFile("/P1/lib.jar", "");
630 		assertTrue("/P1/lib.jar should exist", root.exists());
631 		assertTrue("Should have been initialized", initializer.initialized);
632 	} finally {
633 		stopDeltas();
634 		deleteProject("P1");
635 	}
636 }
637 
638 /*
639  * Ensures that no resource deta is reported if a container that was not initialized is initialized with null
640  * (regression test for bug 149043 Unresolvable classpath container leads to lots of scheduled jobs)
641  */
testContainerInitializer13()642 public void testContainerInitializer13() throws CoreException {
643 	IResourceChangeListener listener = new IResourceChangeListener() {
644 		StringBuffer buffer = new StringBuffer();
645 		public void resourceChanged(IResourceChangeEvent event) {
646 			this.buffer.append(event.getDelta().findMember(new Path("/P1")));
647 		}
648 		public String toString() {
649 			return this.buffer.toString();
650 		}
651 	};
652 	try {
653 		NullContainerInitializer nullInitializer = new NullContainerInitializer();
654 		ContainerInitializer.setInitializer(nullInitializer);
655 		IJavaProject project = createJavaProject(
656 				"P1",
657 				new String[] {},
658 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
659 				"");
660 
661 		// simulate state on startup
662 		simulateExitRestart();
663 
664 		getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE);
665 
666 		// force resolution of container
667 		project.findPackageFragmentRoots(project.getRawClasspath()[0]);
668 
669 		assertEquals(
670 			"Unexpected resource delta on startup",
671 			"",
672 			listener.toString()
673 		);
674 	} finally {
675 		getWorkspace().removeResourceChangeListener(listener);
676 		deleteProject("P1");
677 	}
678 }
679 
680 /*
681  * Ensures that a misbehaving container (that initializes another project than the one asked for) doesn't cause
682  * the container to be initialized again
683  * (regression test for bug 160005 Add protection about misbehaving container initializer)
684  */
testContainerInitializer14()685 public void testContainerInitializer14() throws CoreException {
686 	try {
687 		createProject("P1");
688 		createFile("/P1/lib.jar", "");
689 		class Container extends DefaultContainerInitializer {
690 			int initializeCount = 0;
691 			Container(String[] values) {
692 				super(values);
693 			}
694 			@Override
695 			public void initialize(IPath containerPath, IJavaProject project) 	throws CoreException {
696 				this.initializeCount++;
697 				super.initialize(containerPath, getJavaProject("P1"));
698 			}
699 		}
700 		Container container = new Container(new String[] {"P2", "/P1/lib.jar"});
701 		ContainerInitializer.setInitializer(container);
702 		IJavaProject p2 = createJavaProject(
703 				"P2",
704 				new String[] {},
705 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
706 				"");
707 		p2.getResolvedClasspath(true);
708 		assertEquals("Unexpected number of initalizations", 1, container.initializeCount);
709 	} finally {
710 		stopDeltas();
711 		deleteProject("P1");
712 		deleteProject("P2");
713 	}
714 }
715 
716 /*
717  * Ensures that if a container is misbehaving (it doesn't initialize a project when asked for),
718  * then the resulting container's classpath is not null
719  * (regression test for bug 161846 Expanding a java project with invalid classpath container entries in Project Explorer causes CPU to stay at 100%)
720  */
testContainerInitializer15()721 public void testContainerInitializer15() throws CoreException {
722 	try {
723 		class Container extends DefaultContainerInitializer {
724 			Container(String[] values) {
725 				super(values);
726 			}
727 			@Override
728 			public void initialize(IPath containerPath, IJavaProject project) 	throws CoreException {
729 			}
730 		}
731 		Container container = new Container(new String[] {"P1", "/P1/lib.jar"});
732 		ContainerInitializer.setInitializer(container);
733 		IJavaProject p1 = createJavaProject(
734 				"P1",
735 				new String[] {},
736 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
737 				"");
738 		IClasspathContainer classpathContainer = JavaCore.getClasspathContainer(new Path("org.eclipse.jdt.core.tests.model.TEST_CONTAINER"), p1);
739 		assertClasspathEquals(classpathContainer.getClasspathEntries(), "");
740 	} finally {
741 		stopDeltas();
742 		deleteProject("P1");
743 	}
744 }
745 /*
746  * Ensure that an initializer cannot return a project entry that points to the project of the container (cycle).
747  */
testContainerInitializer16()748 public void testContainerInitializer16() throws CoreException {
749 	try {
750 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P1", "/P1"}));
751 		JavaModelException exception = null;
752 		try {
753 			IJavaProject p1 = createJavaProject(
754 				"P1",
755 				new String[] {},
756 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
757 				"");
758 			p1.getResolvedClasspath(true);
759 		} catch (JavaModelException e) {
760 			exception = e;
761 		}
762 		assertExceptionEquals(
763 			"Unexpected expection",
764 			"Project 'P1' cannot reference itself",
765 			exception);
766 	} finally {
767 		stopDeltas();
768 		deleteProject("P1");
769 	}
770 }
771 
772 /*
773  * Ensures that no resource deta is reported if a container is initialized right after startup  to the same value it had before shutdown.
774  * (regression test for bug 175849 Project is touched on restart)
775  */
testContainerInitializer17()776 public void testContainerInitializer17() throws CoreException {
777 	IResourceChangeListener listener = new IResourceChangeListener() {
778 		StringBuffer buffer = new StringBuffer();
779 		public void resourceChanged(IResourceChangeEvent event) {
780 			this.buffer.append(event.getDelta().findMember(new Path("/P2")));
781 		}
782 		public String toString() {
783 			return this.buffer.toString();
784 		}
785 	};
786 	try {
787 		createProject("P1");
788 		createFile("/P1/lib.jar", "");
789 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar", "P3", "/P1/lib.jar"}));
790 		IJavaProject p2 = createJavaProject(
791 				"P2",
792 				new String[] {},
793 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
794 				"");
795 		createJavaProject(
796 				"P3",
797 				new String[] {},
798 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
799 				"");
800 
801 		// simulate state on startup
802 		simulateExitRestart();
803 
804 		getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE);
805 
806 		// initialize to the same value
807 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar", "P3", "/P1/lib.jar"}) {
808 			@Override
809 	        public void initialize(IPath containerPath, IJavaProject project) throws CoreException {
810 	        	// simulate concurrency (another thread is initializing all containers in parallel and thus this flag is set to true)
811 	        	JavaModelManager.getJavaModelManager().batchContainerInitializations = JavaModelManager.NEED_BATCH_INITIALIZATION;
812 	            super.initialize(containerPath, project);
813 	        }
814 		});
815 		p2.getResolvedClasspath(true);
816 
817 		assertEquals(
818 			"Unexpected resource delta on container initialization",
819 			"",
820 			listener.toString()
821 		);
822 	} finally {
823 		getWorkspace().removeResourceChangeListener(listener);
824 		deleteProject("P1");
825 		deleteProject("P2");
826 		deleteProject("P3");
827 	}
828 }
829 /*
830  * Ensures that an unbound container marker is created if container is reset to null
831  * (regression test for 182204 Deleting a JRE referenced by container does not result in unbound container problem)
832  */
testContainerInitializer18()833 public void testContainerInitializer18() throws CoreException {
834 	try {
835 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P1", "/P1/lib.jar"}));
836 		IJavaProject p1 = createJavaProject(
837 				"P1",
838 				new String[] {},
839 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
840 				"");
841 		createFile("/P1/lib.jar", "");
842 		p1.getResolvedClasspath(true);
843 		waitForAutoBuild();
844 
845 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[0]));
846 		JavaCore.setClasspathContainer(new Path("org.eclipse.jdt.core.tests.model.TEST_CONTAINER"), new IJavaProject[] {p1}, new IClasspathContainer[] {null}, null);
847 		assertBuildPathMarkers(
848 			"Unexpected markers",
849 			"Unbound classpath container: \'org.eclipse.jdt.core.tests.model.TEST_CONTAINER\' in project \'P1\'",
850 			p1);
851 	} finally {
852 		deleteProject("P1");
853 	}
854 }
855 
856 /*
857  * Ensures that a container is not kept in the cache if no longer referenced on the classpath
858  * (regression test for 139446 [build path] bug in the Edit Library dialog box, when changing the default JRE, and switching from alternate JRE to workspace default)
859  */
testContainerInitializer19()860 public void testContainerInitializer19() throws CoreException {
861 	try {
862 		// setup
863 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P1", "/P1/lib1.jar"}));
864 		IJavaProject p1 = createJavaProject(
865 				"P1",
866 				new String[] {},
867 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
868 				"");
869 		createFile("/P1/lib1.jar", "");
870 		createFile("/P1/lib2.jar", "");
871 		p1.getResolvedClasspath(true);
872 		IClasspathEntry[] initialClasspath = p1.getRawClasspath();
873 
874 		// remove reference to container, change initializer, and add reference to container back
875 		p1.setRawClasspath(new IClasspathEntry[0], null);
876 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P1", "/P1/lib2.jar"}));
877 		p1.setRawClasspath(initialClasspath, null);
878 
879 		assertClasspathEquals(
880 			p1.getResolvedClasspath(true),
881 			"/P1/lib2.jar[CPE_LIBRARY][K_BINARY][isExported:false]"
882 		);
883 	} finally {
884 		deleteProject("P1");
885 	}
886 }
887 
888 /*
889  * Ensures that container a container is not kept in the cache if no longer referenced on the classpath
890  * (regression test for 136382 [classpath] Discard container if not referenced on classpath)
891  */
testContainerInitializer20()892 public void testContainerInitializer20() throws CoreException {
893 	try {
894 		IJavaProject p = createJavaProject("P");
895 		final StringBuffer paths = new StringBuffer();
896 		DefaultContainerInitializer initializer = new DefaultContainerInitializer(new String[] {"P", "/P/lib.jar"}) {
897 			@Override
898 			public void initialize(IPath containerPath, IJavaProject project) throws CoreException {
899 				paths.append(containerPath);
900 				paths.append('\n');
901 				super.initialize(containerPath, project);
902 			}
903 		};
904 		ContainerInitializer.setInitializer(initializer);
905 
906 		setClasspath(p, new IClasspathEntry[] {JavaCore.newContainerEntry(new Path("org.eclipse.jdt.core.tests.model.TEST_CONTAINER/JRE1"))});
907 		setClasspath(p, new IClasspathEntry[] {JavaCore.newContainerEntry(new Path("org.eclipse.jdt.core.tests.model.TEST_CONTAINER/JRE2"))});
908 		setClasspath(p, new IClasspathEntry[] {JavaCore.newContainerEntry(new Path("org.eclipse.jdt.core.tests.model.TEST_CONTAINER/JRE1"))});
909 		assertStringEquals(
910 			"org.eclipse.jdt.core.tests.model.TEST_CONTAINER/JRE1\n" +
911 			"org.eclipse.jdt.core.tests.model.TEST_CONTAINER/JRE2\n" +
912 			"org.eclipse.jdt.core.tests.model.TEST_CONTAINER/JRE1\n",
913 			paths.toString(),
914 			false);
915 	} finally {
916 		stopDeltas();
917 		deleteProject("P");
918 	}
919 }
920 
testContainerInitializer21()921 public void testContainerInitializer21() throws CoreException {
922 	try {
923 		createProject("P1");
924 		createExternalFolder("externalLib");
925 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", getExternalResourcePath("externalLib")}));
926 		IJavaProject p2 = createJavaProject(
927 				"P2",
928 				new String[] {},
929 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
930 				"");
931 		IPackageFragmentRoot root = p2.getPackageFragmentRoot(getExternalResourcePath("externalLib"));
932 		assertTrue(getExternalResourcePath("externalLib") + " should exist", root.exists());
933 	} finally {
934 		stopDeltas();
935 		deleteExternalResource("externalLib");
936 		deleteProject("P1");
937 		deleteProject("P2");
938 	}
939 }
940 
testContainerInitializer22()941 public void testContainerInitializer22() throws CoreException {
942 	try {
943 		createProject("P1");
944 		createExternalFile("externalLib.abc", "");
945 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", getExternalResourcePath("externalLib.abc")}));
946 		IJavaProject p2 = createJavaProject(
947 				"P2",
948 				new String[] {},
949 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
950 				"");
951 		IPackageFragmentRoot root = p2.getPackageFragmentRoot(getExternalResourcePath("externalLib.abc"));
952 		assertTrue(getExternalResourcePath("externalLib.abc") + " should exist", root.exists());
953 	} finally {
954 		stopDeltas();
955 		deleteExternalResource("externalLib.abc");
956 		deleteProject("P1");
957 		deleteProject("P2");
958 	}
959 }
960 
testContainerInitializer23()961 public void testContainerInitializer23() throws CoreException {
962 	try {
963 		createProject("P1");
964 		IFile lib = createFile("/P1/internalLib.abc", "");
965 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/internalLib.abc"}));
966 		IJavaProject p2 = createJavaProject(
967 				"P2",
968 				new String[] {},
969 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
970 				"");
971 		IPackageFragmentRoot root = p2.getPackageFragmentRoot(lib);
972 		assertTrue("/P1/internalLib.abc should exist", root.exists());
973 	} finally {
974 		stopDeltas();
975 		deleteExternalResource("externalLib.abc");
976 		deleteProject("P1");
977 		deleteProject("P2");
978 	}
979 }
980 
981 /*
982  * Ensures that the value of a resolved classpath is correct if another thread is resolving the classpath concurrently
983  * (regression test for https://bugs.eclipse.org/bugs/show_bug.cgi?id=232478 )
984  */
testContainerInitializer24()985 public void testContainerInitializer24() throws Exception {
986 	BPThread.TIMEOUT = 30000; // wait 30s max
987 	BPThread thread = new BPThread("getResolvedClasspath()");
988 	ClasspathResolutionBreakpointListener listener = new ClasspathResolutionBreakpointListener(new BPThread[] {thread});
989 	try {
990 		createProject("P1");
991 		createFile("/P1/lib.jar", "");
992 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar"}));
993 		final JavaProject project2 = (JavaProject) createJavaProject(
994 				"P2",
995 				new String[] {},
996 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
997 				"");
998 		simulateExit();
999 		try {
1000 			deleteResource(JavaCore.getPlugin().getStateLocation().append("variablesAndContainers.dat").toFile());
1001 		} finally {
1002 			simulateRestart();
1003 		}
1004 
1005 		JavaProject.addCPResolutionBPListener(listener);
1006 		thread.start(new Runnable() {
1007 			@Override
1008 			public void run() {
1009 				try {
1010 					project2.getResolvedClasspath();
1011 				} catch (JavaModelException e) {
1012 					e.printStackTrace();
1013 				}
1014 			}
1015 		});
1016 		thread.runToBP(1);
1017 		thread.runToBP(2);
1018 		thread.runToBP(3);
1019 
1020 		IClasspathEntry[] classpath = project2.getResolvedClasspath();
1021 		assertClasspathEquals(
1022 			classpath,
1023 			"/P1/lib.jar[CPE_LIBRARY][K_BINARY][isExported:false]"
1024 		);
1025 
1026 	} finally {
1027 		JavaProject.removeCPResolutionBPListener(listener);
1028 		thread.runToEnd();
1029 		deleteProjects(new String[] {"P1", "P2"});
1030 	}
1031 }
1032 
1033 /*
1034  * Ensures that the project references are updated on startup if the initializer gives a different value.
1035  */
testContainerInitializer25()1036 public void testContainerInitializer25() throws CoreException {
1037 	try {
1038 		createProject("P1");
1039 		createFile("/P1/lib.jar", "");
1040 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar"}));
1041 		IJavaProject p2 = createJavaProject(
1042 				"P2",
1043 				new String[] {},
1044 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
1045 				"");
1046 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1"}));
1047 
1048 		// simulate state on startup
1049 		simulateExitRestart();
1050 
1051 		p2.getResolvedClasspath(true);
1052 		assertResourcesEqual(
1053 			"Unexpected project references on startup",
1054 			"/P1",
1055 			p2.getProject().getReferencedProjects());
1056 	} finally {
1057 		deleteProject("P1");
1058 		deleteProject("P2");
1059 	}
1060 }
1061 
1062 
1063 /*
1064  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=327471
1065  * [java.io.EOFException at java.io.DataInputStream.readInt(Unknown Source)]
1066  * This test ensures that there is no exception on a restart of eclipse after
1067  * the project is closed after the workspace save
1068  */
testContainerInitializer26()1069 public void testContainerInitializer26() throws CoreException {
1070 	try {
1071 		createProject("P1");
1072 		createFile("/P1/lib.jar", "");
1073 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar"}));
1074 		IJavaProject p2 = createJavaProject(
1075 				"P2",
1076 				new String[] {},
1077 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
1078 				"");
1079 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1"}));
1080 
1081 		waitForAutoBuild();
1082 		getWorkspace().save(true/*full save*/, null/*no progress*/);
1083 		p2.getProject().close(null); // close the project after the save and before the shutdown
1084 		JavaModelManager.getJavaModelManager().shutdown();
1085 
1086 		startLogListening();
1087 		simulateRestart();
1088 		assertLogEquals(""); // no error should be logged
1089 
1090 	} finally {
1091 		stopLogListening();
1092 		deleteProject("P1");
1093 		deleteProject("P2");
1094 	}
1095 }
testVariableInitializer01()1096 public void testVariableInitializer01() throws CoreException {
1097 	try {
1098 		createProject("P1");
1099 		createFile("/P1/lib.jar", "");
1100 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] {"TEST_LIB", "/P1/lib.jar"}));
1101 		IJavaProject p2 = createJavaProject("P2", new String[] {}, new String[] {"TEST_LIB"}, "");
1102 		IPackageFragmentRoot root = p2.getPackageFragmentRoot(getFile("/P1/lib.jar"));
1103 		assertTrue("/P1/lib.jar should exist", root.exists());
1104 	} finally {
1105 		deleteProject("P1");
1106 		deleteProject("P2");
1107 		VariablesInitializer.reset();
1108 	}
1109 }
testVariableInitializer02()1110 public void testVariableInitializer02() throws CoreException {
1111 	try {
1112 		createProject("P1");
1113 		createFile("/P1/lib.jar", "");
1114 		createFile("/P1/src.zip", "");
1115 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] {
1116 			"TEST_LIB", "/P1/lib.jar",
1117 			"TEST_SRC", "/P1/src.zip",
1118 			"TEST_ROOT", "src",
1119 		}));
1120 		IJavaProject p2 = createJavaProject("P2", new String[] {}, new String[] {"TEST_LIB,TEST_SRC,TEST_ROOT"}, "");
1121 		IPackageFragmentRoot root = p2.getPackageFragmentRoot(getFile("/P1/lib.jar"));
1122 		assertEquals("Unexpected source attachment path", "/P1/src.zip", root.getSourceAttachmentPath().toString());
1123 		assertEquals("Unexpected source attachment root path", "src", root.getSourceAttachmentRootPath().toString());
1124 	} finally {
1125 		deleteProject("P1");
1126 		deleteProject("P2");
1127 		VariablesInitializer.reset();
1128 	}
1129 }
testVariableInitializer03()1130 public void testVariableInitializer03() throws CoreException {
1131 	try {
1132 		createProject("P1");
1133 		createFile("/P1/lib.jar", "");
1134 		createFile("/P1/src.zip", "");
1135 		String[] variableValues = new String[] {
1136 			"TEST_LIB", "/P1/lib.jar",
1137 			"TEST_SRC", "/P1/src.zip",
1138 			"TEST_ROOT", "src",
1139 		};
1140 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(variableValues));
1141 		createJavaProject("P2", new String[] {}, new String[] {"TEST_LIB,TEST_SRC,TEST_ROOT"}, "");
1142 
1143 		// simulate state on startup
1144 		simulateExitRestart();
1145 
1146 		startDeltas();
1147 		//JavaModelManager.CP_RESOLVE_VERBOSE=true;
1148 		getJavaProject("P2").getResolvedClasspath(true);
1149 
1150 		assertDeltas(
1151 			"Unexpected delta on startup",
1152 			""
1153 		);
1154 	} finally {
1155 		//JavaModelManager.CP_RESOLVE_VERBOSE=false;
1156 		stopDeltas();
1157 		deleteProject("P1");
1158 		deleteProject("P2");
1159 		VariablesInitializer.reset();
1160 	}
1161 }
testVariableInitializer04()1162 public void testVariableInitializer04() throws CoreException {
1163 	try {
1164 		final StringBuffer buffer = new StringBuffer();
1165 		VariablesInitializer.setInitializer(new VariablesInitializer.ITestInitializer() {
1166 			@Override
1167 			public void initialize(String variable) throws JavaModelException {
1168 				buffer.append("Initializing " + variable + "\n");
1169 				IPath path = new Path(variable.toLowerCase());
1170 				buffer.append("Setting variable " + variable + " to " + path + "\n");
1171 				JavaCore.setClasspathVariable(variable, path, null);
1172 			}
1173 		});
1174 		createJavaProject("P", new String[] {}, new String[] {"TEST_LIB,TEST_SRC,TEST_ROOT"}, "");
1175 		assertEquals(
1176 			"Initializing TEST_LIB\n" +
1177 			"Setting variable TEST_LIB to test_lib\n",
1178 			buffer.toString());
1179 	} finally {
1180 		deleteProject("P");
1181 		VariablesInitializer.reset();
1182 	}
1183 }
testVariableInitializer05()1184 public void testVariableInitializer05() throws CoreException {
1185 	try {
1186 		final StringBuffer buffer = new StringBuffer();
1187 		VariablesInitializer.setInitializer(new VariablesInitializer.ITestInitializer() {
1188 			@Override
1189 			public void initialize(String variable) throws JavaModelException {
1190 				buffer.append("Initializing " + variable + "\n");
1191 				IPath path = new Path(variable.toLowerCase());
1192 				JavaCore.getClasspathVariable("TEST_SRC");
1193 				buffer.append("Setting variable " + variable + " to " + path + "\n");
1194 				JavaCore.setClasspathVariable(variable, path, null);
1195 			}
1196 		});
1197 		createJavaProject("P", new String[] {}, new String[] {"TEST_LIB,TEST_SRC,TEST_ROOT"}, "");
1198 		assertEquals(
1199 			"Initializing TEST_LIB\n" +
1200 			"Initializing TEST_SRC\n" +
1201 			"Setting variable TEST_SRC to test_src\n" +
1202 			"Setting variable TEST_LIB to test_lib\n",
1203 			buffer.toString());
1204 	} finally {
1205 		deleteProject("P");
1206 		VariablesInitializer.reset();
1207 	}
1208 }
1209 /*
1210  * Ensures that if the initializer doesn't initialize a variable, it can be
1211  * initialized later on.
1212  */
testVariableInitializer06()1213 public void testVariableInitializer06() throws CoreException {
1214 	try {
1215 		final StringBuffer buffer = new StringBuffer();
1216 		VariablesInitializer.setInitializer(new VariablesInitializer.ITestInitializer() {
1217 			@Override
1218 			public void initialize(String variable) {
1219 				// do nothing
1220 				buffer.append("Ignoring request to initialize");
1221 			}
1222 		});
1223 		IPath path = JavaCore.getClasspathVariable("TEST_SRC");
1224 		assertEquals(
1225 			"Unexpected value of TEST_SRC after initializer was called",
1226 			null,
1227 			path);
1228 		IPath varValue = new Path("src.zip");
1229 		JavaCore.setClasspathVariable("TEST_SRC", varValue, null);
1230 		path = JavaCore.getClasspathVariable("TEST_SRC");
1231 		assertEquals(
1232 			"Unexpected value of TEST_SRC after setting it",
1233 			varValue,
1234 			path);
1235 	} finally {
1236 		VariablesInitializer.reset();
1237 	}
1238 }
testVariableInitializer07()1239 public void testVariableInitializer07() throws CoreException {
1240 	try {
1241 		createProject("P1");
1242 		createFile("/P1/lib.jar", "");
1243 		createFile("/P1/src.zip", "");
1244 		String[] variableValues = new String[] {
1245 			"TEST_LIB", "/P1/lib.jar",
1246 			"TEST_SRC", "/P1/src.zip",
1247 			"TEST_ROOT", "src",
1248 		};
1249 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(variableValues));
1250 		createJavaProject("P2", new String[] {}, new String[] {"TEST_LIB,TEST_SRC,TEST_ROOT"}, "");
1251 
1252 		// change value of TEST_LIB
1253 		createFile("/P1/lib2.jar", "");
1254 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] {
1255 			"TEST_LIB", "/P1/lib2.jar",
1256 			"TEST_SRC", "/P1/src.zip",
1257 			"TEST_ROOT", "src",
1258 		}));
1259 
1260 		// simulate state on startup
1261 		simulateExitRestart();
1262 
1263 		startDeltas();
1264 		//JavaModelManager.CP_RESOLVE_VERBOSE=true;
1265 		getJavaProject("P2").getResolvedClasspath(true);
1266 
1267 		assertDeltas(
1268 			"Unexpected delta on startup",
1269 			"P2[*]: {CHILDREN | RESOLVED CLASSPATH CHANGED}\n" +
1270 			"	/P1/lib.jar[*]: {REMOVED FROM CLASSPATH}\n" +
1271 			"	/P1/lib2.jar[*]: {ADDED TO CLASSPATH}"
1272 		);
1273 	} finally {
1274 		//JavaModelManager.CP_RESOLVE_VERBOSE=false;
1275 		stopDeltas();
1276 		deleteProject("P1");
1277 		deleteProject("P2");
1278 		VariablesInitializer.reset();
1279 	}
1280 }
1281 /*
1282  * Ensure that an OperationCanceledException goes through
1283  * (regression test for bug 59363 Should surface cancellation exceptions)
1284  */
1285 
testVariableInitializer08()1286 public void testVariableInitializer08() throws CoreException {
1287 	try {
1288 		boolean gotException = false;
1289 		try {
1290 			VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] {"TEST_LIB", "/P1/lib.jar"}) {
1291 				@Override
1292 				public void initialize(String variable) throws JavaModelException {
1293 					throw new OperationCanceledException("test");
1294 				}
1295 			});
1296 			IJavaProject p1 = createJavaProject("P1", new String[] {}, new String[] {"TEST_LIB"}, "");
1297 			p1.getResolvedClasspath(true);
1298 		} catch (OperationCanceledException e) {
1299 			gotException = true;
1300 		}
1301 		assertTrue("Should get an OperationCanceledException", gotException);
1302 	} finally {
1303 		deleteProject("P1");
1304 		VariablesInitializer.reset();
1305 	}
1306 }
1307 
1308 /*
1309  * Ensure that removing a classpath variable while initializing it doesn't throw a StackOverFlowError
1310  * (regression test for bug 112609 StackOverflow when initializing Java Core)
1311  */
testVariableInitializer09()1312 public void testVariableInitializer09() throws CoreException {
1313 	try {
1314 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] {"TEST_LIB", "/P1/lib.jar"}) {
1315 			@Override
1316 			public void initialize(String variable) throws JavaModelException {
1317 				JavaCore.removeClasspathVariable("TEST_LIB", null);
1318 			}
1319 		});
1320 		IJavaProject p1 = createJavaProject("P1", new String[] {}, new String[] {"TEST_LIB"}, "");
1321 		IClasspathEntry[] resolvedClasspath = p1.getResolvedClasspath(true);
1322 		assertClasspathEquals(
1323 			resolvedClasspath,
1324 			""
1325 		);
1326 	} finally {
1327 		deleteProject("P1");
1328 		VariablesInitializer.reset();
1329 	}
1330 }
1331 /*
1332  * Ensures that not initializing a classpath variable and asking for its value returns null
1333  * (regression test for bug 113110 TestFailures in DebugSuite)
1334  */
testVariableInitializer10()1335 public void testVariableInitializer10() throws CoreException {
1336 	try {
1337 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] {"TEST_LIB", "/P1/lib.jar"}) {
1338 			@Override
1339 			public void initialize(String variable) throws JavaModelException {
1340 				// don't initialize
1341 			}
1342 		});
1343 		// force resolution
1344 		JavaCore.getClasspathVariable("TEST_LIB");
1345 		// second call should still be null
1346 		assertEquals("TEST_LIB should be null", null, JavaCore.getClasspathVariable("TEST_LIB"));
1347 	} finally {
1348 		deleteProject("P1");
1349 		VariablesInitializer.reset();
1350 	}
1351 }
1352 /**
1353  * Bug 125965: [prefs] "Export/Import preferences" should let user to choose wich preference to export/import
1354  * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=125965"
1355  */
testVariableInitializer11()1356 public void testVariableInitializer11() throws CoreException {
1357 	try {
1358 		// Create initializer
1359 		String varName = "TEST_LIB";
1360 		String initialValue = "/P1/lib.jar";
1361 		String newValue = "/tmp/file.jar";
1362 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] {varName, initialValue}));
1363 		assertEquals("JavaCore classpath value should have been initialized", JavaCore.getClasspathVariable(varName).toString(), initialValue);
1364 
1365 		// Modify preference
1366 		JavaModelManager manager = JavaModelManager.getJavaModelManager();
1367 		IEclipsePreferences preferences = manager.getInstancePreferences();
1368 		preferences.put(JavaModelManager.CP_VARIABLE_PREFERENCES_PREFIX+varName, newValue);
1369 
1370 		// verify that JavaCore preferences have been reset
1371 		assertEquals("JavaCore classpath value should be unchanged", JavaCore.getClasspathVariable(varName).toString(), initialValue);
1372 		assertEquals("JavaCore preferences value should be unchanged", preferences.get(varName, "X"), initialValue);
1373 	} finally {
1374 		VariablesInitializer.reset();
1375 	}
1376 }
1377 
1378 /**
1379  * @bug 138599: [model][classpath] Need a way to mark a classpath variable as deprecated
1380  * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=138599"
1381  */
testVariableInitializerDeprecated()1382 public void testVariableInitializerDeprecated() throws CoreException, IOException {
1383 	try {
1384 		// Create initializer
1385 		String varName = "TEST_DEPRECATED";
1386 		String filePath = "/P1/lib.jar";
1387 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] {varName, filePath}));
1388 		assertEquals("JavaCore classpath value should have been initialized", JavaCore.getClasspathVariable(varName).toString(), filePath);
1389 
1390 		// Verify that Classpath Variable is deprecated
1391 		assertEquals("JavaCore classpath variable should be deprecated", "Test deprecated flag", JavaCore.getClasspathVariableDeprecationMessage(varName));
1392 
1393 		// Create project
1394 		IJavaProject project = createJavaProject("P1");
1395 		addLibrary(project, "lib.jar", null, new String[0],
1396 				new String[]{"META-INF/MANIFEST.MF",
1397 					"Manifest-Version: 1.0\n"} ,
1398 					JavaCore.VERSION_1_4);
1399 		IClasspathEntry variable = JavaCore.newVariableEntry(new Path("TEST_DEPRECATED"), null, null);
1400 		IJavaModelStatus status = JavaConventions.validateClasspathEntry(project, variable, false);
1401 		assertStatus("Classpath variable 'TEST_DEPRECATED' in project 'P1' is deprecated: Test deprecated flag", status);
1402 		assertFalse("Status should not be OK", status.isOK());
1403 		assertEquals("Status should have WARNING severity", IStatus.WARNING, status.getSeverity());
1404 		assertEquals("Status should have deprecated code", IJavaModelStatusConstants.DEPRECATED_VARIABLE, status.getCode());
1405 	} finally {
1406 		VariablesInitializer.reset();
1407 		deleteProject("P1");
1408 	}
1409 }
testVariableInitializerUnboundAndDeprecated()1410 public void testVariableInitializerUnboundAndDeprecated() throws CoreException {
1411 	try {
1412 		// Create initializer
1413 		String varName = "TEST_DEPRECATED";
1414 		String filePath = "/P1/lib.jar";
1415 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] {varName, filePath}));
1416 		assertEquals("JavaCore classpath value should have been initialized", JavaCore.getClasspathVariable(varName).toString(), filePath);
1417 
1418 		// Verify that Classpath Variable is deprecated
1419 		assertEquals("JavaCore classpath variable should be deprecated", "Test deprecated flag", JavaCore.getClasspathVariableDeprecationMessage(varName));
1420 
1421 		// Create project
1422 		IJavaProject project = createJavaProject("P1");
1423 		IClasspathEntry variable = JavaCore.newVariableEntry(new Path("TEST_DEPRECATED"), null, null);
1424 		IJavaModelStatus status = JavaConventions.validateClasspathEntry(project, variable, false);
1425 		assertStatus("Project 'P1' is missing required library: 'lib.jar'", status);
1426 		assertFalse("Status should not be OK", status.isOK());
1427 		assertEquals("Status should have WARNING severity", IStatus.ERROR, status.getSeverity());
1428 		assertEquals("Status should have deprecated code", IJavaModelStatusConstants.INVALID_CLASSPATH, status.getCode());
1429 	} finally {
1430 		VariablesInitializer.reset();
1431 		deleteProject("P1");
1432 	}
1433 }
1434 
1435 /**
1436  * @bug 156226: [model][classpath] Allow classpath variable to be marked as non modifiable
1437  * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=156226"
1438  */
testVariableInitializerReadOnly()1439 public void testVariableInitializerReadOnly() throws CoreException, IOException {
1440 	try {
1441 		// Create initializer
1442 		String varName = "TEST_READ_ONLY";
1443 		String path = "/P1/lib.jar";
1444 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] { varName, path }));
1445 		assertEquals("JavaCore classpath value should have been initialized", JavaCore.getClasspathVariable(varName).toString(), path);
1446 
1447 		// verify that Classpath Variable is read-only
1448 		assertTrue("JavaCore classpath variable should be read-only", JavaCore.isClasspathVariableReadOnly(varName));
1449 
1450 		// Create project
1451 		IJavaProject project = createJavaProject("P1");
1452 		addLibrary(project, "lib.jar", null, new String[0],
1453 				new String[]{"META-INF/MANIFEST.MF",
1454 					"Manifest-Version: 1.0\n"} ,
1455 					JavaCore.VERSION_1_4);
1456 		IClasspathEntry variable = JavaCore.newVariableEntry(new Path("TEST_READ_ONLY"), null, null);
1457 		IJavaModelStatus status = JavaConventions.validateClasspathEntry(project, variable, false);
1458 		assertStatus("OK", status);
1459 		assertTrue("Status should be OK", status.isOK());
1460 		assertEquals("Status should be VERIFIED_OK", JavaModelStatus.VERIFIED_OK, status);
1461 	} finally {
1462 		VariablesInitializer.reset();
1463 		deleteProject("P1");
1464 	}
1465 }
testVariableInitializerDeprecatedAndReadOnly()1466 public void testVariableInitializerDeprecatedAndReadOnly() throws CoreException, IOException {
1467 	try {
1468 		// Create initializer
1469 		String varName = "TEST_DEPRECATED_READ_ONLY";
1470 		String path = "/P1/lib.jar";
1471 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] { varName, path }));
1472 		assertEquals("JavaCore classpath value should have been initialized", JavaCore.getClasspathVariable(varName).toString(), path);
1473 
1474 		// verify that Classpath Variable is read-only
1475 		assertEquals("JavaCore classpath variable should be deprecated", "A deprecated and read-only initializer", JavaCore.getClasspathVariableDeprecationMessage(varName));
1476 		assertTrue("JavaCore classpath variable should be read-only", JavaCore.isClasspathVariableReadOnly(varName));
1477 
1478 		// Create project
1479 		IJavaProject project = createJavaProject("P1");
1480 		addLibrary(project, "lib.jar", null, new String[0],
1481 				new String[]{"META-INF/MANIFEST.MF",
1482 					"Manifest-Version: 1.0\n"} ,
1483 					JavaCore.VERSION_1_4);
1484 		IClasspathEntry variable = JavaCore.newVariableEntry(new Path("TEST_DEPRECATED_READ_ONLY"), null, null);
1485 		IJavaModelStatus status = JavaConventions.validateClasspathEntry(project, variable, false);
1486 		assertStatus("Classpath variable 'TEST_DEPRECATED_READ_ONLY' in project 'P1' is deprecated: A deprecated and read-only initializer", status);
1487 		assertFalse("Status should not be OK", status.isOK());
1488 		assertEquals("Status should have WARNING severity", IStatus.WARNING, status.getSeverity());
1489 		assertEquals("Status should have deprecated code", IJavaModelStatusConstants.DEPRECATED_VARIABLE, status.getCode());
1490 	} finally {
1491 		VariablesInitializer.reset();
1492 		deleteProject("P1");
1493 	}
1494 }
1495 
1496 /**
1497  * @bug 172207: [model] Marker for deprecated classpath variable should always have WARNING severity
1498  * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=172207"
1499  */
testVariableInitializerBug172207()1500 public void testVariableInitializerBug172207() throws CoreException, IOException {
1501 	try {
1502 		// Create initializer
1503 		String varName = "TEST_DEPRECATED_READ_ONLY";
1504 		String path = "/P1/lib.jar";
1505 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] { varName, path }));
1506 		assertEquals("JavaCore classpath value should have been initialized", JavaCore.getClasspathVariable(varName).toString(), path);
1507 
1508 		// verify that Classpath Variable is read-only
1509 		assertEquals("JavaCore classpath variable should be deprecated", "A deprecated and read-only initializer", JavaCore.getClasspathVariableDeprecationMessage(varName));
1510 		assertTrue("JavaCore classpath variable should be read-only", JavaCore.isClasspathVariableReadOnly(varName));
1511 
1512 		// Create project
1513 		IJavaProject project = createJavaProject("P1");
1514 		addLibrary(project, "lib.jar", null, new String[0],
1515 				new String[]{"META-INF/MANIFEST.MF",
1516 					"Manifest-Version: 1.0\n"} ,
1517 					JavaCore.VERSION_1_4);
1518 		IClasspathEntry variable = JavaCore.newVariableEntry(new Path("TEST_DEPRECATED_READ_ONLY"), null, null);
1519 		IClasspathEntry[] entries = project.getRawClasspath();
1520 		int length = entries.length;
1521 		System.arraycopy(entries, 0, entries = new IClasspathEntry[length+1], 0, length);
1522 		entries[length] = variable;
1523 		project.setRawClasspath(entries, null);
1524 
1525 		// verify markers
1526 		waitForAutoBuild();
1527 		IMarker[] markers = project.getProject().findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
1528 		sortMarkers(markers);
1529 		assertMarkers("Unexpected marker(s)",
1530 			"Classpath variable 'TEST_DEPRECATED_READ_ONLY' in project 'P1' is deprecated: A deprecated and read-only initializer",
1531 			markers);
1532 		assertEquals("Marker on deprecated variable should be a WARNING", IMarker.SEVERITY_WARNING, markers[0].getAttribute(IMarker.SEVERITY, -1));
1533 	} finally {
1534 		VariablesInitializer.reset();
1535 		deleteProject("P1");
1536 	}
1537 }
1538 
1539 /**
1540  * @bug 186113: [model] classpath variable deprecation messages not initialized when called
1541  * @test	a) Verify that deprecation message can be get through {@link JavaCore#getClasspathVariableDeprecationMessage(String)}
1542  * 	even if the variable initializer was not called before
1543  * 			b) Verify that message is not stored in cache when variable is not initialized (othwerise we could not free it up...)
1544  * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=186113"
1545  */
testVariableInitializerBug186113a()1546 public void testVariableInitializerBug186113a() throws CoreException {
1547 	assertEquals("Invalid deprecation message!",
1548 		"Test deprecated flag",
1549 		JavaCore.getClasspathVariableDeprecationMessage("TEST_DEPRECATED")
1550 	);
1551 }
testVariableInitializerBug186113b()1552 public void testVariableInitializerBug186113b() throws CoreException {
1553 	JavaCore.getClasspathVariableDeprecationMessage("TEST_DEPRECATED");
1554 	assertNull("Deprecation message should not have been stored!", JavaModelManager.getJavaModelManager().deprecatedVariables.get("TEST_DEPRECATED"));
1555 }
1556 
1557 /**
1558  * @bug 200449: [model] classpath variable deprecation messages not initialized when called
1559  * @test	a) Verify that deprecation message is well stored in cache when variable is iniatialized
1560  * 			b) Verify that deprecation message is well removed in cache when variable is removed
1561  * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=200449"
1562  */
testVariableInitializerBug200449()1563 public void testVariableInitializerBug200449() throws CoreException {
1564 	try {
1565 		// Create initializer
1566 		String varName = "TEST_DEPRECATED";
1567 		String filePath = "/P1/lib.jar";
1568 		VariablesInitializer.setInitializer(new DefaultVariableInitializer(new String[] {varName, filePath}));
1569 		JavaCore.getClasspathVariable(varName); // init variable
1570 
1571 		// Verify that deprecation message has been stored
1572 		assertNotNull("Deprecation message should have been stored!", JavaModelManager.getJavaModelManager().deprecatedVariables.get("TEST_DEPRECATED"));
1573 	} finally {
1574 		VariablesInitializer.reset();
1575 		deleteProject("P1");
1576 	}
1577 }
testVariableInitializerBug200449b()1578 public void testVariableInitializerBug200449b() throws CoreException {
1579 	// Verify that deprecated variable has been removed
1580 	assertNull("Deprecation message should have been removed!", JavaModelManager.getJavaModelManager().deprecatedVariables.get("TEST_DEPRECATED"));
1581 }
1582 
1583 /**
1584  * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=61872"
1585  */
testUserLibraryInitializer1()1586 public void testUserLibraryInitializer1() throws Exception {
1587 	try {
1588 		// Create new user library "SWT"
1589 		ClasspathContainerInitializer initializer= JavaCore.getClasspathContainerInitializer(JavaCore.USER_LIBRARY_CONTAINER_ID);
1590 		String libraryName = "SWT";
1591 		IPath containerPath = new Path(JavaCore.USER_LIBRARY_CONTAINER_ID);
1592 		UserLibraryClasspathContainer containerSuggestion = new UserLibraryClasspathContainer(libraryName);
1593 		initializer.requestClasspathContainerUpdate(containerPath.append(libraryName), null, containerSuggestion);
1594 
1595 		// Create java project
1596 		createJavaProject("p61872");
1597 		IFile jarFile = createFile("/p61872/swt.jar", "");
1598 		IFile srcFile = createFile("/p61872/swtsrc.zip", "");
1599 
1600 		// Modify user library
1601 		IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID);
1602 		String propertyName = JavaModelManager.CP_USERLIBRARY_PREFERENCES_PREFIX+"SWT";
1603 		StringBuffer propertyValue = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<userlibrary systemlibrary=\"false\" version=\"1\">\r\n<archive");
1604 		String jarFullPath = getWorkspaceRoot().getLocation().append(jarFile.getFullPath()).toString();
1605 		propertyValue.append(" path=\""+jarFullPath);
1606 		propertyValue.append("\"/>\r\n</userlibrary>\r\n");
1607 		preferences.put(propertyName, propertyValue.toString());
1608 		preferences.flush();
1609 
1610 		// Modify project classpath
1611 		editFile(
1612 			"/p61872/.classpath",
1613 			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
1614 			"<classpath>\n" +
1615 			"	<classpathentry kind=\"con\" path=\"org.eclipse.jdt.USER_LIBRARY/SWT\"/>\n" +
1616 			"	<classpathentry kind=\"output\" path=\"\"/>\n" +
1617 			"</classpath>"
1618 		);
1619 
1620 		// Verify
1621 		IClasspathEntry[] entries = getJavaProject("p61872").getResolvedClasspath(true);
1622 		assertEquals("Invalid entries number in resolved classpath for project p61872!", 1, entries.length);
1623 		assertEquals("Invalid path for project 61872 classpath entry!", jarFullPath.toLowerCase(), entries[0].getPath().toString().toLowerCase());
1624 		assertNull("Project 61872 classpath entry should not have any source attached!", entries[0].getSourceAttachmentPath());
1625 
1626 		// Modify user library
1627 		propertyValue = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<userlibrary systemlibrary=\"false\" version=\"1\">\r\n<archive");
1628 		String srcFullPath = getWorkspaceRoot().getLocation().append(srcFile.getFullPath()).toString();
1629 		propertyValue.append(" sourceattachment=\""+srcFullPath);
1630 		propertyValue.append("\" path=\""+jarFullPath);
1631 		propertyValue.append("\"/>\r\n</userlibrary>\r\n");
1632 		preferences.put(propertyName, propertyValue.toString());
1633 		preferences.flush();
1634 
1635 		// Verify
1636 		entries = getJavaProject("p61872").getResolvedClasspath(true);
1637 		assertEquals("Invalid entries number in resolved classpath for project p61872!", 1, entries.length);
1638 		assertEquals("Invalid path for project 61872 classpath entry!", jarFullPath.toLowerCase(), entries[0].getPath().toString().toLowerCase());
1639 		assertEquals("Invalid source attachement path for project 61872 classpath entry!", srcFullPath.toLowerCase(), entries[0].getSourceAttachmentPath().toString().toLowerCase());
1640 	} finally {
1641 		deleteProject("p61872");
1642 	}
1643 }
1644 /**
1645  * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=346002"
1646  * @throws Exception
1647  */
testBug346002()1648 public void testBug346002() throws Exception {
1649 	ClasspathContainerInitializer initializer = JavaCore.getClasspathContainerInitializer(JavaCore.USER_LIBRARY_CONTAINER_ID);
1650 	String libraryName = "TEST";
1651 	IPath containerPath = new Path(JavaCore.USER_LIBRARY_CONTAINER_ID);
1652 	UserLibraryClasspathContainer containerSuggestion = new UserLibraryClasspathContainer(libraryName);
1653 	initializer.requestClasspathContainerUpdate(containerPath.append(libraryName), null, containerSuggestion);
1654 
1655 	String libPath = "C:/test/test.jar";
1656 
1657 	IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID);
1658 	String propertyName = JavaModelManager.CP_USERLIBRARY_PREFERENCES_PREFIX+ "TEST";
1659 
1660 	StringBuffer propertyValue = new StringBuffer(
1661 			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<userlibrary systemlibrary=\"false\" version=\"2\">\r\n<archive");
1662 	propertyValue.append(" path=\"" + libPath + "\"/>\r\n");
1663 	propertyValue.append("</userlibrary>\r\n");
1664 	preferences.put(propertyName, propertyValue.toString());
1665 
1666 	propertyName = JavaModelManager.CP_USERLIBRARY_PREFERENCES_PREFIX + "INVALID";
1667 	propertyValue = new StringBuffer(
1668 			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<userlibrary systemlibrary=\"false\" version=\"2\">\r\n<archive");
1669 	propertyValue.append(" path=\"\"/>");
1670 	propertyValue.append("</userlibrary>\r\n");
1671 	preferences.put(propertyName, propertyValue.toString());
1672 	preferences.flush();
1673 
1674 	try {
1675 		simulateExitRestart();
1676 
1677 		UserLibrary userLibrary = JavaModelManager.getUserLibraryManager().getUserLibrary(libraryName);
1678 		assertNotNull(userLibrary);
1679 		IPath entryPath = userLibrary.getEntries()[0].getPath();
1680 		assertEquals("Path should be absolute", true, entryPath.isAbsolute());
1681 
1682 		userLibrary = JavaModelManager.getUserLibraryManager().getUserLibrary("INVALID");
1683 		assertNull(userLibrary);
1684 	}
1685 	catch (ClasspathEntry.AssertionFailedException e) {
1686 		fail("Should not throw AssertionFailedException");
1687 	}
1688 }
1689 
1690 /*
1691  * Ensures that when multiple threads enter the batch container initialization,
1692  * a second thread does not initialize a container if the first thread has already completed it
1693  */
testBug525597()1694 public void testBug525597() throws CoreException {
1695 	try {
1696 		createProject("P1");
1697 		createFile("/P1/lib.jar", "");
1698 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar", "P3", "/P1/lib.jar"}));
1699 		createJavaProject(
1700 				"P2",
1701 				new String[] {},
1702 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
1703 				"");
1704 		createJavaProject(
1705 				"P3",
1706 				new String[] {},
1707 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
1708 				"");
1709 		createJavaProject(
1710 				"P4",
1711 				new String[] {},
1712 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
1713 				"");
1714 
1715 		// simulate state on startup
1716 		simulateExitRestart();
1717 
1718 		Thread helperThread = new Thread() {
1719 			@Override
1720 				public void run() {
1721 					try {
1722 						JavaModelManager javaModelManager = JavaModelManager.getJavaModelManager();
1723 						javaModelManager.containerRemove(null);
1724 						javaModelManager.forceBatchInitializations(false);
1725 						javaModelManager.getClasspathContainer(Path.EMPTY, null);
1726 					} catch (JavaModelException e) {
1727 						e.printStackTrace();
1728 					}
1729 				}
1730 		};
1731 		helperThread.setName("ClasspathInitializerTests Helper");
1732 		AtomicInteger p3Counter=new AtomicInteger(0);
1733 		Thread mainThread=Thread.currentThread();
1734 		Semaphore s1=new Semaphore(0);
1735 		Semaphore s2=new Semaphore(0);
1736 
1737 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar", "P3", "/P1/lib.jar"}) {
1738 			@Override
1739 			public void initialize(IPath containerPath, IJavaProject project) throws CoreException {
1740 				if (Thread.currentThread() == helperThread) {
1741 					if (project.getElementName().equals("P2")) {
1742 						s1.release();
1743 						try {
1744 							s2.acquire(10000);
1745 						} catch (TimeOutException e) {
1746 							// ignore
1747 						}
1748 					} else if (project.getElementName().equals("P3")) {
1749 						p3Counter.incrementAndGet();
1750 					}
1751 				} else if (Thread.currentThread() == mainThread) {
1752 					if (project.getElementName().equals("P3")) {
1753 						p3Counter.incrementAndGet();
1754 					} else if (project.getElementName().equals("P4")) {
1755 						// this point is reached when helperThread is still waiting in P2
1756 						// and already has P3 on its TODO list.
1757 						s2.release();
1758 					}
1759 				}
1760 				super.initialize(containerPath, project);
1761 			}
1762 		});
1763 		helperThread.start();
1764 		// wait till helperThread has reached initializer
1765 		try {
1766 			s1.acquire(10000);
1767 		} catch (TimeOutException e1) {
1768 			// ignore
1769 		}
1770 		JavaModelManager.getJavaModelManager().getClasspathContainer(Path.EMPTY, null);
1771 		try {
1772 			helperThread.join();
1773 		} catch (InterruptedException e) {
1774 			e.printStackTrace();
1775 		}
1776 		assertEquals("P3 initialized more than once.", 1, p3Counter.get());
1777 	} finally {
1778 		deleteProject("P1");
1779 		deleteProject("P2");
1780 		deleteProject("P3");
1781 		deleteProject("P4");
1782 	}
1783 }
1784 /*
1785  * Ensures that when multiple threads enter the batch container initialization,
1786  * and two threads both initialize a container, only one result is used.
1787  */
testBug525597B()1788 public void testBug525597B() throws CoreException {
1789 	try {
1790 		createProject("P1");
1791 		createFile("/P1/lib.jar", "");
1792 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar", "P3", "/P1/lib.jar"}));
1793 		createJavaProject(
1794 				"P2",
1795 				new String[] {},
1796 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
1797 				"");
1798 		createJavaProject(
1799 				"P3",
1800 				new String[] {},
1801 				new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"},
1802 				"");
1803 
1804 		// simulate state on startup
1805 		simulateExitRestart();
1806 
1807 		Thread helperThread = new Thread() {
1808 			@Override
1809 				public void run() {
1810 					try {
1811 						JavaModelManager javaModelManager = JavaModelManager.getJavaModelManager();
1812 						javaModelManager.containerRemove(null);
1813 						javaModelManager.forceBatchInitializations(false);
1814 						javaModelManager.getClasspathContainer(Path.EMPTY, null);
1815 					} catch (JavaModelException e) {
1816 						e.printStackTrace();
1817 					}
1818 				}
1819 		};
1820 		helperThread.setName("ClasspathInitializerTests Helper");
1821 		AtomicInteger p2Counter=new AtomicInteger(0);
1822 		AtomicReference<IClasspathContainer> helperContainer=new AtomicReference<>();
1823 		AtomicReference<IClasspathContainer> mainContainer=new AtomicReference<>();
1824 		Thread mainThread=Thread.currentThread();
1825 		Semaphore s1=new Semaphore(0);
1826 		Semaphore s2=new Semaphore(0);
1827 		Semaphore s3=new Semaphore(0);
1828 		Semaphore s4=new Semaphore(0);
1829 		AtomicReference<IJavaProject> p2Project=new AtomicReference<>();
1830 
1831 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar", "P3", "/P1/lib.jar"}) {
1832 			@Override
1833 			public void initialize(IPath containerPath, IJavaProject project) throws CoreException {
1834 				if (Thread.currentThread() == helperThread) {
1835 					if (project.getElementName().equals("P2")) {
1836 						p2Project.set(project);
1837 						s1.release();
1838 						try {
1839 							s2.acquire(10000);
1840 						} catch (TimeOutException e) {
1841 							// ignore
1842 						}
1843 					} else if (project.getElementName().equals("P3")) {
1844 						s3.release();
1845 						try {
1846 							s4.acquire(10000);
1847 						} catch (TimeOutException e) {
1848 							// ignore
1849 						}
1850 						if (JavaModelManager.getJavaModelManager().containerBeingInitializedGet(p2Project.get(),
1851 								containerPath) != null) {
1852 							p2Counter.incrementAndGet();
1853 						}
1854 						helperContainer.set(JavaModelManager.getJavaModelManager().getClasspathContainer(containerPath, p2Project.get()));
1855 					}
1856 				} else if (Thread.currentThread() == mainThread) {
1857 					if (project.getElementName().equals("P2")) {
1858 						// this point is reached when helperThread is also still waiting in P2
1859 						s2.release();
1860 					} else if (project.getElementName().equals("P3")) {
1861 						try {
1862 							s3.acquire(10000);
1863 						} catch (TimeOutException e) {
1864 							// ignore
1865 						}
1866 						s4.release();
1867 						if (JavaModelManager.getJavaModelManager().containerBeingInitializedGet(p2Project.get(),
1868 								containerPath) != null) {
1869 							p2Counter.incrementAndGet();
1870 						}
1871 						mainContainer.set(JavaModelManager.getJavaModelManager().getClasspathContainer(containerPath, p2Project.get()));
1872 					}
1873 				}
1874 				super.initialize(containerPath, project);
1875 			}
1876 		});
1877 		helperThread.start();
1878 		// wait till helperThread has reached initializer
1879 		try {
1880 			s1.acquire(10000);
1881 		} catch (TimeOutException e1) {
1882 			// ignore
1883 		}
1884 		JavaModelManager.getJavaModelManager().getClasspathContainer(Path.EMPTY, null);
1885 		try {
1886 			helperThread.join();
1887 		} catch (InterruptedException e) {
1888 			e.printStackTrace();
1889 		}
1890 		assertEquals("more than one result for P2 used.", 1, p2Counter.get());
1891 		assertEquals("main and helper threads did not see the same container.", helperContainer.get(), mainContainer.get());
1892 	} finally {
1893 		deleteProject("P1");
1894 		deleteProject("P2");
1895 		deleteProject("P3");
1896 	}
1897 }
1898 
1899 }
1900