blob: 86aa1e75ddde26c4a0c586a689c095ed08397b4b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.framework.internal.core;
import java.security.Permission;
import java.security.PermissionCollection;
import java.util.Enumeration;
import java.util.Vector;
import org.osgi.framework.FrameworkEvent;
import org.osgi.service.condpermadmin.Condition;
import org.osgi.service.condpermadmin.ConditionalPermissionAdmin;
/**
*
* This class manages the Permissions for a given code source. It tracks the
* permissions that have yet to be satisfied as well as conditions that are
* already satisfied.
*/
public class ConditionalPermissions extends PermissionCollection {
private static final long serialVersionUID = 3907215965749000496L;
private AbstractBundle bundle;
/**
* This is the list of satisfiedCPIs that we are waiting to process in bulk
* when evaluating the satisfied permissions. Elements are of type
* ConditionalPermissionInfoImpl.
*/
private Vector satisfiedCPIs = new Vector();
/**
* This is set contains that ConditionalPermissionInfos that are satisfied
* and immutable.
*/
private ConditionalPermissionSet satisfiedCPS;
/**
* These are the CPIs that may match this CodeSource. Elements are of type
* ConditionalPermissionSet.
*/
private Vector satisfiableCPSs = new Vector();
private boolean empty;
/**
* Constructs a ConditionalPermission for the given bundle.
*
* @param bundle the bundle for which this ConditionalPermission tracks Permissions.
*/
public ConditionalPermissions(AbstractBundle bundle, ConditionalPermissionAdmin cpa) {
this.bundle = bundle;
satisfiedCPS = new ConditionalPermissionSet(bundle, ConditionalPermissionAdminImpl.EMPTY_COND_PERM_INFO, ConditionalPermissionAdminImpl.EMPTY_COND);
Enumeration en = cpa.getConditionalPermissionInfos();
while (en.hasMoreElements()) {
ConditionalPermissionInfoImpl cpi = (ConditionalPermissionInfoImpl) en.nextElement();
checkConditionalPermissionInfo(cpi);
}
}
void checkConditionalPermissionInfo(ConditionalPermissionInfoImpl cpi) {
try {
// first remove the cpi incase of an update
removeCPI(cpi);
Condition conds[] = cpi.getConditions(bundle);
if (conds == null) {
/* Couldn't process the conditions, so we can't use them */
return;
}
boolean satisfied = true;
for (int i = 0; i < conds.length; i++) {
Condition cond = conds[i];
if (cond.isMutable()) {
satisfied = false;
} else if (!cond.isSatisfied()) {// Note: the RFC says if !mutable, evaluated must be true
/*
* We can just dump here since we have an immutable and
* unsatisfied condition.
*/
return;
} else {
conds[i] = null; /* We can remove satisfied conditions */
}
}
if (satisfied) {
satisfiedCPIs.add(cpi);
} else {
satisfiableCPSs.add(new ConditionalPermissionSet(bundle, new ConditionalPermissionInfoImpl[] {cpi}, conds));
}
} catch (Exception e) {
bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, e);
}
}
private void removeCPI(ConditionalPermissionInfoImpl cpi) {
satisfiedCPIs.remove(cpi);
satisfiedCPS.remove(cpi);
ConditionalPermissionSet cpsArray[] = (ConditionalPermissionSet[]) satisfiableCPSs.toArray(new ConditionalPermissionSet[0]);
for (int i = 0; i < cpsArray.length; i++)
if (cpsArray[i].remove(cpi))
satisfiableCPSs.remove(cpsArray[i]);
}
/**
* This method is not implemented since this PermissionCollection should
* only be used by the ConditionalPolicy which never calls this method.
*
* @see java.security.PermissionCollection#elements()
*/
public void add(Permission perm) {
// do nothing
}
public boolean implies(Permission perm) {
processPending();
boolean newEmpty = !satisfiedCPS.isNonEmpty();
if (!newEmpty && satisfiedCPS.implies(perm)) {
this.empty = false;
return true;
}
boolean satisfied = false;
Vector unevalCondsSets = null;
SecurityManager sm = System.getSecurityManager();
FrameworkSecurityManager fsm = null;
if (sm instanceof FrameworkSecurityManager)
fsm = (FrameworkSecurityManager) sm;
ConditionalPermissionSet cpsArray[] = (ConditionalPermissionSet[]) satisfiableCPSs.toArray(new ConditionalPermissionSet[0]);
cpsLoop: for (int i = 0; i < cpsArray.length; i++) {
if (cpsArray[i].isNonEmpty()) {
newEmpty = false;
Condition conds[] = cpsArray[i].getNeededConditions();
if (conds == null)
continue;
// check mutable !isPostponed conditions first;
// note that !mutable conditions have already been evaluated
for (int j = 0; j < conds.length; j++)
if (conds[j] != null && !conds[j].isPostponed() && !conds[j].isSatisfied())
continue cpsLoop;
// check the implies now
if (cpsArray[i].implies(perm)) {
// the permission is implied; the only unevaluated conditions left are mutable postponed conditions
// postpone their evaluation until the end
Vector unevaluatedConds = null;
for (int j = 0; j < conds.length; j++) {
if (conds[j] != null && conds[j].isPostponed()) {
if (fsm == null) {
// If there is no FrameworkSecurityManager, we must evaluate now
if (!conds[j].isSatisfied())
continue cpsLoop;
} else {
if (unevaluatedConds == null)
unevaluatedConds = new Vector();
unevaluatedConds.add(conds[j]);
}
}
}
if (unevaluatedConds == null) {
// no postponed conditions exist return true now
this.empty = false;
return true;
}
if (unevalCondsSets == null)
unevalCondsSets = new Vector(2);
unevalCondsSets.add(unevaluatedConds.toArray(new Condition[unevaluatedConds.size()]));
satisfied = true;
}
} else {
satisfiableCPSs.remove(cpsArray[i]);
}
}
this.empty = newEmpty;
if (satisfied && fsm != null) {
// There must be at least one set of Conditions to evaluate since
// we didn't return right we we realized the permission was satisfied
// so unevalCondsSets must be non-null.
Condition[][] condArray = (Condition[][]) unevalCondsSets.toArray(new Condition[unevalCondsSets.size()][]);
satisfied = fsm.addConditionsForDomain(condArray);
}
return satisfied;
}
/**
* Process any satisfiedCPIs that have been added.
*/
private void processPending() {
if (satisfiedCPIs.size() > 0) {
synchronized (satisfiedCPIs) {
for (int i = 0; i < satisfiedCPIs.size(); i++) {
ConditionalPermissionInfoImpl cpi = (ConditionalPermissionInfoImpl) satisfiedCPIs.get(i);
if (!cpi.isDeleted())
satisfiedCPS.addConditionalPermissionInfo(cpi);
}
satisfiedCPIs.clear();
}
}
}
/**
* This method is not implemented since this PermissionCollection should
* only be used by the ConditionalPolicy which never calls this method.
*
* @return always returns null.
*
* @see java.security.PermissionCollection#elements()
*/
public Enumeration elements() {
return null;
}
/**
* This method returns true if there are no ConditionalPermissionInfos in
* this PermissionCollection. The empty condition is only checked during the
* implies method, it should only be checked after implies has been called.
*
* @return false if there are any Conditions that may provide permissions to
* this bundle.
*/
boolean isEmpty() {
return empty;
}
void unresolvePermissions() {
satisfiedCPS.unresolvePermissions();
synchronized (satisfiableCPSs) {
Enumeration en = satisfiableCPSs.elements();
while (en.hasMoreElements()) {
ConditionalPermissionSet cs = (ConditionalPermissionSet) en.nextElement();
cs.unresolvePermissions();
}
}
}
}