| /******************************************************************************* |
| * Copyright (c) 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.osgi.framework.internal.core; |
| |
| import java.security.*; |
| import java.util.*; |
| import org.eclipse.osgi.framework.debug.Debug; |
| |
| /** |
| * A heterogeneous collection of permissions for a bundle. |
| * |
| */ |
| final class BundlePermissions extends BundlePermissionCollection { |
| /** |
| * Maps a Permission's class to an appropriate PermissionCollection. |
| * Class => PermissionCollection |
| */ |
| private Hashtable collections = new Hashtable(8); //TODO How dynamic is this? |
| |
| /** |
| * Set to an AllPermissionCollection if this Permissions contains AllPermission. |
| */ |
| private PermissionCollection allPermission; |
| |
| /** Used to load classes for unresolved permissions */ |
| private PackageAdmin packageAdmin; |
| |
| /** |
| * Constructs a new instance of this class. |
| * |
| */ |
| BundlePermissions(PackageAdmin packageAdmin) { |
| super(); |
| |
| this.packageAdmin = packageAdmin; |
| } |
| |
| /** |
| * Adds the argument to the collection. |
| * |
| * @param permission java.security.Permission |
| * the permission to add to the collection |
| */ |
| public void add(Permission permission) { |
| if (isReadOnly()) { |
| throw new SecurityException(); |
| } |
| |
| PermissionCollection collection; |
| |
| synchronized (collections) { |
| collection = findCollection(permission); |
| |
| if (collection == null) { |
| collection = newPermissionCollection(permission); |
| } |
| } |
| |
| if (permission instanceof AllPermission) { |
| allPermission = collection; |
| } |
| |
| collection.add(permission); |
| } |
| |
| /** |
| * Answers an enumeration of the permissions |
| * in the receiver. |
| * |
| * @return Enumeration |
| * the permissions in the receiver. |
| */ |
| public Enumeration elements() { |
| return new Enumeration() { |
| Enumeration enumMap = collections.elements(); |
| PermissionCollection c; |
| Enumeration enumC; |
| Permission next = findNextPermission(); |
| |
| public boolean hasMoreElements() { |
| return (next != null); |
| } |
| |
| public Object nextElement() { |
| if (next == null) { |
| throw new NoSuchElementException(); |
| } else { |
| Object answer = next; |
| next = findNextPermission(); |
| return (answer); |
| } |
| } |
| |
| // This method is the important one. It looks for and |
| // answers the next available permission. If there are |
| // no permissions left to return, it answers null. |
| private Permission findNextPermission() { |
| // Loop until we get a collection with at least one element. |
| while (c == null && enumMap.hasMoreElements()) { |
| c = (PermissionCollection) enumMap.nextElement(); |
| enumC = c.elements(); |
| if (!enumC.hasMoreElements()) |
| c = null; |
| } |
| // At this point, c == null if there are no more elements, |
| // and otherwise is the first collection with a free element |
| // (with enumC set up to return that element). |
| if (c == null) { |
| // no more elements, so return null; |
| return (null); |
| } else { |
| Permission answer = (Permission) enumC.nextElement(); |
| if (!enumC.hasMoreElements()) |
| c = null; |
| return (answer); |
| } |
| } |
| }; |
| } |
| |
| /** |
| * Find the appropriate permission collection to use for |
| * the given permission. |
| * |
| * @param permission Permission |
| * the permission to find a collection for |
| * @return PermissionCollection |
| * the collection to use with the permission. |
| */ |
| private PermissionCollection findCollection(Permission permission) { |
| Class clazz = permission.getClass(); |
| |
| PermissionCollection collection = (PermissionCollection) collections.get(clazz); |
| |
| if (collection == null) { |
| synchronized (collections) { |
| collection = (PermissionCollection) collections.get(clazz); |
| |
| if (collection == null) { |
| collection = resolvePermissions(permission); |
| } |
| } |
| } |
| |
| return collection; |
| } |
| |
| /** |
| * This method will attempt to resolve unresolved permissions of the |
| * type of the specified permission. |
| * |
| * This method should only be called while holding the collections lock. |
| * |
| * @param permission Permission whose type we shall attempt to resolve. |
| * @return A PermissionCollection for the resolved permissions or |
| * <tt>null</tt> if the permissions cannot currently be resolved. |
| */ |
| private PermissionCollection resolvePermissions(Permission permission) { |
| UnresolvedPermissionCollection unresolvedCollection = (UnresolvedPermissionCollection) collections.get(UnresolvedPermission.class); |
| |
| if (unresolvedCollection != null) { |
| String name = permission.getClass().getName(); |
| |
| Vector permissions = unresolvedCollection.getPermissions(name); |
| |
| if (permissions != null) { |
| PermissionCollection collection = null; |
| Class clazz; |
| |
| // We really need to resolve the permission |
| // by loading it only from the proper classloader, |
| // i.e. the system classloader or and exporting bundle's |
| // classloader. Otherwise there is a security hole. |
| clazz = packageAdmin.loadServiceClass(name,null); |
| if (clazz == null) { |
| return null; |
| } |
| |
| Enumeration enum = permissions.elements(); |
| |
| while (enum.hasMoreElements()) { |
| Permission resolved = ((UnresolvedPermission) enum.nextElement()).resolve(clazz); |
| |
| if (resolved != null) { |
| if (collection == null) { |
| collection = newPermissionCollection(resolved); |
| } |
| |
| collection.add(resolved); |
| } |
| } |
| |
| return collection; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Creates a PermissionCollection suitable to hold the specified permission. |
| * The created collection is added to the collections Hashtable. |
| * |
| * This method should only be called while holding the collections lock. |
| */ |
| private PermissionCollection newPermissionCollection(Permission permission) { |
| PermissionCollection collection = permission.newPermissionCollection(); |
| |
| if (collection == null) { |
| collection = new PermissionsHash(); |
| } |
| |
| collections.put(permission.getClass(), collection); |
| |
| return collection; |
| } |
| |
| /** |
| * Indicates whether the argument permission is implied |
| * by the permissions contained in the receiver. |
| * |
| * @return boolean |
| * <code>true</code> if the argument permission |
| * is implied by the permissions in the receiver, |
| * and <code>false</code> if it is not. |
| * @param perm java.security.Permission |
| * the permission to check |
| */ |
| public boolean implies(Permission perm) { |
| if ((allPermission != null) && allPermission.implies(perm)) { |
| return true; |
| } |
| |
| PermissionCollection collection = findCollection(perm); |
| |
| if (collection == null) { |
| return false; |
| } |
| |
| return collection.implies(perm); |
| } |
| |
| /** |
| * The Permission collection will unresolve the permissions in these packages. |
| * |
| * @param unresolvedPackages A list of the package which have been unresolved |
| * as a result of a packageRefresh |
| */ |
| void unresolvePermissions(Hashtable unresolvedPackages) { |
| synchronized (collections) { |
| int size = collections.size(); |
| |
| Class[] clazzes = new Class[size]; |
| Enumeration enum = collections.keys(); |
| |
| for (int i = 0; i < size; i++) { |
| clazzes[i] = (Class) enum.nextElement(); |
| } |
| |
| for (int i = 0; i < size; i++) { |
| Class clazz = clazzes[i]; |
| |
| String name = clazz.getName(); |
| |
| int index = name.lastIndexOf('.'); /* find last period in class name */ |
| |
| if (index > 0) { |
| if (unresolvedPackages.get(name.substring(0, index)) != null) { |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println(" Unresolving permission class " + name); |
| } |
| |
| collections.remove(clazz); |
| } |
| } |
| } |
| } |
| } |
| } |