Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/permadmin/SecurityTable.java')
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/permadmin/SecurityTable.java143
1 files changed, 110 insertions, 33 deletions
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 bdd1c188c..43dc91154 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
@@ -7,13 +7,18 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Connexta, LLC - evaluation cache implementation
*******************************************************************************/
package org.eclipse.osgi.internal.permadmin;
import java.security.Permission;
import java.security.PermissionCollection;
import java.util.Enumeration;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
import org.eclipse.osgi.internal.permadmin.SecurityRow.Decision;
+import org.osgi.service.condpermadmin.Condition;
public class SecurityTable extends PermissionCollection {
private static final long serialVersionUID = -1800193310096318060L;
@@ -22,9 +27,14 @@ public class SecurityTable extends PermissionCollection {
static final int ABSTAIN = 0x0004;
static final int POSTPONED = 0x0008;
+ private static final int MUTABLE = 0x0016;
+
private final SecurityRow[] rows;
private final SecurityAdmin securityAdmin;
+ private final transient Map<EvaluationCacheKey, Integer> evaluationCache =
+ new ConcurrentHashMap<>(10000);
+
public SecurityTable(SecurityAdmin securityAdmin, SecurityRow[] rows) {
if (rows == null)
throw new NullPointerException("rows cannot be null!!"); //$NON-NLS-1$
@@ -37,63 +47,130 @@ public class SecurityTable extends PermissionCollection {
}
int evaluate(BundlePermissions bundlePermissions, Permission permission) {
- if (isEmpty())
+ if (bundlePermissions == null) {
return ABSTAIN;
+ }
+ EvaluationCacheKey evaluationCacheKey = new EvaluationCacheKey(bundlePermissions,
+ permission);
+ if (isEmpty()) {
+ evaluationCache.put(evaluationCacheKey, ABSTAIN);
+ return ABSTAIN;
+ }
+
+ //can't short-circuit early, so try cache
+ Integer result = evaluationCache.get(evaluationCacheKey);
+ boolean hasMutable = false;
+ if (result != null) {
+ hasMutable = (result & MUTABLE) == MUTABLE;
+ if (!hasMutable) {
+ return result;
+ }
+ }
+ //cache miss or has mutable rows
boolean postponed = false;
Decision[] results = new Decision[rows.length];
int immediateDecisionIdx = -1;
// evaluate each row
- for (int i = 0; i < rows.length; i++) {
+ for (int i = 0; i < rows.length && immediateDecisionIdx == -1; i++) {
+ if (result == null) {
+ //check all conditions for any that are mutable, this will turn off the cache
+ hasMutable |= checkMutable(bundlePermissions,
+ evaluationCacheKey,
+ rows[i]);
+ }
try {
results[i] = rows[i].evaluate(bundlePermissions, permission);
- } catch (Throwable t) {
+ } catch (Exception e) {
// TODO log?
results[i] = SecurityRow.DECISION_ABSTAIN;
}
- if ((results[i].decision & ABSTAIN) != 0)
+ if ((results[i].decision & ABSTAIN) == ABSTAIN)
continue; // ignore this row and continue to next row
- if ((results[i].decision & POSTPONED) != 0) {
+ if ((results[i].decision & POSTPONED) == POSTPONED) {
// row is postponed; we can no longer return quickly on a denied decision
postponed = true;
continue; // continue to next row
}
- if (!postponed)
+ if (!postponed) {
// no postpones encountered yet; we can return the decision quickly
+ if (!hasMutable) {
+ evaluationCache.put(evaluationCacheKey, results[i].decision);
+ }
return results[i].decision; // return GRANTED or DENIED
+ }
// got an immediate answer; but it is after a postponed condition.
// no need to process the rest of the rows
immediateDecisionIdx = i;
- break;
}
- if (postponed) {
- int immediateDecision = immediateDecisionIdx < 0 ? DENIED : results[immediateDecisionIdx].decision;
- // iterate over all postponed conditions;
- // if they all provide the same decision as the immediate decision then return the immediate decision
- boolean allSameDecision = true;
- int i = immediateDecisionIdx < 0 ? results.length - 1 : immediateDecisionIdx - 1;
- for (; i >= 0 && allSameDecision; i--) {
- if (results[i] == null)
- continue;
- if ((results[i].decision & POSTPONED) != 0) {
- if ((results[i].decision & immediateDecision) == 0)
- allSameDecision = false;
- else
- results[i] = SecurityRow.DECISION_ABSTAIN; // we can clear postpones with the same decision as the immediate
+ Integer immediateDecision = handlePostponedConditions(evaluationCacheKey,
+ hasMutable,
+ postponed,
+ results,
+ immediateDecisionIdx);
+ if (immediateDecision != null)
+ return immediateDecision;
+ int finalDecision = postponed ? POSTPONED : ABSTAIN;
+ if (!hasMutable && (finalDecision & POSTPONED) != POSTPONED) {
+ evaluationCache.put(evaluationCacheKey, finalDecision);
+ }
+ return finalDecision;
+ }
+
+ private boolean checkMutable(BundlePermissions bundlePermissions,
+ EvaluationCacheKey evaluationCacheKey, SecurityRow row) {
+ Condition[] conditions = row.getConditions(bundlePermissions);
+ if (conditions != null) {
+ for (Condition condition : conditions) {
+ if (condition.isMutable()) {
+ evaluationCache.put(evaluationCacheKey, MUTABLE);
+ return true;
}
}
- if (allSameDecision)
- return immediateDecision;
-
- // we now are forced to postpone; we need to also remember the postponed decisions and
- // the immediate decision if there is one.
- EquinoxSecurityManager equinoxManager = securityAdmin.getSupportedSecurityManager();
- if (equinoxManager == null)
- // TODO this is really an error condition.
- // This should never happen. We checked for a supported manager when the row was postponed
- return ABSTAIN;
- equinoxManager.addConditionsForDomain(results);
}
- return postponed ? POSTPONED : ABSTAIN;
+ return false;
+ }
+
+ private Integer handlePostponedConditions(EvaluationCacheKey evaluationCacheKey,
+ boolean hasMutable, boolean postponed, Decision[] results, int immediateDecisionIdx) {
+ if (postponed) {
+ int immediateDecision = immediateDecisionIdx < 0 ? DENIED : results[immediateDecisionIdx].decision;
+ // iterate over all postponed conditions;
+ // if they all provide the same decision as the immediate decision then return the immediate decision
+ boolean allSameDecision = true;
+ int i = immediateDecisionIdx < 0 ? results.length - 1 : immediateDecisionIdx - 1;
+ for (; i >= 0 && allSameDecision; i--) {
+ if ((results[i].decision & POSTPONED) == POSTPONED) {
+ if ((results[i].decision & immediateDecision) == 0)
+ allSameDecision = false;
+ else
+ results[i] = SecurityRow.DECISION_ABSTAIN; // we can clear postpones with the same decision as the immediate
+ }
+ }
+ if (allSameDecision) {
+ if (!hasMutable) {
+ evaluationCache.put(evaluationCacheKey, immediateDecision);
+ }
+ return immediateDecision;
+ }
+
+ // we now are forced to postpone; we need to also remember the postponed decisions and
+ // the immediate decision if there is one.
+ EquinoxSecurityManager equinoxManager = securityAdmin.getSupportedSecurityManager();
+ if (equinoxManager == null) {
+ // TODO this is really an error condition.
+ // This should never happen. We checked for a supported manager when the row was postponed
+ if (!hasMutable) {
+ evaluationCache.put(evaluationCacheKey, ABSTAIN);
+ }
+ return ABSTAIN;
+ }
+ equinoxManager.addConditionsForDomain(results);
+ }
+ return null;
+ }
+
+ void clearEvaluationCache() {
+ evaluationCache.clear();
}
SecurityRow getRow(int i) {

Back to the top