Somehow these two files were missed when I updated to the ASL licensed files.


git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@386660 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.osgi/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java b/org.osgi/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java
index 904b318..4f8b25f 100644
--- a/org.osgi/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java
+++ b/org.osgi/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java
@@ -1,113 +1,121 @@
-/*
- * $Header: /cvshome/build/org.osgi.service.permissionadmin/src/org/osgi/service/permissionadmin/PermissionAdmin.java,v 1.7 2005/05/13 20:33:46 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2001, 2005). 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.
- */
-
-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</code>. In addition <code>AdminPermission</code> 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</code>) 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</code> 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</code>
- * 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</code> 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</code> and
- * <code>getDefaultPermissions</code>.
- * 
- * @version $Revision: 1.7 $
- */
-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</code> 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</code> if
-	 *        the specified location is to be removed from the permission table.
-	 * @exception SecurityException if the caller does not have the
-	 *            <code>AdminPermission</code>.
-	 */
-	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</code> 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</code> 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</code> if the
-	 *        default permissions are to be removed from the permission table.
-	 * @exception SecurityException if the caller does not have the
-	 *            <code>AdminPermission</code>.
-	 */
-	void setDefaultPermissions(PermissionInfo[] permissions);
+/*

+ * $Header: /cvshome/build/org.osgi.service.permissionadmin/src/org/osgi/service/permissionadmin/PermissionAdmin.java,v 1.11 2006/03/14 01:21:28 hargrave Exp $

+ * 

+ * Copyright (c) OSGi Alliance (2001, 2005). 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</code>. In addition <code>AdminPermission</code> 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</code>) 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</code> 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</code>

+ * 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</code> 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</code> and

+ * <code>getDefaultPermissions</code>.

+ * 

+ * @version $Revision: 1.11 $

+ */

+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</code> 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</code> if

+	 *        the specified location is to be removed from the permission table.

+	 * @throws SecurityException If the caller does not have

+	 *            <code>AllPermission</code>.

+	 */

+	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</code> 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</code> 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</code> if the

+	 *        default permissions are to be removed from the permission table.

+	 * @throws SecurityException If the caller does not have

+	 *            <code>AllPermission</code>.

+	 */

+	void setDefaultPermissions(PermissionInfo[] permissions);

 }
\ No newline at end of file
diff --git a/org.osgi/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java b/org.osgi/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java
index 3502e89..fff10b5 100644
--- a/org.osgi/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java
+++ b/org.osgi/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java
@@ -1,360 +1,406 @@
-/*
- * $Header: /cvshome/build/org.osgi.service.permissionadmin/src/org/osgi/service/permissionadmin/PermissionInfo.java,v 1.8 2005/06/21 15:41:57 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2001, 2005). 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.
- */
-
-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</code>, 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</code> 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</code> may be delayed until the package containing its
- * Permission class has been exported by a bundle.
- * 
- * @version $Revision: 1.8 $
- */
-public class PermissionInfo {
-	private String	type;
-	private String	name;
-	private String	actions;
-
-	/**
-	 * Constructs a <code>PermissionInfo</code> from the given type, name, and
-	 * actions.
-	 * 
-	 * @param type The fully qualified class name of the permission represented
-	 *        by this <code>PermissionInfo</code>. The class must be a subclass
-	 *        of <code>java.security.Permission</code> 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</code> class identified
-	 *        by <code>type</code>.
-	 * 
-	 * @param actions The permission actions that will be passed as the second
-	 *        argument to the constructor of the <code>Permission</code> class
-	 *        identified by <code>type</code>.
-	 * 
-	 * @exception java.lang.NullPointerException if <code>type</code> is
-	 *            <code>null</code>.
-	 * @exception java.lang.IllegalArgumentException if <code>action</code> is not
-	 *            <code>null</code> and <code>name</code> is <code>null</code>.
-	 */
-	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</code> object from the given encoded
-	 * <code>PermissionInfo</code> string.
-	 * 
-	 * @param encodedPermission The encoded <code>PermissionInfo</code>.
-	 * @see #getEncoded
-	 * @exception java.lang.IllegalArgumentException if
-	 *            <code>encodedPermission</code> 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");
-		}
-		try {
-			char[] encoded = encodedPermission.toCharArray();
-			/* the first character must be '(' */
-			if (encoded[0] != '(') {
-				throw new IllegalArgumentException(
-						"first character not open parenthesis");
-			}
-			/* type is not quoted or encoded */
-			int end = 1;
-			int begin = end;
-			while ((encoded[end] != ' ') && (encoded[end] != ')')) {
-				end++;
-			}
-			if (end == begin) {
-				throw new IllegalArgumentException("expecting type");
-			}
-			this.type = new String(encoded, begin, end - begin);
-			/* type may be followed by name which is quoted and encoded */
-			// TODO Need to support multiple spaces
-			if (encoded[end] == ' ') {
-				end++;
-				if (encoded[end] != '"') {
-					throw new IllegalArgumentException("expecting quoted name");
-				}
-				end++;
-				begin = end;
-				while (encoded[end] != '"') {
-					if (encoded[end] == '\\') {
-						end++;
-					}
-					end++;
-				}
-				this.name = decodeString(encoded, begin, end);
-				end++;
-				/* name may be followed by actions which is quoted and encoded */
-				// TODO Need to support multiple spaces
-				if (encoded[end] == ' ') {
-					end++;
-					if (encoded[end] != '"') {
-						throw new IllegalArgumentException(
-								"expecting quoted actions");
-					}
-					end++;
-					begin = end;
-					while (encoded[end] != '"') {
-						if (encoded[end] == '\\') {
-							end++;
-						}
-						end++;
-					}
-					this.actions = decodeString(encoded, begin, end);
-					end++;
-				}
-			}
-			/* the final character must be ')' */
-			if ((encoded[end] != ')') || (end + 1 != encoded.length)) {
-				throw new IllegalArgumentException("last character not "
-						+ "close parenthesis");
-			}
-		}
-		catch (ArrayIndexOutOfBoundsException e) {
-			throw new IllegalArgumentException("parsing terminated abruptly");
-		}
-	}
-
-	/**
-	 * Returns the string encoding of this <code>PermissionInfo</code> in a form
-	 * suitable for restoring this <code>PermissionInfo</code>.
-	 * 
-	 * <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 are encoded for
-	 * proper parsing. Specifically, the <code>"</code>,<code>\</code>, carriage
-	 * return, and linefeed characters are escaped using <code>\"</code>,
-	 * <code>\\</code>,<code>\r</code>, and <code>\n</code>, respectively.
-	 * 
-	 * <p>
-	 * The encoded string must contain no leading or trailing whitespace
-	 * characters. A single space character must be 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</code>.
-	 */
-	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(" \"");
-			encodeString(name, output);
-			if (actions != null) {
-				output.append("\" \"");
-				encodeString(actions, output);
-			}
-			output.append('\"');
-		}
-		output.append(')');
-		return (output.toString());
-	}
-
-	/**
-	 * Returns the string representation of this <code>PermissionInfo</code>. The
-	 * string is created by calling the <code>getEncoded</code> method on this
-	 * <code>PermissionInfo</code>.
-	 * 
-	 * @return The string representation of this <code>PermissionInfo</code>.
-	 */
-	public String toString() {
-		return (getEncoded());
-	}
-
-	/**
-	 * Returns the fully qualified class name of the permission represented by
-	 * this <code>PermissionInfo</code>.
-	 * 
-	 * @return The fully qualified class name of the permission represented by
-	 *         this <code>PermissionInfo</code>.
-	 */
-	public final String getType() {
-		return (type);
-	}
-
-	/**
-	 * Returns the name of the permission represented by this
-	 * <code>PermissionInfo</code>.
-	 * 
-	 * @return The name of the permission represented by this
-	 *         <code>PermissionInfo</code>, or <code>null</code> 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</code>.
-	 * 
-	 * @return The actions of the permission represented by this
-	 *         <code>PermissionInfo</code>, or <code>null</code> if the permission
-	 *         does not have any actions associated with it.
-	 */
-	public final String getActions() {
-		return (actions);
-	}
-
-	/**
-	 * Determines the equality of two <code>PermissionInfo</code> objects.
-	 * 
-	 * This method checks that specified object has the same type, name and
-	 * actions as this <code>PermissionInfo</code> object.
-	 * 
-	 * @param obj The object to test for equality with this
-	 *        <code>PermissionInfo</code> object.
-	 * @return <code>true</code> if <code>obj</code> is a <code>PermissionInfo</code>,
-	 *         and has the same type, name and actions as this
-	 *         <code>PermissionInfo</code> object; <code>false</code> 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 hash = type.hashCode();
-		if (name != null) {
-			hash ^= name.hashCode();
-			if (actions != null) {
-				hash ^= actions.hashCode();
-			}
-		}
-		return (hash);
-	}
-
-	/**
-	 * 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 encodeString(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 decodeString(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];
-					if (c == 'n') {
-						c = '\n';
-					}
-					else
-						if (c == 'r') {
-							c = '\r';
-						}
-				}
-			}
-			output.append(c);
-		}
-		return (output.toString());
-	}
+/*

+ * $Header: /cvshome/build/org.osgi.service.permissionadmin/src/org/osgi/service/permissionadmin/PermissionInfo.java,v 1.15 2006/03/14 01:21:28 hargrave Exp $

+ * 

+ * Copyright (c) OSGi Alliance (2001, 2005). 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</code>, 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</code> 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</code> may be delayed until the package containing its

+ * Permission class has been exported by a bundle.

+ * 

+ * @version $Revision: 1.15 $

+ */

+public class PermissionInfo {

+	private String	type;

+	private String	name;

+	private String	actions;

+

+	/**

+	 * Constructs a <code>PermissionInfo</code> from the specified type, name, and

+	 * actions.

+	 * 

+	 * @param type The fully qualified class name of the permission represented

+	 *        by this <code>PermissionInfo</code>. The class must be a subclass

+	 *        of <code>java.security.Permission</code> 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</code> class identified

+	 *        by <code>type</code>.

+	 * 

+	 * @param actions The permission actions that will be passed as the second

+	 *        argument to the constructor of the <code>Permission</code> class

+	 *        identified by <code>type</code>.

+	 * 

+	 * @throws java.lang.NullPointerException if <code>type</code> is

+	 *            <code>null</code>.

+	 * @throws java.lang.IllegalArgumentException if <code>action</code> is not

+	 *            <code>null</code> and <code>name</code> is <code>null</code>.

+	 */

+	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</code> object from the specified encoded

+	 * <code>PermissionInfo</code> string. White space in the encoded

+	 * <code>PermissionInfo</code> string is ignored.

+	 * 

+	 * 

+	 * @param encodedPermission The encoded <code>PermissionInfo</code>.

+	 * @see #getEncoded

+	 * @throws java.lang.IllegalArgumentException If the 

+	 *            <code>encodedPermission</code> 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");

+		}

+		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");

+			}

+			this.type = 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++;

+				}

+				this.name = 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++;

+						}

+						this.actions = 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");

+		}

+	}

+

+	/**

+	 * Returns the string encoding of this <code>PermissionInfo</code> in a form

+	 * suitable for restoring this <code>PermissionInfo</code>.

+	 * 

+	 * <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 are encoded for

+	 * proper parsing. Specifically, the <code>"</code>,<code>\</code>, carriage

+	 * return, and linefeed characters are escaped using <code>\"</code>,

+	 * <code>\\</code>,<code>\r</code>, and <code>\n</code>, 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</code>.

+	 */

+	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</code>. The

+	 * string is created by calling the <code>getEncoded</code> method on this

+	 * <code>PermissionInfo</code>.

+	 * 

+	 * @return The string representation of this <code>PermissionInfo</code>.

+	 */

+	public String toString() {

+		return getEncoded();

+	}

+

+	/**

+	 * Returns the fully qualified class name of the permission represented by

+	 * this <code>PermissionInfo</code>.

+	 * 

+	 * @return The fully qualified class name of the permission represented by

+	 *         this <code>PermissionInfo</code>.

+	 */

+	public final String getType() {

+		return type;

+	}

+

+	/**

+	 * Returns the name of the permission represented by this

+	 * <code>PermissionInfo</code>.

+	 * 

+	 * @return The name of the permission represented by this

+	 *         <code>PermissionInfo</code>, or <code>null</code> 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</code>.

+	 * 

+	 * @return The actions of the permission represented by this

+	 *         <code>PermissionInfo</code>, or <code>null</code> if the permission

+	 *         does not have any actions associated with it.

+	 */

+	public final String getActions() {

+		return actions;

+	}

+

+	/**

+	 * Determines the equality of two <code>PermissionInfo</code> objects.

+	 * 

+	 * This method checks that specified object has the same type, name and

+	 * actions as this <code>PermissionInfo</code> object.

+	 * 

+	 * @param obj The object to test for equality with this

+	 *        <code>PermissionInfo</code> object.

+	 * @return <code>true</code> if <code>obj</code> is a <code>PermissionInfo</code>,

+	 *         and has the same type, name and actions as this

+	 *         <code>PermissionInfo</code> object; <code>false</code> 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 hash = type.hashCode();

+		if (name != null) {

+			hash ^= name.hashCode();

+			if (actions != null) {

+				hash ^= actions.hashCode();

+			}

+		}

+		return hash;

+	}

+

+	/**

+	 * 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();

+	}

 }
\ No newline at end of file