Package org.eclipse.osgi.framework.internal.core

Source Code of org.eclipse.osgi.framework.internal.core.ConditionalPermissionSet

/*******************************************************************************
* 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.*;
import java.util.*;
import org.osgi.service.condpermadmin.Condition;
import org.osgi.service.permissionadmin.PermissionInfo;

/**
* This class represents a PermissionCollection tied to a set of Conditions.
* Before the permissions are actually used, isNonEmpty should be called.
*/
public class ConditionalPermissionSet extends BundlePermissionCollection {
  private static final long serialVersionUID = 3258411750729920566L;
  private ConditionalPermissionInfoImpl cpis[] = ConditionalPermissionAdminImpl.EMPTY_COND_PERM_INFO;
  private HashMap cachedPermissionCollections = new HashMap();
  private boolean hasAllPermission = false;
  private AbstractBundle bundle;
  /**
   * These are conditions that need to be satisfied in order to enable the
   * permissions. If the array is empty, no conditions need to be satisfied.
   * If <code>neededCondititions</code> is null,
   */
  private Condition neededConditions[];

  /*
   * TODO: we need to validate the cpis[] to make sure they don't go away.
   * Reset everything if they do. We also need to be able to add CPIs
   */
  /**
   * Construct a new ConditionalPermission set with an initial set of
   * permissions.
   */
  public ConditionalPermissionSet(AbstractBundle bundle, ConditionalPermissionInfoImpl cpis[], Condition neededConditions[]) {
    this.bundle = bundle;
    this.cpis = cpis;
    this.neededConditions = neededConditions;
    checkForAllPermission();
  }

  /**
   * Adds another ConditionalPermissionInfoImpl to this set. <b>Only a
   * CondtitionalPermissionInfo whose Conditions are immutable and satisfied
   * may be added. </b>
   *
   * @param cpi the ConditionalPermissionInfoImpl to be added to this set.
   *        <b>Only a CondtitionalPermissionInfo whose Conditions are
   *        immutable and satisfied may be added. </b>
   */
  void addConditionalPermissionInfo(ConditionalPermissionInfoImpl cpi) {
    if (neededConditions == null || neededConditions.length > 0)
      throw new RuntimeException("Cannot add ConditionalPermissionInfoImpl to a non satisfied set"); //$NON-NLS-1$
    synchronized (cachedPermissionCollections) {
      // first look for a null slot
      for (int i = 0; i < cpis.length; i++)
        if (cpis[i] == null) { // found an empty slot; use it
          cpis[i] = cpi;
          cachedPermissionCollections.clear();
          return;
        }
      ConditionalPermissionInfoImpl newcpis[] = new ConditionalPermissionInfoImpl[cpis.length + 1];
      System.arraycopy(cpis, 0, newcpis, 0, cpis.length);
      newcpis[cpis.length] = cpi;
      cpis = newcpis;
      /*
       * TODO: I couldn't decide wether it is better to run through the cached
       * PermissionCollections and add permissions from this cpi, or to just
       * clear out and let them get rebuilt ondemand. The ondemand route is
       * simpler and in the end may be more efficient.
       */
      cachedPermissionCollections.clear();
      checkForAllPermission();
    }
  }

  /**
   * This runs through the PermissionInfos to see if there is an AllPermission in the mix.
   */
  private void checkForAllPermission() {
    if (hasAllPermission) {
      return;
    }
    out: for (int i = 0; i < cpis.length; i++) {
      if (cpis[i] == null) // check for deletions
        continue;
      PermissionInfo perms[] = cpis[i].perms;
      for (int j = 0; j < perms.length; j++) {
        if (perms[j].getType().equals(AllPermission.class.getName())) {
          hasAllPermission = true;
          break out;
        }
      }
    }
  }

  /**
   * Returns true if at least one of the ConditionalPermissionInfos in this
   * set is still active. (Not deleted.)
   *
   * @return true if there is at least one active ConditionalPermissionInfo.
   */
  boolean isNonEmpty() {
    boolean nonEmpty = false;
    boolean forceAllPermCheck = false;
    synchronized (cachedPermissionCollections) {
      for (int i = 0; i < cpis.length; i++) {
        if (cpis[i] != null) {
          if (cpis[i].isDeleted()) {
            cpis[i] = null;
            forceAllPermCheck = true;
            /*
             * We don't have a way to remove from a collection; we can
             * only add. Thus, we must clear out everything. TODO:
             * Investigate if it would be more efficient to only clear
             * the permission collections of the type stored by the cpi.
             */
            cachedPermissionCollections.clear();
          } else {
            nonEmpty = true;
          }
        }
      }
      if (!nonEmpty)
        cpis = ConditionalPermissionAdminImpl.EMPTY_COND_PERM_INFO;
      if (forceAllPermCheck) {
        hasAllPermission = false;
        checkForAllPermission();
      }
    }
    return nonEmpty;
  }

  /**
   * Returns the conditions that need to be satisfied before the permissions
   * embodied in this set can be used.
   *
   * @return the array of conditions that need to be satisfied. If the array
   *         is empty, no conditions need to be satisfied to use the
   *         permissions. If null is returned, these permissions can never be
   *         used.
   */
  Condition[] getNeededConditions() {
    if (neededConditions == null || neededConditions.length == 0)
      return neededConditions;
    boolean foundNonNullCondition = false;
    /* We need to check to see if any conditions became immutable */
    for (int i = 0; i < neededConditions.length; i++) {
      Condition cond = neededConditions[i];
      if (cond == null)
        continue;
      if (!cond.isMutable()) {
        if (cond.isSatisfied()) {
          neededConditions[i] = null;
        } else {
          /*
           * We now have an immutable unsatisfied condition, this set
           * is no longer valid.
           */
          neededConditions = null;
          break;
        }
      } else {
        foundNonNullCondition = true;
      }
    }
    if (neededConditions != null && !foundNonNullCondition)
      neededConditions = ConditionalPermissionAdminImpl.EMPTY_COND;
    return neededConditions;
  }

  /**
   * We don't do anything here since this isn't a real PermissionCollection.
   *
   * @param perm ignored.
   * @see java.security.PermissionCollection#add(java.security.Permission)
   */
  public void add(Permission perm) {
    // do nothing
  }

  /**
   * Checks to see if the desired Permission is implied by this collection of
   * ConditionalPermissionInfos.
   *
   * @param perm Permission to check.
   * @return true if this ConditionPermissionSet implies the passed
   *         Permission.
   * @see java.security.PermissionCollection#implies(java.security.Permission)
   */
  public boolean implies(Permission perm) {
    if (hasAllPermission)
      return true;
    Class permClass = perm.getClass();
    PermissionCollection collection;
    synchronized (cachedPermissionCollections) {
      collection = (PermissionCollection) cachedPermissionCollections.get(permClass);
      if (collection == null) {
        collection = perm.newPermissionCollection();
        if (collection == null)
          collection = new PermissionsHash();
        for (int i = 0; i < cpis.length; i++) {
          try {
            ConditionalPermissionInfoImpl cpi = cpis[i];
            if (cpi != null)
              cpi.addPermissions(bundle, collection, permClass);
          } catch (Exception e) {
            // TODO: we should log this somewhere
            e.printStackTrace();
          }
        }
        cachedPermissionCollections.put(permClass, collection);
      }
    }
    return collection.implies(perm);
  }

  /**
   * We don't do anything here since this isn't a real PermissionCollection.
   *
   * @return always returns null.
   * @see java.security.PermissionCollection#elements()
   */
  public Enumeration elements() {
    return null;
  }

  /**
   * This method simply clears the resolved permission table. I think in both the
   * short-term and the amoritized case, this is more efficient than walking through
   * and clearing specific entries.
   */
  void unresolvePermissions() {
    synchronized (cachedPermissionCollections) {
      cachedPermissionCollections.clear();
    }
  }

  boolean remove(ConditionalPermissionInfoImpl cpi) {
    synchronized (cachedPermissionCollections) {
      for (int i = 0; i < cpis.length; i++)
        if (cpis[i] == cpi) {
          cpis[i] = null;
          cachedPermissionCollections.clear();
          return true;
        }
    }
    return false;
  }
}
TOP

Related Classes of org.eclipse.osgi.framework.internal.core.ConditionalPermissionSet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.