R3_6Maintenance: Fix for 372687:org.eclipse.jdt.core.LRUCache.get(Object
key) returns an empty list from a class that has methods
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClassFileTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClassFileTests.java
index f2afc82..ce676c1 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClassFileTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClassFileTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2012 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
@@ -1543,5 +1543,46 @@
 		assertStringsEqual("Type parameter bounds signatures", 
 							"TT;\n", typeParam.getBoundsSignatures());
 	}
-
+	
+	/*
+	 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=372687
+	 * Ensures that if more than one thread try to open a class file at the same time, the children are correct.
+	 */
+	public void testBug372687() throws CoreException {
+		String expected = "X.class\n" + 
+						  "  class X\n" + 
+						  "    X()\n" + 
+						  "    void foo()";
+		class GetClassThread extends Thread {
+			public String childString;
+			public void run(){
+				IClassFile clazz = ClassFileTests.this.jarRoot.getPackageFragment("workingcopy").getClassFile("X.class");
+				try {
+					this.childString = expandAll(clazz);
+				} catch (CoreException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		for (int i = 0; i < 10; i++) {
+			GetClassThread th1 = new GetClassThread();
+			GetClassThread th2 = new GetClassThread();
+			GetClassThread th3 = new GetClassThread();
+			th1.start();
+			th2.start();
+			th3.start();
+			try {
+				th1.join();
+				th2.join();
+				th3.join();
+			} catch (InterruptedException e) {
+				// ignore
+			}
+			assertEquals("Unexpected children", expected, th1.childString);
+			assertEquals("Unexpected children", expected, th2.childString);
+			assertEquals("Unexpected children", expected, th3.childString);
+			IClassFile clazz = ClassFileTests.this.jarRoot.getPackageFragment("workingcopy").getClassFile("X.class");
+			clazz.close();
+		}
+	}
 }
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
index a2a1d5e..5905aa8 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2011 IBM Corporation and others.
+# Copyright (c) 2000, 2012 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
@@ -15,8 +15,8 @@
 #Format: compiler.name = word1 word2 word3
 compiler.name = Eclipse Compiler for Java(TM)
 #Format: compiler.version = 0.XXX[, other words (don't forget the comma if adding other words)]
-compiler.version = 0.A80_R36x, 3.6.4
-compiler.copyright = Copyright IBM Corp 2000, 2011. All rights reserved.
+compiler.version = 0.A81_R36x, 3.6.4
+compiler.copyright = Copyright IBM Corp 2000, 2012. All rights reserved.
 
 ### progress
 progress.compiling = Compiling
diff --git a/org.eclipse.jdt.core/buildnotes_jdt-core.html b/org.eclipse.jdt.core/buildnotes_jdt-core.html
index 73aa7be..b790af6 100644
--- a/org.eclipse.jdt.core/buildnotes_jdt-core.html
+++ b/org.eclipse.jdt.core/buildnotes_jdt-core.html
@@ -40,6 +40,21 @@
 	</td>
   </tr>
 </table>
+<a name="v_A81_R36x"></a>
+<hr><h1>
+Eclipse Platform Build Notes<br>
+Java development tools core</h1>
+Eclipse SDK 3.6.4 - %date% - April 13, 2012
+<br>Project org.eclipse.jdt.core v_A81_R36x
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_A81_R36x">cvs</a>).
+<h2>What's new in this drop</h2>
+
+<h3>Problem Reports Fixed</h3>
+<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=372687">372687</a>
+org.eclipse.jdt.core.LRUCache.get(Object key) returns an empty list from a class that has methods
+<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=185601">185601</a>
+.apt_generated is not restored as a source folder
+
 <a name="v_A80_R36x"></a>
 <hr><h1>
 Eclipse Platform Build Notes<br>
@@ -57,7 +72,7 @@
 <hr><h1>
 Eclipse Platform Build Notes<br>
 Java development tools core</h1>
-Eclipse SDK 3.6.4 - October 21, 2011
+Eclipse SDK 3.6.4
 <br>Project org.eclipse.jdt.core v_A79_R36x
 (<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_A79_R36x">cvs</a>).
 <h2>What's new in this drop</h2>
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BecomeWorkingCopyOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BecomeWorkingCopyOperation.java
index a132158..7f5be9a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BecomeWorkingCopyOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BecomeWorkingCopyOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2012 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
@@ -35,7 +35,7 @@
 		// open the working copy now to ensure contents are that of the current state of this element
 		CompilationUnit workingCopy = getWorkingCopy();
 		JavaModelManager.getJavaModelManager().getPerWorkingCopyInfo(workingCopy, true/*create if needed*/, true/*record usage*/, this.problemRequestor);
-		workingCopy.openWhenClosed(workingCopy.createElementInfo(), this.progressMonitor);
+		workingCopy.openWhenClosed(workingCopy.createElementInfo(), true, this.progressMonitor);
 
 		if (!workingCopy.isPrimary()) {
 			// report added java delta for a non-primary working copy
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
index ef32aad..d89361a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2012 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
@@ -283,7 +283,7 @@
 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
 	Object info = manager.getInfo(this);
 	if (info != null && info != JavaModelCache.NON_EXISTING_JAR_TYPE_INFO) return info;
-	return openWhenClosed(createElementInfo(), monitor);
+	return openWhenClosed(createElementInfo(), false, monitor);
 }
 /*
  * @see IJavaElement
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
index 2d62037..2231ac1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2012 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
@@ -1076,12 +1076,12 @@
 			info.resolveBindings = resolveBindings;
 			info.reconcileFlags = reconcileFlags;
 			info.problems = problems;
-			openWhenClosed(info, monitor);
+			openWhenClosed(info, true, monitor);
 			org.eclipse.jdt.core.dom.CompilationUnit result = info.ast;
 			info.ast = null;
 			return result;
 		} else {
-			openWhenClosed(createElementInfo(), monitor);
+			openWhenClosed(createElementInfo(), true, monitor);
 			return null;
 		}
 	} finally {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
index dd1afbf..13669d2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2012 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
@@ -249,7 +249,7 @@
 		JavaModelManager manager = JavaModelManager.getJavaModelManager();
 		Object info = manager.getInfo(this);
 		if (info != null) return info;
-		return openWhenClosed(createElementInfo(), monitor);
+		return openWhenClosed(createElementInfo(), false, monitor);
 	}
 	/**
 	 * @see IAdaptable
@@ -507,7 +507,7 @@
 	 * Opens an <code>Openable</code> that is known to be closed (no check for <code>isOpen()</code>).
 	 * Returns the created element info.
 	 */
-	protected Object openWhenClosed(Object info, IProgressMonitor monitor) throws JavaModelException {
+	protected Object openWhenClosed(Object info, boolean forceAdd, IProgressMonitor monitor) throws JavaModelException {
 		JavaModelManager manager = JavaModelManager.getJavaModelManager();
 		boolean hadTemporaryCache = manager.hasTemporaryCache();
 		try {
@@ -526,7 +526,7 @@
 				throw newNotPresentException();
 			}
 			if (!hadTemporaryCache) {
-				manager.putInfos(this, newElements);
+				manager.putInfos(this, info, forceAdd, newElements);
 			}
 		} finally {
 			if (!hadTemporaryCache) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
index b5a0313..8744967 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2012 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
@@ -3446,13 +3446,26 @@
 	public void prepareToSave(ISaveContext context) /*throws CoreException*/ {
 		// nothing to do
 	}
+	
 	/*
 	 * Puts the infos in the given map (keys are IJavaElements and values are JavaElementInfos)
-	 * in the Java model cache in an atomic way.
+	 * in the Java model cache in an atomic way if the info is not already present in the cache. 
+	 * If the info is already present in the cache, it depends upon the forceAdd parameter.
+	 * If forceAdd is false it just returns the existing info and if true, this element and it's children are closed and then 
+	 * this particular info is added to the cache.
 	 */
-	protected synchronized void putInfos(IJavaElement openedElement, Map newElements) {
+	protected synchronized Object putInfos(IJavaElement openedElement, Object newInfo, boolean forceAdd, Map newElements) {
 		// remove existing children as the are replaced with the new children contained in newElements
 		Object existingInfo = this.cache.peekAtInfo(openedElement);
+		if (existingInfo != null && !forceAdd) {
+			// If forceAdd is false, then it could mean that the particular element 
+			// wasn't in cache at that point of time, but would have got added through 
+			// another thread. In that case, removing the children could remove it's own
+			// children. So, we should not remove the children but return the already existing 
+			// info.
+			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=372687
+			return existingInfo;
+		}
 		if (openedElement instanceof IParent) {
 			closeChildren(existingInfo);
 		}
@@ -3482,6 +3495,7 @@
 			Map.Entry entry = (Map.Entry) iterator.next();
 			this.cache.putInfo((IJavaElement) entry.getKey(), entry.getValue());
 		}
+		return newInfo;
 	}
 
 	private void closeChildren(Object info) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
index 9fb59c6..b9f4ce4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2012 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
@@ -485,7 +485,7 @@
 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
 	PackageFragmentRootInfo info = (PackageFragmentRootInfo) manager.peekAtInfo(this);
 	if (info == null) {
-		info = (PackageFragmentRootInfo) openWhenClosed(createElementInfo(), null);
+		info = (PackageFragmentRootInfo) openWhenClosed(createElementInfo(), false, null);
 	}
 	return info.getRootKind();
 }