blob: b7a370c6c214e4f65e9d4af437adcfc4f45dac91 [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.io.File;
import java.io.Serializable;
import java.lang.reflect.*;
import java.security.*;
import java.util.ArrayList;
import org.osgi.framework.Bundle;
import org.osgi.service.condpermadmin.*;
import org.osgi.service.permissionadmin.PermissionInfo;
/**
*
* This is a runtime embodiment of the data stored in ConditionalPermissionInfo.
* It has methods to facilitate the management of Conditions and Permissions at
* runtime.
*/
public class ConditionalPermissionInfoImpl implements ConditionalPermissionInfo, Serializable {
private static final long serialVersionUID = 3258130245704825139L;
/**
* The permissions enabled by the associated Conditions.
*/
PermissionInfo perms[];
/**
* The conditions that must be satisfied to enable the corresponding
* permissions.
*/
ConditionInfo conds[];
/**
* The name of the ConditionalPermissionInfo
*/
private String name;
/**
* When true, this object has been deleted and any information retrieved
* from it should be discarded.
*/
private boolean deleted = false;
/**
* When true, this object has been deleted and any information retrieved
* from it should be discarded.
*/
boolean isDeleted() {
return deleted;
}
public ConditionalPermissionInfoImpl(String encoded) {
decode(encoded);
}
public ConditionalPermissionInfoImpl(String name, ConditionInfo conds[], PermissionInfo perms[]) {
this.name = name;
this.conds = conds;
this.perms = perms;
}
private void decode(String encoded) {
int start = encoded.indexOf('{');
int end = encoded.lastIndexOf('}');
if (start < 0 || end < start)
throw new IllegalArgumentException(encoded);
if (start != 0)
name = encoded.substring(0, start);
char[] chars = encoded.substring(start + 1, end).toCharArray();
ArrayList condList = new ArrayList();
ArrayList permList = new ArrayList();
int pos = 0;
while (pos < chars.length) {
while (pos < chars.length && chars[pos] != '[' && chars[pos] != '(')
pos++;
if (pos == chars.length)
break; // no perms or conds left
int startPos = pos;
char endChar = chars[startPos] == '[' ? ']' : ')';
while (chars[pos] != endChar) {
if (chars[pos] == '"') {
pos++;
while (chars[pos] != '"') {
if (chars[pos] == '\\')
pos++;
pos++;
}
}
pos++;
}
int endPos = pos;
String token = new String(chars, startPos, endPos - startPos + 1);
if (endChar == ']')
condList.add(new ConditionInfo(token));
else
permList.add(new PermissionInfo(token));
pos++;
}
conds = (ConditionInfo[]) condList.toArray(new ConditionInfo[condList.size()]);
perms = (PermissionInfo[]) permList.toArray(new PermissionInfo[permList.size()]);
}
public String getName() {
return name;
}
/**
* @see org.osgi.service.condpermadmin.ConditionalPermissionInfo#getConditionInfos()
*/
public ConditionInfo[] getConditionInfos() {
if (conds == null)
return null;
ConditionInfo[] results = new ConditionInfo[conds.length];
System.arraycopy(conds, 0, results, 0, conds.length);
return results;
}
/* Used to find permission constructors in addPermissions */
static private final Class twoStringClassArray[] = new Class[] {String.class, String.class};
static private final Class oneStringClassArray[] = new Class[] {String.class};
static private final Class noArgClassArray[] = new Class[] {};
static private final Class[][] permClassArrayArgs = new Class[][] {noArgClassArray, oneStringClassArray, twoStringClassArray};
/* Used to find condition constructors getConditions */
static private final Class[] condClassArray = new Class[] {Bundle.class, ConditionInfo.class};
/**
* Adds the permissions of the given type (if any) that are part of this
* ConditionalPermissionInfo to the specified collection. The Permission
* instances are constructed using the specified permClass.
*
* @param collection the collection to add to.
* @param permClass the class to use to construct Permission instances.
* @return the number of Permissions added.
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws IllegalArgumentException
*/
int addPermissions(AbstractBundle bundle, PermissionCollection collection, Class permClass) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
String permClassName = permClass.getName();
Constructor constructor = null;
int numArgs = -1;
for (int i = permClassArrayArgs.length - 1 ; i >= 0; i--) {
try {
constructor = permClass.getConstructor(permClassArrayArgs[i]);
numArgs = i;
break;
} catch (NoSuchMethodException e) {
// ignore
}
}
if (constructor == null)
throw new NoSuchMethodException(permClass.getName() + ".<init>()"); //$NON-NLS-1$
int count = 0;
/*
* TODO: We need to cache the permission constructors to enhance performance (see bug 118813).
*/
for (int i = 0; i < perms.length; i++) {
if (perms[i].getType().equals(permClassName)) {
count++;
String args[] = new String[numArgs];
if (numArgs > 0)
args[0] = perms[i].getName();
if (numArgs > 1)
args[1] = perms[i].getActions();
if (perms[i].getType().equals("java.io.FilePermission")) { //$NON-NLS-1$
// map FilePermissions for relative names to the bundle's data area
if (!args[0].equals("<<ALL FILES>>")) { //$NON-NLS-1$
File file = new File(args[0]);
if (!file.isAbsolute()) { // relative name
if (bundle == null) // default permissions
continue; // no relative file permissions
File target = bundle.framework.getDataFile(bundle, args[0]);
if (target == null) // no bundle data file area
continue; // no relative file permissions
args[0] = target.getPath();
}
}
}
collection.add((Permission) constructor.newInstance(args));
}
}
return count;
}
/**
* Returns the Condition objects associated with this ConditionalPermissionInfo.
*
* @param bundle the bundle to be used to construct the Conditions.
*
* @return the array of Conditions that must be satisfied before permissions
* in the ConditionPermissionInfoImpl can be used.
*/
Condition[] getConditions(Bundle bundle) {
Condition conditions[] = new Condition[conds.length];
for (int i = 0; i < conds.length; i++) {
/*
* TODO: I think we can pre-get the Constructors in our own
* constructor
*/
Class clazz;
try {
clazz = Class.forName(conds[i].getType());
} catch (ClassNotFoundException e) {
/* If the class isn't there, we fail */
return null;
}
Constructor constructor = null;
Method method = null;
try {
method = clazz.getMethod("getCondition", condClassArray); //$NON-NLS-1$
if ((method.getModifiers() & Modifier.STATIC) == 0)
method = null;
} catch (NoSuchMethodException e) {
// This is a normal case
}
if (method == null)
try {
constructor = clazz.getConstructor(condClassArray);
} catch (NoSuchMethodException e) {
// TODO should post a FrameworkEvent of type error here
conditions[i] = Condition.FALSE;
continue;
}
Object args[] = {bundle, conds[i]};
try {
if (method != null)
conditions[i] = (Condition) method.invoke(null, args);
else
conditions[i] = (Condition) constructor.newInstance(args);
} catch (Throwable t) {
// TODO should post a FrameworkEvent of type error here
conditions[i] = Condition.FALSE;
}
}
return conditions;
}
/**
* @see org.osgi.service.condpermadmin.ConditionalPermissionInfo#getPermissionInfos()
*/
public PermissionInfo[] getPermissionInfos() {
if (perms == null)
return null;
PermissionInfo[] results = new PermissionInfo[perms.length];
System.arraycopy(perms, 0, results, 0, perms.length);
return results;
}
/**
*
* @see org.osgi.service.condpermadmin.ConditionalPermissionInfo#delete()
*/
public void delete() {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new AllPermission());
deleted = true;
condAdmin.deleteConditionalPermissionInfo(this);
}
private static ConditionalPermissionAdminImpl condAdmin;
static void setConditionalPermissionAdminImpl(ConditionalPermissionAdminImpl condAdmin) {
ConditionalPermissionInfoImpl.condAdmin = condAdmin;
}
public String toString() {
StringBuffer result = new StringBuffer();
if (name != null)
result.append(name);
ConditionInfo[] curConds = getConditionInfos();
PermissionInfo[] curPerms = getPermissionInfos();
result.append('{').append(' ');
if (curConds != null)
for (int i = 0; i < curConds.length; i++)
result.append(curConds[i].getEncoded()).append(' ');
if (curPerms != null)
for (int i = 0; i < curPerms.length; i++)
result.append(curPerms[i].getEncoded()).append(' ');
result.append('}');
return result.toString();
}
}