Bug 571531 - Cap evaluation cache at 10000

Because permission instances can be infinite the evaluationCache can
grow unbounded leading to a memory leak. This is a quick fix to cap the
cache at 10000.  A better approach may be to use some weak reference
cache in the future, but for now we need to stop the uncontrolled leak.

A test is added that does 10 million different file permission checks.
On my system this grinds to a halt after about 8 million checks. With
the cap at 10000 the 10 million permission checks happen <15 seconds.

Change-Id: I6e18d4d6fcab274bb2f56c69a6e0893f8e474418
Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityAdminUnitTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityAdminUnitTests.java
index 3935b9e..5e61766 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityAdminUnitTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityAdminUnitTests.java
@@ -1160,6 +1160,29 @@
 		testPermission(acc, new FilePermission(relativeExecutable.getAbsolutePath(), "execute"), true);
 	}
 
+	public void testPermissionCheckCache() {
+		// test single row with signer condition
+		ConditionalPermissionUpdate update = cpa.newConditionalPermissionUpdate();
+		List rows = update.getConditionalPermissionInfos();
+		rows.add(cpa.newConditionalPermissionInfo(null, new ConditionInfo[] { SIGNER_CONDITION1 }, READONLY_INFOS,
+				ConditionalPermissionInfo.ALLOW));
+		assertTrue("failed to commit", update.commit()); //$NON-NLS-1$
+
+		AccessControlContext acc = cpa.getAccessControlContext(new String[] { "cn=t1,c=FR;cn=test1,c=US" }); //$NON-NLS-1$
+
+		for (int i = 0; i < 10000000; i++) {
+			try {
+				if (i % 1000 == 0) {
+					System.out.println("i=" + i);
+				}
+				acc.checkPermission(new FilePermission("test" + i, "read")); //$NON-NLS-1$ //$NON-NLS-2$
+			} catch (AccessControlException e) {
+				fail("Unexpected AccessControlExcetpion", e); //$NON-NLS-1$
+			}
+		}
+
+	}
+
 	private void checkInfos(ConditionalPermissionInfo testInfo1, ConditionalPermissionInfo testInfo2) {
 		assertTrue("Infos are not equal: " + testInfo1.getEncoded() + " " + testInfo2.getEncoded(), testInfo1.equals(testInfo2));
 		assertEquals("Info hash code is not equal", testInfo1.hashCode(), testInfo2.hashCode());
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/permadmin/SecurityTable.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/permadmin/SecurityTable.java
index ff32046..7fc0837 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/permadmin/SecurityTable.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/permadmin/SecurityTable.java
@@ -51,6 +51,9 @@
 		if (bundlePermissions == null) {
 			return ABSTAIN;
 		}
+		if (evaluationCache.size() > 10000) {
+			clearEvaluationCache();
+		}
 		EvaluationCacheKey evaluationCacheKey = new EvaluationCacheKey(bundlePermissions, permission);
 		if (isEmpty()) {
 			evaluationCache.put(evaluationCacheKey, ABSTAIN);