You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2012/01/05 15:16:38 UTC

svn commit: r1227602 [9/10] - in /karaf/trunk: ./ admin/command/ admin/core/ admin/core/src/test/java/org/apache/karaf/jpm/ admin/management/ deployer/blueprint/ deployer/features/ deployer/kar/ deployer/spring/ deployer/wrap/ diagnostic/command/ diagn...

Added: karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/Condition.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/Condition.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/Condition.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/Condition.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.condpermadmin;
+
+import java.util.Dictionary;
+
+/**
+ * The interface implemented by a Condition. Conditions are bound to Permissions
+ * using Conditional Permission Info. The Permissions of a ConditionalPermission
+ * Info can only be used if the associated Conditions are satisfied.
+ * 
+ * @ThreadSafe
+ * @version $Id: 7e80cf578718db713c347568e7d3232010beac0a $
+ */
+public interface Condition {
+	/**
+	 * A Condition object that will always evaluate to true and that is never
+	 * postponed.
+	 */
+	public final static Condition	TRUE	= new BooleanCondition(true);
+
+	/**
+	 * A Condition object that will always evaluate to false and that is never
+	 * postponed.
+	 */
+	public final static Condition	FALSE	= new BooleanCondition(false);
+
+	/**
+	 * Returns whether the evaluation must be postponed until the end of the
+	 * permission check. If this method returns {@code false} (or this
+	 * Condition is immutable), then this Condition must be able to directly
+	 * answer the {@link #isSatisfied()} method. In other words, isSatisfied()
+	 * will return very quickly since no external sources, such as for example
+	 * users or networks, need to be consulted. <br/>
+	 * This method must always return the same value whenever it is called so
+	 * that the Conditional Permission Admin can cache its result.
+	 * 
+	 * @return {@code true} to indicate the evaluation must be postponed.
+	 *         Otherwise, {@code false} if the evaluation can be performed
+	 *         immediately.
+	 */
+	boolean isPostponed();
+
+	/**
+	 * Returns whether the Condition is satisfied. This method is only called
+	 * for immediate Condition objects or immutable postponed conditions, and
+	 * must always be called inside a permission check. Mutable postponed
+	 * Condition objects will be called with the grouped version
+	 * {@link #isSatisfied(Condition[],Dictionary)} at the end of the permission
+	 * check.
+	 * 
+	 * @return {@code true} to indicate the Conditions is satisfied.
+	 *         Otherwise, {@code false} if the Condition is not satisfied.
+	 */
+	boolean isSatisfied();
+
+	/**
+	 * Returns whether the Condition is mutable. A Condition can go from mutable
+	 * ({@code true}) to immutable ({@code false}) over time but never
+	 * from immutable ({@code false}) to mutable ({@code true}).
+	 * 
+	 * @return {@code true} {@link #isSatisfied()} can change. Otherwise,
+	 *         {@code false} if the value returned by
+	 *         {@link #isSatisfied()} will not change for this condition.
+	 */
+	boolean isMutable();
+
+	/**
+	 * Returns whether the specified set of Condition objects are satisfied.
+	 * Although this method is not static, it must be implemented as if it
+	 * were static. All of the passed Condition objects will be of the same
+	 * type and will correspond to the class type of the object on which this
+	 * method is invoked. This method must be called inside a permission check
+	 * only.
+	 * 
+	 * @param conditions The array of Condition objects, which must all be of
+	 *        the same class and mutable. The receiver must be one of those
+	 *        Condition objects.
+	 * @param context A Dictionary object that implementors can use to track
+	 *        state. If this method is invoked multiple times in the same
+	 *        permission check, the same Dictionary will be passed multiple
+	 *        times. The SecurityManager treats this Dictionary as an opaque
+	 *        object and simply creates an empty dictionary and passes it to
+	 *        subsequent invocations if multiple invocations are needed.
+	 * @return {@code true} if all the Condition objects are satisfied.
+	 *         Otherwise, {@code false} if one of the Condition objects is
+	 *         not satisfied.
+	 */
+	boolean isSatisfied(Condition conditions[],
+			Dictionary<Object, Object> context);
+}
+
+/**
+ * Package private class used to define the {@link Condition#FALSE} and
+ * {@link Condition#TRUE} constants.
+ * 
+ * @Immutable
+ */
+final class BooleanCondition implements Condition {
+	private final boolean	satisfied;
+
+	BooleanCondition(boolean satisfied) {
+		this.satisfied = satisfied;
+	}
+
+	public boolean isPostponed() {
+		return false;
+	}
+
+	public boolean isSatisfied() {
+		return satisfied;
+	}
+
+	public boolean isMutable() {
+		return false;
+	}
+
+	public boolean isSatisfied(Condition[] conds,
+			Dictionary<Object, Object> context) {
+		for (int i = 0, length = conds.length; i < length; i++) {
+			if (!conds[i].isSatisfied())
+				return false;
+		}
+		return true;
+	}
+}

Added: karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.condpermadmin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Condition representation used by the Conditional Permission Admin service.
+ * 
+ * <p>
+ * This class encapsulates two pieces of information: a Condition <i>type</i>
+ * (class name), which must implement {@code Condition}, and the
+ * arguments passed to its constructor.
+ * 
+ * <p>
+ * In order for a Condition represented by a {@code ConditionInfo} to be
+ * instantiated and considered during a permission check, its Condition class
+ * must be available from the system classpath.
+ * 
+ * <p>
+ * The Condition class must either:
+ * <ul>
+ * <li>Declare a public static {@code getCondition} method that takes a
+ * {@code Bundle} object and a {@code ConditionInfo} object as
+ * arguments. That method must return an object that implements the
+ * {@code Condition} interface.</li>
+ * <li>Implement the {@code Condition} interface and define a public
+ * constructor that takes a {@code Bundle} object and a
+ * {@code ConditionInfo} object as arguments.
+ * </ul>
+ * 
+ * @Immutable
+ * @version $Id: dd1d84aa3175b2a2dfec879d04c93887f05161be $
+ */
+public class ConditionInfo {
+	private final String	type;
+	private final String[]	args;
+
+	/**
+	 * Constructs a {@code ConditionInfo} from the specified type and args.
+	 * 
+	 * @param type The fully qualified class name of the Condition represented
+	 *        by this {@code ConditionInfo}.
+	 * @param args The arguments for the Condition. These arguments are
+	 *        available to the newly created Condition by calling the
+	 *        {@link #getArgs()} method.
+	 * @throws NullPointerException If {@code type} is {@code null}.
+	 */
+	public ConditionInfo(String type, String[] args) {
+		this.type = type;
+		this.args = (args != null) ? args.clone() : new String[0];
+		if (type == null) {
+			throw new NullPointerException("type is null");
+		}
+	}
+
+	/**
+	 * Constructs a {@code ConditionInfo} object from the specified encoded
+	 * {@code ConditionInfo} string. White space in the encoded
+	 * {@code ConditionInfo} string is ignored.
+	 * 
+	 * @param encodedCondition The encoded {@code ConditionInfo}.
+	 * @see #getEncoded
+	 * @throws IllegalArgumentException If the specified
+	 *         {@code encodedCondition} is not properly formatted.
+	 */
+	public ConditionInfo(String encodedCondition) {
+		if (encodedCondition == null) {
+			throw new NullPointerException("missing encoded condition");
+		}
+		if (encodedCondition.length() == 0) {
+			throw new IllegalArgumentException("empty encoded condition");
+		}
+		try {
+			char[] encoded = encodedCondition.toCharArray();
+			int length = encoded.length;
+			int pos = 0;
+
+			/* skip whitespace */
+			while (Character.isWhitespace(encoded[pos])) {
+				pos++;
+			}
+
+			/* the first character must be '[' */
+			if (encoded[pos] != '[') {
+				throw new IllegalArgumentException("expecting open bracket");
+			}
+			pos++;
+
+			/* skip whitespace */
+			while (Character.isWhitespace(encoded[pos])) {
+				pos++;
+			}
+
+			/* type is not quoted or encoded */
+			int begin = pos;
+			while (!Character.isWhitespace(encoded[pos])
+					&& (encoded[pos] != ']')) {
+				pos++;
+			}
+			if (pos == begin || encoded[begin] == '"') {
+				throw new IllegalArgumentException("expecting type");
+			}
+			this.type = new String(encoded, begin, pos - begin);
+
+			/* skip whitespace */
+			while (Character.isWhitespace(encoded[pos])) {
+				pos++;
+			}
+
+			/* type may be followed by args which are quoted and encoded */
+			List<String> argsList = new ArrayList<String>();
+			while (encoded[pos] == '"') {
+				pos++;
+				begin = pos;
+				while (encoded[pos] != '"') {
+					if (encoded[pos] == '\\') {
+						pos++;
+					}
+					pos++;
+				}
+				argsList.add(unescapeString(encoded, begin, pos));
+				pos++;
+
+				if (Character.isWhitespace(encoded[pos])) {
+					/* skip whitespace */
+					while (Character.isWhitespace(encoded[pos])) {
+						pos++;
+					}
+				}
+			}
+			this.args = argsList.toArray(new String[argsList.size()]);
+
+			/* the final character must be ']' */
+			char c = encoded[pos];
+			pos++;
+			while ((pos < length) && Character.isWhitespace(encoded[pos])) {
+				pos++;
+			}
+			if ((c != ']') || (pos != length)) {
+				throw new IllegalArgumentException("expecting close bracket");
+			}
+		}
+		catch (ArrayIndexOutOfBoundsException e) {
+			throw new IllegalArgumentException("parsing terminated abruptly");
+		}
+	}
+
+	/**
+	 * Returns the string encoding of this {@code ConditionInfo} in a form
+	 * suitable for restoring this {@code ConditionInfo}.
+	 * 
+	 * <p>
+	 * The encoded format is:
+	 * 
+	 * <pre>
+	 *   [type &quot;arg0&quot; &quot;arg1&quot; ...]
+	 * </pre>
+	 * 
+	 * where <i>argN</i> are strings that must be encoded for proper parsing.
+	 * Specifically, the {@code &quot;}, {@code \}, carriage return,
+	 * and line feed characters must be escaped using {@code \&quot;},
+	 * {@code \\}, {@code \r}, and {@code \n}, respectively.
+	 * 
+	 * <p>
+	 * The encoded string contains no leading or trailing whitespace characters.
+	 * A single space character is used between type and &quot;<i>arg0</i>&quot;
+	 * and between the arguments.
+	 * 
+	 * @return The string encoding of this {@code ConditionInfo}.
+	 */
+	public final String getEncoded() {
+		StringBuffer output = new StringBuffer();
+		output.append('[');
+		output.append(type);
+
+		for (int i = 0; i < args.length; i++) {
+			output.append(" \"");
+			escapeString(args[i], output);
+			output.append('\"');
+		}
+
+		output.append(']');
+
+		return output.toString();
+	}
+
+	/**
+	 * Returns the string representation of this {@code ConditionInfo}.
+	 * The string is created by calling the {@code getEncoded} method on
+	 * this {@code ConditionInfo}.
+	 * 
+	 * @return The string representation of this {@code ConditionInfo}.
+	 */
+	public String toString() {
+		return getEncoded();
+	}
+
+	/**
+	 * Returns the fully qualified class name of the condition represented by
+	 * this {@code ConditionInfo}.
+	 * 
+	 * @return The fully qualified class name of the condition represented by
+	 *         this {@code ConditionInfo}.
+	 */
+	public final String getType() {
+		return type;
+	}
+
+	/**
+	 * Returns arguments of this {@code ConditionInfo}.
+	 * 
+	 * @return The arguments of this {@code ConditionInfo}. An empty
+	 *         array is returned if the {@code ConditionInfo} has no
+	 *         arguments.
+	 */
+	public final String[] getArgs() {
+		return args.clone();
+	}
+
+	/**
+	 * Determines the equality of two {@code ConditionInfo} objects.
+	 * 
+	 * This method checks that specified object has the same type and args as
+	 * this {@code ConditionInfo} object.
+	 * 
+	 * @param obj The object to test for equality with this
+	 *        {@code ConditionInfo} object.
+	 * @return {@code true} if {@code obj} is a
+	 *         {@code ConditionInfo}, and has the same type and args as
+	 *         this {@code ConditionInfo} object; {@code false}
+	 *         otherwise.
+	 */
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+
+		if (!(obj instanceof ConditionInfo)) {
+			return false;
+		}
+
+		ConditionInfo other = (ConditionInfo) obj;
+
+		if (!type.equals(other.type) || args.length != other.args.length)
+			return false;
+
+		for (int i = 0; i < args.length; i++) {
+			if (!args[i].equals(other.args[i]))
+				return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Returns the hash code value for this object.
+	 * 
+	 * @return A hash code value for this object.
+	 */
+
+	public int hashCode() {
+		int h = 31 * 17 + type.hashCode();
+		for (int i = 0; i < args.length; i++) {
+			h = 31 * h + args[i].hashCode();
+		}
+		return h;
+	}
+
+	/**
+	 * This escapes the quotes, backslashes, \n, and \r in the string using a
+	 * backslash and appends the newly escaped string to a StringBuffer.
+	 */
+	private static void escapeString(String str, StringBuffer output) {
+		int len = str.length();
+		for (int i = 0; i < len; i++) {
+			char c = str.charAt(i);
+			switch (c) {
+				case '"' :
+				case '\\' :
+					output.append('\\');
+					output.append(c);
+					break;
+				case '\r' :
+					output.append("\\r");
+					break;
+				case '\n' :
+					output.append("\\n");
+					break;
+				default :
+					output.append(c);
+					break;
+			}
+		}
+	}
+
+	/**
+	 * Takes an encoded character array and decodes it into a new String.
+	 */
+	private static String unescapeString(char[] str, int begin, int end) {
+		StringBuffer output = new StringBuffer(end - begin);
+		for (int i = begin; i < end; i++) {
+			char c = str[i];
+			if (c == '\\') {
+				i++;
+				if (i < end) {
+					c = str[i];
+					switch (c) {
+						case '"' :
+						case '\\' :
+							break;
+						case 'r' :
+							c = '\r';
+							break;
+						case 'n' :
+							c = '\n';
+							break;
+						default :
+							c = '\\';
+							i--;
+							break;
+					}
+				}
+			}
+			output.append(c);
+		}
+
+		return output.toString();
+	}
+}

Added: karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) OSGi Alliance (2005, 2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.condpermadmin;
+
+import java.security.AccessControlContext;
+import java.util.Enumeration;
+
+import org.osgi.service.permissionadmin.PermissionInfo;
+
+/**
+ * Framework service to administer Conditional Permissions. Conditional
+ * Permissions can be added to, retrieved from, and removed from the framework.
+ * Conditional Permissions are conceptually managed in an ordered table called
+ * the Conditional Permission Table.
+ * 
+ * @ThreadSafe
+ * @noimplement
+ * @version $Id: 887450b65e453145d57197e2db75db0bb2918ef4 $
+ */
+public interface ConditionalPermissionAdmin {
+	/**
+	 * Create a new Conditional Permission Info in the Conditional Permission
+	 * Table.
+	 * <p>
+	 * The Conditional Permission Info will be given a unique, never reused
+	 * name. This entry will be added at the beginning of the Conditional
+	 * Permission Table with an access decision of
+	 * {@link ConditionalPermissionInfo#ALLOW ALLOW}.
+	 * <p>
+	 * Since this method changes the Conditional Permission Table any
+	 * {@link ConditionalPermissionUpdate}s that were created prior to calling
+	 * this method can no longer be committed.
+	 * 
+	 * @param conditions The conditions that need to be satisfied to enable the
+	 *        specified permissions. This argument can be {@code null} or
+	 *        an empty array indicating the specified permissions are not
+	 *        guarded by any conditions.
+	 * @param permissions The permissions that are enabled when the specified
+	 *        conditions, if any, are satisfied. This argument must not be
+	 *        {@code null} and must specify at least one permission.
+	 * @return The ConditionalPermissionInfo for the specified Conditions and
+	 *         Permissions.
+	 * @throws IllegalArgumentException If no permissions are specified.
+	 * @throws SecurityException If the caller does not have
+	 *         {@code AllPermission}.
+	 * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+	 *             instead.
+	 */
+	ConditionalPermissionInfo addConditionalPermissionInfo(
+			ConditionInfo conditions[], PermissionInfo permissions[]);
+
+	/**
+	 * Set or create a Conditional Permission Info with a specified name in the
+	 * Conditional Permission Table.
+	 * <p>
+	 * If the specified name is {@code null}, a new Conditional Permission
+	 * Info must be created and will be given a unique, never reused name. If
+	 * there is currently no Conditional Permission Info with the specified
+	 * name, a new Conditional Permission Info must be created with the
+	 * specified name. Otherwise, the Conditional Permission Info with the
+	 * specified name must be updated with the specified Conditions and
+	 * Permissions. If a new entry was created in the Conditional Permission
+	 * Table it will be added at the beginning of the table with an access
+	 * decision of {@link ConditionalPermissionInfo#ALLOW ALLOW}.
+	 * <p>
+	 * Since this method changes the underlying permission table any
+	 * {@link ConditionalPermissionUpdate}s that were created prior to calling
+	 * this method can no longer be committed.
+	 * 
+	 * @param name The name of the Conditional Permission Info, or
+	 *        {@code null}.
+	 * @param conditions The conditions that need to be satisfied to enable the
+	 *        specified permissions. This argument can be {@code null} or
+	 *        an empty array indicating the specified permissions are not
+	 *        guarded by any conditions.
+	 * @param permissions The permissions that are enabled when the specified
+	 *        conditions, if any, are satisfied. This argument must not be
+	 *        {@code null} and must specify at least one permission.
+	 * @return The ConditionalPermissionInfo for the specified name, Conditions
+	 *         and Permissions.
+	 * @throws IllegalArgumentException If no permissions are specified.
+	 * @throws SecurityException If the caller does not have
+	 *         {@code AllPermission}.
+	 * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+	 *             instead.
+	 */
+	ConditionalPermissionInfo setConditionalPermissionInfo(String name,
+			ConditionInfo conditions[], PermissionInfo permissions[]);
+
+	/**
+	 * Returns the Conditional Permission Infos from the Conditional Permission
+	 * Table.
+	 * <p>
+	 * The returned Enumeration will return elements in the order they are kept
+	 * in the Conditional Permission Table.
+	 * <p>
+	 * The Enumeration returned is based on a copy of the Conditional Permission
+	 * Table and therefore will not throw exceptions if the Conditional
+	 * Permission Table is changed during the course of reading elements from
+	 * the Enumeration.
+	 * 
+	 * @return An enumeration of the Conditional Permission Infos that are
+	 *         currently in the Conditional Permission Table.
+	 * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+	 *             instead.
+	 */
+	Enumeration<ConditionalPermissionInfo> getConditionalPermissionInfos();
+
+	/**
+	 * Return the Conditional Permission Info with the specified name.
+	 * 
+	 * @param name The name of the Conditional Permission Info to be returned.
+	 * @return The Conditional Permission Info with the specified name or
+	 *         {@code null} if no Conditional Permission Info with the
+	 *         specified name exists in the Conditional Permission Table.
+	 * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+	 *             instead.
+	 */
+	ConditionalPermissionInfo getConditionalPermissionInfo(String name);
+
+	/**
+	 * Returns the Access Control Context that corresponds to the specified
+	 * signers.
+	 * 
+	 * The returned Access Control Context must act as if its protection domain
+	 * came from a bundle that has the following characteristics:
+	 * <ul>
+	 * <li>It is signed by all of the given signers</li>
+	 * <li>It has a bundle id of -1</li>
+	 * <li>Its location is the empty string</li>
+	 * <li>Its state is UNINSTALLED</li>
+	 * <li>It has no headers</li>
+	 * <li>It has the empty version (0.0.0)</li>
+	 * <li>Its last modified time=0</li>
+	 * <li>Many methods will throw {@code IllegalStateException} because the state is UNINSTALLED</li>
+	 * <li>All other methods return a {@code null}</li>
+	 * </ul> 
+	 * @param signers The signers for which to return an Access Control Context.
+	 * @return An {@code AccessControlContext} that has the Permissions
+	 *         associated with the signer.
+	 */
+	AccessControlContext getAccessControlContext(String[] signers);
+
+	/**
+	 * Creates a new update for the Conditional Permission Table. The update is
+	 * a working copy of the current Conditional Permission Table. If the
+	 * running Conditional Permission Table is modified before commit is called
+	 * on the returned update, then the call to commit on the returned update
+	 * will fail. That is, the commit method will return false and no change
+	 * will be made to the running Conditional Permission Table. There is no
+	 * requirement that commit is eventually called on the returned update.
+	 * 
+	 * @return A new update for the Conditional Permission Table.
+	 * @since 1.1
+	 */
+	ConditionalPermissionUpdate newConditionalPermissionUpdate();
+
+	/**
+	 * Creates a new ConditionalPermissionInfo with the specified fields
+	 * suitable for insertion into a {@link ConditionalPermissionUpdate}. The
+	 * {@code delete} method on {@code ConditionalPermissionInfo}
+	 * objects created with this method must throw
+	 * UnsupportedOperationException.
+	 * 
+	 * @param name The name of the created
+	 *        {@code ConditionalPermissionInfo} or {@code null} to
+	 *        have a unique name generated when the returned
+	 *        {@code ConditionalPermissionInfo} is committed in an update
+	 *        to the Conditional Permission Table.
+	 * @param conditions The conditions that need to be satisfied to enable the
+	 *        specified permissions. This argument can be {@code null} or
+	 *        an empty array indicating the specified permissions are not
+	 *        guarded by any conditions.
+	 * @param permissions The permissions that are enabled when the specified
+	 *        conditions, if any, are satisfied. This argument must not be
+	 *        {@code null} and must specify at least one permission.
+	 * @param access Access decision. Must be one of the following values:
+	 *        <ul>
+	 *        <li>{@link ConditionalPermissionInfo#ALLOW allow}</li>
+	 *        <li>{@link ConditionalPermissionInfo#DENY deny}</li>
+	 *        </ul>
+	 *        The specified access decision value must be evaluated case
+	 *        insensitively.
+	 * @return A {@code ConditionalPermissionInfo} object suitable for
+	 *         insertion into a {@link ConditionalPermissionUpdate}.
+	 * @throws IllegalArgumentException If no permissions are specified or if
+	 *         the specified access decision is not a valid value.
+	 * @since 1.1
+	 */
+	ConditionalPermissionInfo newConditionalPermissionInfo(String name,
+			ConditionInfo conditions[], PermissionInfo permissions[],
+			String access);
+
+	/**
+	 * Creates a new {@code ConditionalPermissionInfo} from the specified
+	 * encoded {@code ConditionalPermissionInfo} string suitable for
+	 * insertion into a {@link ConditionalPermissionUpdate}. The
+	 * {@code delete} method on {@code ConditionalPermissionInfo}
+	 * objects created with this method must throw
+	 * UnsupportedOperationException.
+	 * 
+	 * @param encodedConditionalPermissionInfo The encoded
+	 *        {@code ConditionalPermissionInfo}. White space in the encoded
+	 *        {@code ConditionalPermissionInfo} is ignored. The access
+	 *        decision value in the encoded
+	 *        {@code ConditionalPermissionInfo} must be evaluated case
+	 *        insensitively. If the encoded
+	 *        {@code ConditionalPermissionInfo} does not contain the
+	 *        optional name, {@code null} must be used for the name and a
+	 *        unique name will be generated when the returned
+	 *        {@code ConditionalPermissionInfo} is committed in an update
+	 *        to the Conditional Permission Table.
+	 * @return A {@code ConditionalPermissionInfo} object suitable for
+	 *         insertion into a {@link ConditionalPermissionUpdate}.
+	 * @throws IllegalArgumentException If the specified
+	 *         {@code encodedConditionalPermissionInfo} is not properly
+	 *         formatted.
+	 * @see ConditionalPermissionInfo#getEncoded
+	 * @since 1.1
+	 */
+	ConditionalPermissionInfo newConditionalPermissionInfo(
+			String encodedConditionalPermissionInfo);
+}

Added: karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.condpermadmin;
+
+import org.osgi.service.permissionadmin.PermissionInfo;
+
+/**
+ * A list of Permissions guarded by a list of conditions with an access
+ * decision. Instances of this interface are obtained from the Conditional
+ * Permission Admin service.
+ * 
+ * @Immutable
+ * @noimplement
+ * @version $Id: ca51e4dd6dfa350959bb2a2e420bdb2c996323e9 $
+ */
+public interface ConditionalPermissionInfo {
+	/**
+	 * This string is used to indicate that a row in the Conditional Permission
+	 * Table should return an access decision of &quot;allow&quot; if the
+	 * conditions are all satisfied and at least one of the permissions is
+	 * implied.
+	 * 
+	 * @since 1.1
+	 */
+	public final static String	ALLOW	= "allow";
+
+	/**
+	 * This string is used to indicate that a row in the Conditional Permission
+	 * Table should return an access decision of &quot;deny&quot; if the
+	 * conditions are all satisfied and at least one of the permissions is
+	 * implied.
+	 * 
+	 * @since 1.1
+	 */
+	public final static String	DENY	= "deny";
+
+	/**
+	 * Returns the Condition Infos for the Conditions that must be satisfied to
+	 * enable the Permissions.
+	 * 
+	 * @return The Condition Infos for the Conditions in this Conditional
+	 *         Permission Info.
+	 */
+	ConditionInfo[] getConditionInfos();
+
+	/**
+	 * Returns the Permission Infos for the Permissions in this Conditional
+	 * Permission Info.
+	 * 
+	 * @return The Permission Infos for the Permissions in this Conditional
+	 *         Permission Info.
+	 */
+	PermissionInfo[] getPermissionInfos();
+
+	/**
+	 * Removes this Conditional Permission Info from the Conditional Permission
+	 * Table.
+	 * <p>
+	 * Since this method changes the underlying permission table, any
+	 * {@link ConditionalPermissionUpdate}s that were created prior to calling
+	 * this method can no longer be committed.
+	 * 
+	 * @throws UnsupportedOperationException If this object was created by
+	 *         {@link ConditionalPermissionAdmin#newConditionalPermissionInfo}
+	 *         or obtained from a {@link ConditionalPermissionUpdate}. This
+	 *         method only functions if this object was obtained from one of the
+	 *         {@link ConditionalPermissionAdmin} methods deprecated in version
+	 *         1.1.
+	 * @throws SecurityException If the caller does not have
+	 *         {@code AllPermission}.
+	 * @deprecated Since 1.1. Use
+	 *             {@link ConditionalPermissionAdmin#newConditionalPermissionUpdate()}
+	 *             instead to manage the Conditional Permissions.
+	 */
+	void delete();
+
+	/**
+	 * Returns the name of this Conditional Permission Info.
+	 * 
+	 * @return The name of this Conditional Permission Info. This can be
+	 *         {@code null} if this Conditional Permission Info was created
+	 *         without a name.
+	 */
+	String getName();
+
+	/**
+	 * Returns the access decision for this Conditional Permission Info.
+	 * 
+	 * @return One of the following values:
+	 *         <ul>
+	 *         <li>{@link #ALLOW allow} - The access decision is
+	 *         &quot;allow&quot;.</li>
+	 *         <li>{@link #DENY deny} - The access decision is &quot;deny&quot;.
+	 *         </li>
+	 *         </ul>
+	 * @since 1.1
+	 */
+	String getAccessDecision();
+
+	/**
+	 * Returns the string encoding of this {@code ConditionalPermissionInfo} in
+	 * a form suitable for restoring this {@code ConditionalPermissionInfo}.
+	 * 
+	 * <p>
+	 * The encoded format is:
+	 * 
+	 * <pre>
+	 *   access {conditions permissions} name
+	 * </pre>
+	 * 
+	 * where <i>access</i> is the access decision, <i>conditions</i> is zero or
+	 * more {@link ConditionInfo#getEncoded() encoded conditions},
+	 * <i>permissions</i> is one or more {@link PermissionInfo#getEncoded()
+	 * encoded permissions} and <i>name</i> is the name of the
+	 * {@code ConditionalPermissionInfo}.
+	 * 
+	 * <p>
+	 * <i>name</i> is optional. If <i>name</i> is present in the encoded string,
+	 * it must quoted, beginning and ending with {@code &quot;}. The <i>name</i>
+	 * value must be encoded for proper parsing. Specifically, the
+	 * {@code &quot;}, {@code \}, carriage return, and line feed characters must
+	 * be escaped using {@code \&quot;}, {@code \\}, {@code \r}, and {@code \n},
+	 * respectively.
+	 * 
+	 * <p>
+	 * The encoded string contains no leading or trailing whitespace characters.
+	 * A single space character is used between <i>access</i> and <code>{</code>
+	 * and between <code>}</code> and <i>name</i>, if <i>name</i> is present.
+	 * All encoded conditions and permissions are separated by a single space
+	 * character.
+	 * 
+	 * @return The string encoding of this {@code ConditionalPermissionInfo}.
+	 * @since 1.1
+	 */
+	String getEncoded();
+
+	/**
+	 * Returns the string representation of this
+	 * {@code ConditionalPermissionInfo}. The string is created by calling
+	 * the {@code getEncoded} method on this
+	 * {@code ConditionalPermissionInfo}.
+	 * 
+	 * @return The string representation of this
+	 *         {@code ConditionalPermissionInfo}.
+	 * @since 1.1
+	 */
+	String toString();
+
+	/**
+	 * Determines the equality of two {@code ConditionalPermissionInfo}
+	 * objects.
+	 * 
+	 * This method checks that specified object has the same access decision,
+	 * conditions, permissions and name as this
+	 * {@code ConditionalPermissionInfo} object.
+	 * 
+	 * @param obj The object to test for equality with this
+	 *        {@code ConditionalPermissionInfo} object.
+	 * @return {@code true} if {@code obj} is a
+	 *         {@code ConditionalPermissionInfo}, and has the same access
+	 *         decision, conditions, permissions and name as this
+	 *         {@code ConditionalPermissionInfo} object; {@code false}
+	 *         otherwise.
+	 * @since 1.1
+	 */
+	 boolean equals(Object obj);
+ 
+	/**
+	 * Returns the hash code value for this object.
+	 * 
+	 * @return A hash code value for this object.
+	 * @since 1.1
+	 */
+	int hashCode();
+}

Added: karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionUpdate.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionUpdate.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionUpdate.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionUpdate.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.condpermadmin;
+
+import java.util.List;
+
+/**
+ * Update the Conditional Permission Table. There may be many update objects in
+ * the system at one time. If commit is called and the Conditional Permission
+ * Table has been modified since this update was created, then the call to
+ * commit will fail and this object should be discarded.
+ * 
+ * @ThreadSafe
+ * @noimplement
+ * @version $Id: 3b16b47db71fa449d60d5acdcc9f7dddc7679a25 $
+ * @since 1.1
+ */
+public interface ConditionalPermissionUpdate {
+	/**
+	 * This method returns the list of {@link ConditionalPermissionInfo}s for
+	 * this update. This list is originally based on the Conditional Permission
+	 * Table at the time this update was created. The list returned by this
+	 * method will be replace the Conditional Permission Table if commit is
+	 * called and is successful.
+	 * <p>
+	 * The {@link ConditionalPermissionInfo#delete delete} method of the
+	 * ConditionalPermissionInfos in the list must throw
+	 * UnsupportedOperationException.
+	 * <p>
+	 * The list returned by this method is ordered and the most significant
+	 * table entry is the first entry in the list.
+	 * 
+	 * @return A {@code List} of the {@link ConditionalPermissionInfo}s
+	 *         which represent the Conditional Permissions maintained by this
+	 *         update. Modifications to this list will not affect the
+	 *         Conditional Permission Table until successfully committed. The
+	 *         list may be empty if the Conditional Permission Table was empty
+	 *         when this update was created.
+	 */
+	List<ConditionalPermissionInfo> getConditionalPermissionInfos();
+
+	/**
+	 * Commit this update. If no changes have been made to the Conditional
+	 * Permission Table since this update was created, then this method will
+	 * replace the Conditional Permission Table with this update's Conditional
+	 * Permissions. This method may only be successfully called once on this
+	 * object.
+	 * <p>
+	 * If any of the {@link ConditionalPermissionInfo}s in the update list has
+	 * {@code null} as a name it will be replaced with a new
+	 * {@link ConditionalPermissionInfo} object that has a generated name which
+	 * is unique within the list.
+	 * <p>
+	 * No two entries in this update's Conditional Permissions may have the same
+	 * name. Other consistency checks may also be performed. If this update's
+	 * Conditional Permissions are determined to be inconsistent in some way
+	 * then an {@code IllegalStateException} will be thrown.
+	 * <p>
+	 * This method returns {@code false} if the commit did not occur
+	 * because the Conditional Permission Table has been modified since the
+	 * creation of this update.
+	 * 
+	 * @return {@code true} if the commit was successful.
+	 *         {@code false} if the commit did not occur because the
+	 *         Conditional Permission Table has been modified since the creation
+	 *         of this update.
+	 * @throws SecurityException If the caller does not have
+	 *         {@code AllPermission}.
+	 * @throws IllegalStateException If this update's Conditional Permissions
+	 *         are not valid or inconsistent. For example, this update has two
+	 *         Conditional Permissions in it with the same name.
+	 */
+	boolean commit();
+}

Added: karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/package-info.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/package-info.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/package-info.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/package-info.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) OSGi Alliance (2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Conditional Permission Admin Package Version 1.1.
+ * 
+ * <p>
+ * Bundles wishing to use this package must list the package in the
+ * Import-Package header of the bundle's manifest.
+ * 
+ * <p>
+ * Example import for consumers using the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.condpermadmin; version="[1.1,2.0)"}
+ * 
+ * @version $Id: cb84fc1342d7f8863ec8eae2dd244843246b2fc1 $
+ */
+
+package org.osgi.service.condpermadmin;

Added: karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/packageinfo
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/packageinfo?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/packageinfo (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/condpermadmin/packageinfo Thu Jan  5 14:16:33 2012
@@ -0,0 +1 @@
+version 1.1.1

Added: karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) OSGi Alliance (2001, 2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.packageadmin;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+
+/**
+ * An exported package.
+ * 
+ * Objects implementing this interface are created by the Package Admin service.
+ * 
+ * <p>
+ * The term <i>exported package</i> refers to a package that has been exported
+ * from a resolved bundle. This package may or may not be currently wired to
+ * other bundles.
+ * 
+ * <p>
+ * The information about an exported package provided by this object may change.
+ * An {@code ExportedPackage} object becomes stale if the package it
+ * references has been updated or removed as a result of calling
+ * {@code PackageAdmin.refreshPackages()}.
+ * 
+ * If this object becomes stale, its {@code getName()} and
+ * {@code getVersion()} methods continue to return their original values,
+ * {@code isRemovalPending()} returns {@code true}, and
+ * {@code getExportingBundle()} and {@code getImportingBundles()}
+ * return {@code null}.
+ * 
+ * @ThreadSafe
+ * @noimplement
+ * @deprecated The PackageAdmin service has been replaced by the
+ *             <code>org.osgi.framework.wiring</code> package.
+ * @version $Id: c56b99465e3f62a9808297a47de8cb7edb802119 $
+ */
+public interface ExportedPackage {
+	/**
+	 * Returns the name of the package associated with this exported package.
+	 * 
+	 * @return The name of this exported package.
+	 */
+	public String getName();
+
+	/**
+	 * Returns the bundle exporting the package associated with this exported
+	 * package.
+	 * 
+	 * @return The exporting bundle, or {@code null} if this
+	 *         {@code ExportedPackage} object has become stale.
+	 */
+	public Bundle getExportingBundle();
+
+	/**
+	 * Returns the resolved bundles that are currently wired to this exported
+	 * package.
+	 * 
+	 * <p>
+	 * Bundles which require the exporting bundle associated with this exported
+	 * package are considered to be wired to this exported package are included
+	 * in the returned array. See {@link RequiredBundle#getRequiringBundles()}.
+	 * 
+	 * @return The array of resolved bundles currently wired to this exported
+	 *         package, or {@code null} if this
+	 *         {@code ExportedPackage} object has become stale. The array
+	 *         will be empty if no bundles are wired to this exported package.
+	 */
+	public Bundle[] getImportingBundles();
+
+	/**
+	 * Returns the version of this exported package.
+	 * 
+	 * @return The version of this exported package, or {@code null} if
+	 *         no version information is available.
+	 * @deprecated As of 1.2, replaced by {@link #getVersion}.
+	 */
+	public String getSpecificationVersion();
+
+	/**
+	 * Returns the version of this exported package.
+	 * 
+	 * @return The version of this exported package, or
+	 *         {@link Version#emptyVersion} if no version information is
+	 *         available.
+	 * @since 1.2
+	 */
+	public Version getVersion();
+
+	/**
+	 * Returns {@code true} if the package associated with this
+	 * {@code ExportedPackage} object has been exported by a bundle that
+	 * has been updated or uninstalled.
+	 * 
+	 * @return {@code true} if the associated package is being exported
+	 *         by a bundle that has been updated or uninstalled, or if this
+	 *         {@code ExportedPackage} object has become stale;
+	 *         {@code false} otherwise.
+	 */
+	public boolean isRemovalPending();
+}

Added: karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) OSGi Alliance (2001, 2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.packageadmin;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * Framework service which allows bundle programmers to inspect the package
+ * wiring state of bundles in the Framework as well as other functions related
+ * to the class loader network among bundles.
+ * 
+ * <p>
+ * If present, there will only be a single instance of this service registered
+ * with the Framework.
+ * 
+ * @ThreadSafe
+ * @noimplement
+ * @version $Id: a268c3bdc986080fa16bdb2f56ba1d3800d030dd $
+ * @deprecated This service has been replaced by the
+ *             <code>org.osgi.framework.wiring</code> package.
+ * @see org.osgi.service.packageadmin.ExportedPackage
+ * @see org.osgi.service.packageadmin.RequiredBundle
+ */
+public interface PackageAdmin {
+	/**
+	 * Gets the exported packages for the specified bundle.
+	 * 
+	 * @param bundle The bundle whose exported packages are to be returned, or
+	 *        {@code null} if all exported packages are to be returned. If
+	 *        the specified bundle is the system bundle (that is, the bundle
+	 *        with id zero), this method returns all the packages known to be
+	 *        exported by the system bundle. This will include the package
+	 *        specified by the {@code org.osgi.framework.system.packages}
+	 *        system property as well as any other package exported by the
+	 *        framework implementation.
+	 * 
+	 * @return An array of exported packages, or {@code null} if the
+	 *         specified bundle has no exported packages.
+	 * @throws IllegalArgumentException If the specified {@code Bundle} was
+	 *         not created by the same framework instance that registered this
+	 *         {@code PackageAdmin} service.
+	 */
+	public ExportedPackage[] getExportedPackages(Bundle bundle);
+
+	/**
+	 * Gets the exported packages for the specified package name.
+	 * 
+	 * @param name The name of the exported packages to be returned.
+	 * 
+	 * @return An array of the exported packages, or {@code null} if no
+	 *         exported packages with the specified name exists.
+	 * @since 1.2
+	 */
+	public ExportedPackage[] getExportedPackages(String name);
+
+	/**
+	 * Gets the exported package for the specified package name.
+	 * 
+	 * <p>
+	 * If there are multiple exported packages with specified name, the exported
+	 * package with the highest version will be returned.
+	 * 
+	 * @param name The name of the exported package to be returned.
+	 * 
+	 * @return The exported package, or {@code null} if no exported
+	 *         package with the specified name exists.
+	 * @see #getExportedPackages(String)
+	 */
+	public ExportedPackage getExportedPackage(String name);
+
+	/**
+	 * Forces the update (replacement) or removal of packages exported by the
+	 * specified bundles.
+	 * 
+	 * <p>
+	 * If no bundles are specified, this method will update or remove any
+	 * packages exported by any bundles that were previously updated or
+	 * uninstalled since the last call to this method. The technique by which
+	 * this is accomplished may vary among different Framework implementations.
+	 * One permissible implementation is to stop and restart the Framework.
+	 * 
+	 * <p>
+	 * This method returns to the caller immediately and then performs the
+	 * following steps on a separate thread:
+	 * 
+	 * <ol>
+	 * <li>Compute a graph of bundles starting with the specified bundles. If no
+	 * bundles are specified, compute a graph of bundles starting with bundle
+	 * updated or uninstalled since the last call to this method. Add to the
+	 * graph any bundle that is wired to a package that is currently exported by
+	 * a bundle in the graph. The graph is fully constructed when there is no
+	 * bundle outside the graph that is wired to a bundle in the graph. The
+	 * graph may contain {@code UNINSTALLED} bundles that are currently
+	 * still exporting packages.
+	 * 
+	 * <li>Each bundle in the graph that is in the {@code ACTIVE} state
+	 * will be stopped as described in the {@code Bundle.stop} method.
+	 * 
+	 * <li>Each bundle in the graph that is in the {@code RESOLVED} state
+	 * is unresolved and thus moved to the {@code INSTALLED} state. The
+	 * effect of this step is that bundles in the graph are no longer
+	 * {@code RESOLVED}.
+	 * 
+	 * <li>Each bundle in the graph that is in the {@code UNINSTALLED}
+	 * state is removed from the graph and is now completely removed from the
+	 * Framework.
+	 * 
+	 * <li>Each bundle in the graph that was in the {@code ACTIVE} state
+	 * prior to Step 2 is started as described in the {@code Bundle.start}
+	 * method, causing all bundles required for the restart to be resolved. It
+	 * is possible that, as a result of the previous steps, packages that were
+	 * previously exported no longer are. Therefore, some bundles may be
+	 * unresolvable until another bundle offering a compatible package for
+	 * export has been installed in the Framework.
+	 * <li>A framework event of type
+	 * {@code FrameworkEvent.PACKAGES_REFRESHED} is fired.
+	 * </ol>
+	 * 
+	 * <p>
+	 * For any exceptions that are thrown during any of these steps, a
+	 * {@code FrameworkEvent} of type {@code ERROR} is fired
+	 * containing the exception. The source bundle for these events should be
+	 * the specific bundle to which the exception is related. If no specific
+	 * bundle can be associated with the exception then the System Bundle must
+	 * be used as the source bundle for the event.
+	 * 
+	 * @param bundles The bundles whose exported packages are to be updated or
+	 *        removed, or {@code null} for all bundles updated or
+	 *        uninstalled since the last call to this method.
+	 * @throws SecurityException If the caller does not have
+	 *         {@code AdminPermission[System Bundle,RESOLVE]} and the Java
+	 *         runtime environment supports permissions.
+	 * @throws IllegalArgumentException If the specified {@code Bundle}s
+	 *         were not created by the same framework instance that registered
+	 *         this {@code PackageAdmin} service.
+	 */
+	public void refreshPackages(Bundle[] bundles);
+
+	/**
+	 * Resolve the specified bundles. The Framework must attempt to resolve the
+	 * specified bundles that are unresolved. Additional bundles that are not
+	 * included in the specified bundles may be resolved as a result of calling
+	 * this method. A permissible implementation of this method is to attempt to
+	 * resolve all unresolved bundles installed in the framework.
+	 * 
+	 * <p>
+	 * If {@code null} is specified then the Framework will attempt to
+	 * resolve all unresolved bundles. This method must not cause any bundle to
+	 * be refreshed, stopped, or started. This method will not return until the
+	 * operation has completed.
+	 * 
+	 * @param bundles The bundles to resolve or {@code null} to resolve all
+	 *        unresolved bundles installed in the Framework.
+	 * @return {@code true} if all specified bundles are resolved;
+	 * @throws SecurityException If the caller does not have
+	 *         {@code AdminPermission[System Bundle,RESOLVE]} and the Java
+	 *         runtime environment supports permissions.
+	 * @throws IllegalArgumentException If the specified {@code Bundle}s
+	 *         were not created by the same framework instance that registered
+	 *         this {@code PackageAdmin} service.
+	 * @since 1.2
+	 */
+	public boolean resolveBundles(Bundle[] bundles);
+
+	/**
+	 * Returns an array of required bundles having the specified symbolic name.
+	 * 
+	 * <p>
+	 * If {@code null} is specified, then all required bundles will be
+	 * returned.
+	 * 
+	 * @param symbolicName The bundle symbolic name or {@code null} for
+	 *        all required bundles.
+	 * @return An array of required bundles or {@code null} if no
+	 *         required bundles exist for the specified symbolic name.
+	 * @since 1.2
+	 */
+	public RequiredBundle[] getRequiredBundles(String symbolicName);
+
+	/**
+	 * Returns the bundles with the specified symbolic name whose bundle version
+	 * is within the specified version range. If no bundles are installed that
+	 * have the specified symbolic name, then {@code null} is returned.
+	 * If a version range is specified, then only the bundles that have the
+	 * specified symbolic name and whose bundle versions belong to the specified
+	 * version range are returned. The returned bundles are ordered by version
+	 * in descending version order so that the first element of the array
+	 * contains the bundle with the highest version.
+	 * 
+	 * @see org.osgi.framework.Constants#BUNDLE_VERSION_ATTRIBUTE
+	 * @param symbolicName The symbolic name of the desired bundles.
+	 * @param versionRange The version range of the desired bundles, or
+	 *        {@code null} if all versions are desired.
+	 * @return An array of bundles with the specified name belonging to the
+	 *         specified version range ordered in descending version order, or
+	 *         {@code null} if no bundles are found.
+	 * @since 1.2
+	 */
+	public Bundle[] getBundles(String symbolicName, String versionRange);
+
+	/**
+	 * Returns an array of attached fragment bundles for the specified bundle.
+	 * If the specified bundle is a fragment then {@code null} is returned.
+	 * If no fragments are attached to the specified bundle then
+	 * {@code null} is returned.
+	 * <p>
+	 * This method does not attempt to resolve the specified bundle. If the
+	 * specified bundle is not resolved then {@code null} is returned.
+	 * 
+	 * @param bundle The bundle whose attached fragment bundles are to be
+	 *        returned.
+	 * @return An array of fragment bundles or {@code null} if the bundle
+	 *         does not have any attached fragment bundles or the bundle is not
+	 *         resolved.
+	 * @throws IllegalArgumentException If the specified {@code Bundle} was
+	 *         not created by the same framework instance that registered this
+	 *         {@code PackageAdmin} service.
+	 * @since 1.2
+	 */
+	public Bundle[] getFragments(Bundle bundle);
+
+	/**
+	 * Returns the host bundles to which the specified fragment bundle is
+	 * attached.
+	 * 
+	 * @param bundle The fragment bundle whose host bundles are to be returned.
+	 * @return An array containing the host bundles to which the specified
+	 *         fragment is attached or {@code null} if the specified bundle
+	 *         is not a fragment or is not attached to any host bundles.
+	 * @throws IllegalArgumentException If the specified {@code Bundle} was
+	 *         not created by the same framework instance that registered this
+	 *         {@code PackageAdmin} service.
+	 * @since 1.2
+	 */
+	public Bundle[] getHosts(Bundle bundle);
+
+	/**
+	 * Returns the bundle from which the specified class is loaded. The class
+	 * loader of the returned bundle must have been used to load the specified
+	 * class. If the class was not loaded by a bundle class loader then
+	 * {@code null} is returned.
+	 * 
+	 * @param clazz The class object from which to locate the bundle.
+	 * @return The bundle from which the specified class is loaded or
+	 *         {@code null} if the class was not loaded by a bundle class
+	 *         loader created by the same framework instance that registered
+	 *         this {@code PackageAdmin} service.
+	 * @since 1.2
+	 */
+	public Bundle getBundle(Class clazz);
+
+	/**
+	 * Bundle type indicating the bundle is a fragment bundle.
+	 * 
+	 * <p>
+	 * The value of {@code BUNDLE_TYPE_FRAGMENT} is 0x00000001.
+	 * 
+	 * @since 1.2
+	 */
+	public static final int	BUNDLE_TYPE_FRAGMENT	= 0x00000001;
+
+	/**
+	 * Returns the special type of the specified bundle. The bundle type values
+	 * are:
+	 * <ul>
+	 * <li>{@link #BUNDLE_TYPE_FRAGMENT}
+	 * </ul>
+	 * 
+	 * A bundle may be more than one type at a time. A type code is used to
+	 * identify the bundle type for future extendability.
+	 * 
+	 * <p>
+	 * If a bundle is not one or more of the defined types then 0x00000000 is
+	 * returned.
+	 * 
+	 * @param bundle The bundle for which to return the special type.
+	 * @return The special type of the bundle.
+	 * @throws IllegalArgumentException If the specified {@code Bundle} was
+	 *         not created by the same framework instance that registered this
+	 *         {@code PackageAdmin} service.
+	 * @since 1.2
+	 */
+	public int getBundleType(Bundle bundle);
+}

Added: karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.packageadmin;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+
+/**
+ * A required bundle.
+ * 
+ * Objects implementing this interface are created by the Package Admin service.
+ * 
+ * <p>
+ * The term <i>required bundle</i> refers to a resolved bundle that has a bundle
+ * symbolic name and is not a fragment. That is, a bundle that may be required
+ * by other bundles. This bundle may or may not be currently required by other
+ * bundles.
+ * 
+ * <p>
+ * The information about a required bundle provided by this object may change. A
+ * {@code RequiredBundle} object becomes stale if an exported package of
+ * the bundle it references has been updated or removed as a result of calling
+ * {@code PackageAdmin.refreshPackages()}).
+ * 
+ * If this object becomes stale, its {@code getSymbolicName()} and
+ * {@code getVersion()} methods continue to return their original values,
+ * {@code isRemovalPending()} returns true, and {@code getBundle()}
+ * and {@code getRequiringBundles()} return {@code null}.
+ * 
+ * @since 1.2
+ * @ThreadSafe
+ * @noimplement
+ * @deprecated The PackageAdmin service has been replaced by the
+ *             <code>org.osgi.framework.wiring</code> package.
+ * @version $Id: 1606b0422cae6769b7eedc2d565df61841da1e22 $
+ */
+public interface RequiredBundle {
+	/**
+	 * Returns the symbolic name of this required bundle.
+	 * 
+	 * @return The symbolic name of this required bundle.
+	 */
+	public String getSymbolicName();
+
+	/**
+	 * Returns the bundle associated with this required bundle.
+	 * 
+	 * @return The bundle, or {@code null} if this
+	 *         {@code RequiredBundle} object has become stale.
+	 */
+	public Bundle getBundle();
+
+	/**
+	 * Returns the bundles that currently require this required bundle.
+	 * 
+	 * <p>
+	 * If this required bundle is required and then re-exported by another
+	 * bundle then all the requiring bundles of the re-exporting bundle are
+	 * included in the returned array.
+	 * 
+	 * @return An array of bundles currently requiring this required bundle, or
+	 *         {@code null} if this {@code RequiredBundle} object
+	 *         has become stale. The array will be empty if no bundles require
+	 *         this required package.
+	 */
+	public Bundle[] getRequiringBundles();
+
+	/**
+	 * Returns the version of this required bundle.
+	 * 
+	 * @return The version of this required bundle, or
+	 *         {@link Version#emptyVersion} if no version information is
+	 *         available.
+	 */
+	public Version getVersion();
+
+	/**
+	 * Returns {@code true} if the bundle associated with this
+	 * {@code RequiredBundle} object has been updated or uninstalled.
+	 * 
+	 * @return {@code true} if the required bundle has been updated or
+	 *         uninstalled, or if the {@code RequiredBundle} object has
+	 *         become stale; {@code false} otherwise.
+	 */
+	public boolean isRemovalPending();
+}

Added: karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/package-info.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/package-info.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/package-info.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/package-info.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) OSGi Alliance (2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package Admin Package Version 1.2.
+ * 
+ * <p>
+ * <b>Deprecated.</b>
+ * <i>This package is deprecated and has been replaced by the
+ * {@code org.osgi.framework.wiring} package.</i>
+ *
+ * <p>
+ * Bundles wishing to use this package must list the package in the
+ * Import-Package header of the bundle's manifest.
+ * 
+ * <p>
+ * Example import for consumers using the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.packageadmin; version="[1.2,2.0)"}
+ * 
+ * @version $Id: b1c7db22b9c84e48d3c6c711f0ed976e825053c9 $
+ */
+
+package org.osgi.service.packageadmin;

Added: karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/packageinfo
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/packageinfo?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/packageinfo (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/packageadmin/packageinfo Thu Jan  5 14:16:33 2012
@@ -0,0 +1 @@
+version 1.2

Added: karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) OSGi Alliance (2001, 2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.permissionadmin;
+
+/**
+ * The Permission Admin service allows management agents to manage the
+ * permissions of bundles. There is at most one Permission Admin service present
+ * in the OSGi environment.
+ * <p>
+ * Access to the Permission Admin service is protected by corresponding
+ * {@code ServicePermission}. In addition {@code AdminPermission}
+ * is required to actually set permissions.
+ * 
+ * <p>
+ * Bundle permissions are managed using a permission table. A bundle's location
+ * serves as the key into this permission table. The value of a table entry is
+ * the set of permissions (of type {@code PermissionInfo}) granted to
+ * the bundle named by the given location. A bundle may have an entry in the
+ * permission table prior to being installed in the Framework.
+ * 
+ * <p>
+ * The permissions specified in {@code setDefaultPermissions} are used as
+ * the default permissions which are granted to all bundles that do not have an
+ * entry in the permission table.
+ * 
+ * <p>
+ * Any changes to a bundle's permissions in the permission table will take
+ * effect no later than when bundle's
+ * {@code java.security.ProtectionDomain} is next involved in a
+ * permission check, and will be made persistent.
+ * 
+ * <p>
+ * Only permission classes on the system classpath or from an exported package
+ * are considered during a permission check. Additionally, only permission
+ * classes that are subclasses of {@code java.security.Permission} and
+ * define a 2-argument constructor that takes a <i>name </i> string and an
+ * <i>actions </i> string can be used.
+ * <p>
+ * Permissions implicitly granted by the Framework (for example, a bundle's
+ * permission to access its persistent storage area) cannot be changed, and are
+ * not reflected in the permissions returned by {@code getPermissions}
+ * and {@code getDefaultPermissions}.
+ * 
+ * @ThreadSafe
+ * @noimplement
+ * @version $Id: 91132d707097c085fdb3fb7241c9599335427082 $
+ */
+public interface PermissionAdmin {
+	/**
+	 * Gets the permissions assigned to the bundle with the specified location.
+	 * 
+	 * @param location The location of the bundle whose permissions are to be
+	 *        returned.
+	 * 
+	 * @return The permissions assigned to the bundle with the specified
+	 *         location, or {@code null} if that bundle has not been
+	 *         assigned any permissions.
+	 */
+	PermissionInfo[] getPermissions(String location);
+
+	/**
+	 * Assigns the specified permissions to the bundle with the specified
+	 * location.
+	 * 
+	 * @param location The location of the bundle that will be assigned the
+	 *        permissions.
+	 * @param permissions The permissions to be assigned, or {@code null}
+	 *        if the specified location is to be removed from the permission
+	 *        table.
+	 * @throws SecurityException If the caller does not have
+	 *         {@code AllPermission}.
+	 */
+	void setPermissions(String location, PermissionInfo[] permissions);
+
+	/**
+	 * Returns the bundle locations that have permissions assigned to them, that
+	 * is, bundle locations for which an entry exists in the permission table.
+	 * 
+	 * @return The locations of bundles that have been assigned any permissions,
+	 *         or {@code null} if the permission table is empty.
+	 */
+	String[] getLocations();
+
+	/**
+	 * Gets the default permissions.
+	 * 
+	 * <p>
+	 * These are the permissions granted to any bundle that does not have
+	 * permissions assigned to its location.
+	 * 
+	 * @return The default permissions, or {@code null} if no default
+	 *         permissions are set.
+	 */
+	PermissionInfo[] getDefaultPermissions();
+
+	/**
+	 * Sets the default permissions.
+	 * 
+	 * <p>
+	 * These are the permissions granted to any bundle that does not have
+	 * permissions assigned to its location.
+	 * 
+	 * @param permissions The default permissions, or {@code null} if the
+	 *        default permissions are to be removed from the permission table.
+	 * @throws SecurityException If the caller does not have
+	 *         {@code AllPermission}.
+	 */
+	void setDefaultPermissions(PermissionInfo[] permissions);
+}

Added: karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) OSGi Alliance (2001, 2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.permissionadmin;
+
+/**
+ * Permission representation used by the Permission Admin service.
+ * 
+ * <p>
+ * This class encapsulates three pieces of information: a Permission <i>type
+ * </i> (class name), which must be a subclass of
+ * {@code java.security.Permission}, and the <i>name</i> and <i>actions</i>
+ * arguments passed to its constructor.
+ * 
+ * <p>
+ * In order for a permission represented by a {@code PermissionInfo} to be
+ * instantiated and considered during a permission check, its Permission class
+ * must be available from the system classpath or an exported package. This
+ * means that the instantiation of a permission represented by a
+ * {@code PermissionInfo} may be delayed until the package containing its
+ * Permission class has been exported by a bundle.
+ * 
+ * @Immutable
+ * @version $Id: b9516d07ada162fb8fc750f09e1e3a686189c46b $
+ */
+public class PermissionInfo {
+	private final String	type;
+	private final String	name;
+	private final String	actions;
+
+	/**
+	 * Constructs a {@code PermissionInfo} from the specified type, name,
+	 * and actions.
+	 * 
+	 * @param type The fully qualified class name of the permission represented
+	 *        by this {@code PermissionInfo}. The class must be a subclass
+	 *        of {@code java.security.Permission} and must define a
+	 *        2-argument constructor that takes a <i>name</i> string and an
+	 *        <i>actions</i> string.
+	 * 
+	 * @param name The permission name that will be passed as the first argument
+	 *        to the constructor of the {@code Permission} class identified
+	 *        by {@code type}.
+	 * 
+	 * @param actions The permission actions that will be passed as the second
+	 *        argument to the constructor of the {@code Permission} class
+	 *        identified by {@code type}.
+	 * 
+	 * @throws NullPointerException If {@code type} is {@code null}.
+	 * @throws IllegalArgumentException If {@code action} is not
+	 *         {@code null} and {@code name} is {@code null}.
+	 */
+	public PermissionInfo(String type, String name, String actions) {
+		this.type = type;
+		this.name = name;
+		this.actions = actions;
+		if (type == null) {
+			throw new NullPointerException("type is null");
+		}
+		if ((name == null) && (actions != null)) {
+			throw new IllegalArgumentException("name missing");
+		}
+	}
+
+	/**
+	 * Constructs a {@code PermissionInfo} object from the specified
+	 * encoded {@code PermissionInfo} string. White space in the encoded
+	 * {@code PermissionInfo} string is ignored.
+	 * 
+	 * 
+	 * @param encodedPermission The encoded {@code PermissionInfo}.
+	 * @see #getEncoded
+	 * @throws IllegalArgumentException If the specified
+	 *         {@code encodedPermission} is not properly formatted.
+	 */
+	public PermissionInfo(String encodedPermission) {
+		if (encodedPermission == null) {
+			throw new NullPointerException("missing encoded permission");
+		}
+		if (encodedPermission.length() == 0) {
+			throw new IllegalArgumentException("empty encoded permission");
+		}
+		String parsedType = null;
+		String parsedName = null;
+		String parsedActions = null;
+		try {
+			char[] encoded = encodedPermission.toCharArray();
+			int length = encoded.length;
+			int pos = 0;
+
+			/* skip whitespace */
+			while (Character.isWhitespace(encoded[pos])) {
+				pos++;
+			}
+
+			/* the first character must be '(' */
+			if (encoded[pos] != '(') {
+				throw new IllegalArgumentException("expecting open parenthesis");
+			}
+			pos++;
+
+			/* skip whitespace */
+			while (Character.isWhitespace(encoded[pos])) {
+				pos++;
+			}
+
+			/* type is not quoted or encoded */
+			int begin = pos;
+			while (!Character.isWhitespace(encoded[pos])
+					&& (encoded[pos] != ')')) {
+				pos++;
+			}
+			if (pos == begin || encoded[begin] == '"') {
+				throw new IllegalArgumentException("expecting type");
+			}
+			parsedType = new String(encoded, begin, pos - begin);
+
+			/* skip whitespace */
+			while (Character.isWhitespace(encoded[pos])) {
+				pos++;
+			}
+
+			/* type may be followed by name which is quoted and encoded */
+			if (encoded[pos] == '"') {
+				pos++;
+				begin = pos;
+				while (encoded[pos] != '"') {
+					if (encoded[pos] == '\\') {
+						pos++;
+					}
+					pos++;
+				}
+				parsedName = unescapeString(encoded, begin, pos);
+				pos++;
+
+				if (Character.isWhitespace(encoded[pos])) {
+					/* skip whitespace */
+					while (Character.isWhitespace(encoded[pos])) {
+						pos++;
+					}
+
+					/*
+					 * name may be followed by actions which is quoted and
+					 * encoded
+					 */
+					if (encoded[pos] == '"') {
+						pos++;
+						begin = pos;
+						while (encoded[pos] != '"') {
+							if (encoded[pos] == '\\') {
+								pos++;
+							}
+							pos++;
+						}
+						parsedActions = unescapeString(encoded, begin, pos);
+						pos++;
+
+						/* skip whitespace */
+						while (Character.isWhitespace(encoded[pos])) {
+							pos++;
+						}
+					}
+				}
+			}
+
+			/* the final character must be ')' */
+			char c = encoded[pos];
+			pos++;
+			while ((pos < length) && Character.isWhitespace(encoded[pos])) {
+				pos++;
+			}
+			if ((c != ')') || (pos != length)) {
+				throw new IllegalArgumentException(
+						"expecting close parenthesis");
+			}
+		}
+		catch (ArrayIndexOutOfBoundsException e) {
+			throw new IllegalArgumentException("parsing terminated abruptly");
+		}
+
+		type = parsedType;
+		name = parsedName;
+		actions = parsedActions;
+	}
+
+	/**
+	 * Returns the string encoding of this {@code PermissionInfo} in a form
+	 * suitable for restoring this {@code PermissionInfo}.
+	 * 
+	 * <p>
+	 * The encoded format is:
+	 * 
+	 * <pre>
+	 * (type)
+	 * </pre>
+	 * 
+	 * or
+	 * 
+	 * <pre>
+	 * (type &quot;name&quot;)
+	 * </pre>
+	 * 
+	 * or
+	 * 
+	 * <pre>
+	 * (type &quot;name&quot; &quot;actions&quot;)
+	 * </pre>
+	 * 
+	 * where <i>name</i> and <i>actions</i> are strings that must be encoded for
+	 * proper parsing. Specifically, the {@code &quot;},{@code \},
+	 * carriage return, and line feed characters must be escaped using
+	 * {@code \&quot;}, {@code \\},{@code \r}, and
+	 * {@code \n}, respectively.
+	 * 
+	 * <p>
+	 * The encoded string contains no leading or trailing whitespace characters.
+	 * A single space character is used between <i>type</i> and
+	 * &quot;<i>name</i>&quot; and between &quot;<i>name</i>&quot; and
+	 * &quot;<i>actions</i>&quot;.
+	 * 
+	 * @return The string encoding of this {@code PermissionInfo}.
+	 */
+	public final String getEncoded() {
+		StringBuffer output = new StringBuffer(
+				8
+						+ type.length()
+						+ ((((name == null) ? 0 : name.length()) + ((actions == null) ? 0
+								: actions.length())) << 1));
+		output.append('(');
+		output.append(type);
+		if (name != null) {
+			output.append(" \"");
+			escapeString(name, output);
+			if (actions != null) {
+				output.append("\" \"");
+				escapeString(actions, output);
+			}
+			output.append('\"');
+		}
+		output.append(')');
+		return output.toString();
+	}
+
+	/**
+	 * Returns the string representation of this {@code PermissionInfo}.
+	 * The string is created by calling the {@code getEncoded} method on
+	 * this {@code PermissionInfo}.
+	 * 
+	 * @return The string representation of this {@code PermissionInfo}.
+	 */
+	public String toString() {
+		return getEncoded();
+	}
+
+	/**
+	 * Returns the fully qualified class name of the permission represented by
+	 * this {@code PermissionInfo}.
+	 * 
+	 * @return The fully qualified class name of the permission represented by
+	 *         this {@code PermissionInfo}.
+	 */
+	public final String getType() {
+		return type;
+	}
+
+	/**
+	 * Returns the name of the permission represented by this
+	 * {@code PermissionInfo}.
+	 * 
+	 * @return The name of the permission represented by this
+	 *         {@code PermissionInfo}, or {@code null} if the
+	 *         permission does not have a name.
+	 */
+	public final String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns the actions of the permission represented by this
+	 * {@code PermissionInfo}.
+	 * 
+	 * @return The actions of the permission represented by this
+	 *         {@code PermissionInfo}, or {@code null} if the
+	 *         permission does not have any actions associated with it.
+	 */
+	public final String getActions() {
+		return actions;
+	}
+
+	/**
+	 * Determines the equality of two {@code PermissionInfo} objects.
+	 * 
+	 * This method checks that specified object has the same type, name and
+	 * actions as this {@code PermissionInfo} object.
+	 * 
+	 * @param obj The object to test for equality with this
+	 *        {@code PermissionInfo} object.
+	 * @return {@code true} if {@code obj} is a
+	 *         {@code PermissionInfo}, and has the same type, name and
+	 *         actions as this {@code PermissionInfo} object;
+	 *         {@code false} otherwise.
+	 */
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+		if (!(obj instanceof PermissionInfo)) {
+			return false;
+		}
+		PermissionInfo other = (PermissionInfo) obj;
+		if (!type.equals(other.type) || ((name == null) ^ (other.name == null))
+				|| ((actions == null) ^ (other.actions == null))) {
+			return false;
+		}
+		if (name != null) {
+			if (actions != null) {
+				return name.equals(other.name) && actions.equals(other.actions);
+			}
+			else {
+				return name.equals(other.name);
+			}
+		}
+		else {
+			return true;
+		}
+	}
+
+	/**
+	 * Returns the hash code value for this object.
+	 * 
+	 * @return A hash code value for this object.
+	 */
+	public int hashCode() {
+		int h = 31 * 17 + type.hashCode();
+		if (name != null) {
+			h = 31 * h + name.hashCode();
+			if (actions != null) {
+				h = 31 * h + actions.hashCode();
+			}
+		}
+		return h;
+	}
+
+	/**
+	 * This escapes the quotes, backslashes, \n, and \r in the string using a
+	 * backslash and appends the newly escaped string to a StringBuffer.
+	 */
+	private static void escapeString(String str, StringBuffer output) {
+		int len = str.length();
+		for (int i = 0; i < len; i++) {
+			char c = str.charAt(i);
+			switch (c) {
+				case '"' :
+				case '\\' :
+					output.append('\\');
+					output.append(c);
+					break;
+				case '\r' :
+					output.append("\\r");
+					break;
+				case '\n' :
+					output.append("\\n");
+					break;
+				default :
+					output.append(c);
+					break;
+			}
+		}
+	}
+
+	/**
+	 * Takes an encoded character array and decodes it into a new String.
+	 */
+	private static String unescapeString(char[] str, int begin, int end) {
+		StringBuffer output = new StringBuffer(end - begin);
+		for (int i = begin; i < end; i++) {
+			char c = str[i];
+			if (c == '\\') {
+				i++;
+				if (i < end) {
+					c = str[i];
+					switch (c) {
+						case '"' :
+						case '\\' :
+							break;
+						case 'r' :
+							c = '\r';
+							break;
+						case 'n' :
+							c = '\n';
+							break;
+						default :
+							c = '\\';
+							i--;
+							break;
+					}
+				}
+			}
+			output.append(c);
+		}
+
+		return output.toString();
+	}
+}

Added: karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/package-info.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/package-info.java?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/package-info.java (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/package-info.java Thu Jan  5 14:16:33 2012
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) OSGi Alliance (2010). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Permission Admin Package Version 1.2.
+ * 
+ * <p>
+ * Bundles wishing to use this package must list the package in the
+ * Import-Package header of the bundle's manifest.
+ * 
+ * <p>
+ * Example import for consumers using the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.permissionadmin; version="[1.2,2.0)"}
+ * 
+ * @version $Id: 4e7435396ab10ff2d4f5cce1edbffc3b0ccd5e84 $
+ */
+
+package org.osgi.service.permissionadmin;

Added: karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/packageinfo
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/packageinfo?rev=1227602&view=auto
==============================================================================
--- karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/packageinfo (added)
+++ karaf/trunk/main/src/main/java/org/osgi/service/permissionadmin/packageinfo Thu Jan  5 14:16:33 2012
@@ -0,0 +1 @@
+version 1.2