Updated to the latest R4.2 interfaces.


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@782737 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/AdminPermission.java b/org.osgi.core/src/main/java/org/osgi/framework/AdminPermission.java
index 396e114..c55fc7b 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/AdminPermission.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/AdminPermission.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/AdminPermission.java,v 1.34 2007/02/21 16:49:05 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -18,9 +16,24 @@
 
 package org.osgi.framework;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.security.*;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.security.AccessController;
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
 
 /**
  * A bundle's authority to perform specific privileged administrative operations
@@ -28,182 +41,183 @@
  * permission are:
  * 
  * <pre>
- *   Action               Methods
- *   class                Bundle.loadClass
- *   execute              Bundle.start
- *                        Bundle.stop
- *                        StartLevel.setBundleStartLevel
- *   extensionLifecycle   BundleContext.installBundle for extension bundles
- *                        Bundle.update for extension bundles
- *                        Bundle.uninstall for extension bundles
- *   lifecycle            BundleContext.installBundle
- *                        Bundle.update
- *                        Bundle.uninstall
- *   listener             BundleContext.addBundleListener for SynchronousBundleListener
- *                        BundleContext.removeBundleListener for SynchronousBundleListener
- *   metadata             Bundle.getHeaders
- *                        Bundle.getLocation
- *   resolve              PackageAdmin.refreshPackages
- *                        PackageAdmin.resolveBundles
- *   resource             Bundle.getResource
- *                        Bundle.getResources
- *                        Bundle.getEntry
- *                        Bundle.getEntryPaths
- *                        Bundle.findEntries
- *                        Bundle resource/entry URL creation
- *   startlevel           StartLevel.setStartLevel
- *                        StartLevel.setInitialBundleStartLevel 
- *   context              Bundle.getBundleContext                     
- *                        
+ *  Action               Methods
+ *  class                Bundle.loadClass
+ *  execute              Bundle.start
+ *                       Bundle.stop
+ *                       StartLevel.setBundleStartLevel
+ *  extensionLifecycle   BundleContext.installBundle for extension bundles
+ *                       Bundle.update for extension bundles
+ *                       Bundle.uninstall for extension bundles
+ *  lifecycle            BundleContext.installBundle
+ *                       Bundle.update
+ *                       Bundle.uninstall
+ *  listener             BundleContext.addBundleListener for SynchronousBundleListener
+ *                       BundleContext.removeBundleListener for SynchronousBundleListener
+ *  metadata             Bundle.getHeaders
+ *                       Bundle.getLocation
+ *  resolve              PackageAdmin.refreshPackages
+ *                       PackageAdmin.resolveBundles
+ *  resource             Bundle.getResource
+ *                       Bundle.getResources
+ *                       Bundle.getEntry
+ *                       Bundle.getEntryPaths
+ *                       Bundle.findEntries
+ *                       Bundle resource/entry URL creation
+ *  startlevel           StartLevel.setStartLevel
+ *                       StartLevel.setInitialBundleStartLevel 
+ *  context              Bundle.getBundleContext
  * </pre>
  * 
  * <p>
- * The special action &quot;*&quot; will represent all actions.
+ * The special action &quot;*&quot; will represent all actions. The
+ * <code>resolve</code> action is implied by the <code>class</code>,
+ * <code>execute</code> and <code>resource</code> actions.
  * <p>
  * The name of this permission is a filter expression. The filter gives access
- * to the following parameters:
+ * to the following attributes:
  * <ul>
- * <li>signer - A Distinguished Name chain used to sign a bundle. Wildcards in
- * a DN are not matched according to the filter string rules, but according to
- * the rules defined for a DN chain.</li>
+ * <li>signer - A Distinguished Name chain used to sign a bundle. Wildcards in a
+ * DN are not matched according to the filter string rules, but according to the
+ * rules defined for a DN chain.</li>
  * <li>location - The location of a bundle.</li>
  * <li>id - The bundle ID of the designated bundle.</li>
  * <li>name - The symbolic name of a bundle.</li>
  * </ul>
+ * Filter attribute names are processed in a case sensitive manner.
  * 
  * @ThreadSafe
- * @version $Revision: 1.34 $
+ * @version $Revision: 6867 $
  */
 
 public final class AdminPermission extends BasicPermission {
-	static final long					serialVersionUID	= 307051004521261705L;
+	static final long						serialVersionUID			= 307051004521261705L;
 
 	/**
-	 * The action string <code>class</code> (Value is "class").
+	 * The action string <code>class</code>. The <code>class</code> action
+	 * implies the <code>resolve</code> action.
+	 * 
 	 * @since 1.3
 	 */
-	public final static String			CLASS				= "class";
+	public final static String	CLASS						= "class";
 	/**
-	 * The action string <code>execute</code> (Value is "execute").
+	 * The action string <code>execute</code>. The <code>execute</code> action
+	 * implies the <code>resolve</code> action.
+	 * 
 	 * @since 1.3
 	 */
-	public final static String			EXECUTE				= "execute";
+	public final static String	EXECUTE						= "execute";
 	/**
-	 * The action string <code>extensionLifecycle</code> (Value is
-	 * "extensionLifecycle").
+	 * The action string <code>extensionLifecycle</code>.
+	 * 
 	 * @since 1.3
 	 */
-	public final static String			EXTENSIONLIFECYCLE	= "extensionLifecycle";
+	public final static String	EXTENSIONLIFECYCLE			= "extensionLifecycle";
 	/**
-	 * The action string <code>lifecycle</code> (Value is "lifecycle").
+	 * The action string <code>lifecycle</code>.
+	 * 
 	 * @since 1.3
 	 */
-	public final static String			LIFECYCLE			= "lifecycle";
+	public final static String	LIFECYCLE					= "lifecycle";
 	/**
-	 * The action string <code>listener</code> (Value is "listener").
+	 * The action string <code>listener</code>.
+	 * 
 	 * @since 1.3
 	 */
-	public final static String			LISTENER			= "listener";
+	public final static String	LISTENER					= "listener";
 	/**
-	 * The action string <code>metadata</code> (Value is "metadata").
+	 * The action string <code>metadata</code>.
+	 * 
 	 * @since 1.3
 	 */
-	public final static String			METADATA			= "metadata";
+	public final static String	METADATA					= "metadata";
 	/**
-	 * The action string <code>resolve</code> (Value is "resolve").
+	 * The action string <code>resolve</code>. The <code>resolve</code> action
+	 * is implied by the <code>class</code>, <code>execute</code> and
+	 * <code>resource</code> actions.
+	 * 
 	 * @since 1.3
 	 */
-	public final static String			RESOLVE				= "resolve";
+	public final static String	RESOLVE						= "resolve";
 	/**
-	 * The action string <code>resource</code> (Value is "resource").
+	 * The action string <code>resource</code>. The <code>resource</code> action
+	 * implies the <code>resolve</code> action.
+	 * 
 	 * @since 1.3
 	 */
-	public final static String			RESOURCE			= "resource";
+	public final static String	RESOURCE					= "resource";
 	/**
-	 * The action string <code>startlevel</code> (Value is "startlevel").
+	 * The action string <code>startlevel</code>.
+	 * 
 	 * @since 1.3
 	 */
-	public final static String			STARTLEVEL			= "startlevel";
+	public final static String	STARTLEVEL					= "startlevel";
 
 	/**
-	 * The action string <code>context</code> (Value is "context").
+	 * The action string <code>context</code>.
+	 * 
 	 * @since 1.4
 	 */
-	public final static String			CONTEXT				= "context";
-	
-	/*
-	 * NOTE: A framework implementor may also choose to replace this class in
-	 * their distribution with a class that directly interfaces with the
-	 * framework implementation. This replacement class MUST NOT
-	 * alter the public/protected signature of this class.
-	 */
+	public final static String	CONTEXT						= "context";
 
-	/*
-	 * This class will load the AdminPermission class in the package named by
-	 * the org.osgi.vendor.framework package. For each instance of this class,
-	 * an instance of the vendor AdminPermission class will be created and this
-	 * class will delegate method calls to the vendor AdminPermission instance.
-	 */
+	private final static int	ACTION_CLASS				= 0x00000001;
+	private final static int	ACTION_EXECUTE				= 0x00000002;
+	private final static int	ACTION_LIFECYCLE			= 0x00000004;
+	private final static int	ACTION_LISTENER				= 0x00000008;
+	private final static int	ACTION_METADATA				= 0x00000010;
+	private final static int	ACTION_RESOLVE				= 0x00000040;
+	private final static int	ACTION_RESOURCE				= 0x00000080;
+	private final static int	ACTION_STARTLEVEL			= 0x00000100;
+	private final static int	ACTION_EXTENSIONLIFECYCLE	= 0x00000200;
+	private final static int	ACTION_CONTEXT				= 0x00000400;
+	private final static int	ACTION_ALL					= ACTION_CLASS
+																	| ACTION_EXECUTE
+																	| ACTION_LIFECYCLE
+																	| ACTION_LISTENER
+																	| ACTION_METADATA
+																	| ACTION_RESOLVE
+																	| ACTION_RESOURCE
+																	| ACTION_STARTLEVEL
+																	| ACTION_EXTENSIONLIFECYCLE
+																	| ACTION_CONTEXT;
+	final static int						ACTION_NONE					= 0;
 
-	private static class ImplHolder implements PrivilegedAction {
-		private static final String			packageProperty		= "org.osgi.vendor.framework";
-		static final Constructor	initStringString;
-		static final Constructor	initBundleString;
-		static {
-			Constructor[] constructors = (Constructor[]) AccessController.doPrivileged(new ImplHolder());
-			
-			initStringString = constructors[0];
-			initBundleString = constructors[1];
-		}
-
-		private ImplHolder() {
-		}
-		
-		public Object run() {
-			String packageName = System
-			.getProperty(packageProperty);
-			if (packageName == null) {
-				throw new NoClassDefFoundError(packageProperty
-						+ " property not set");
-			}
-			
-			Class delegateClass;
-			try {
-				delegateClass = Class.forName(packageName
-						+ ".AdminPermission");
-			}
-			catch (ClassNotFoundException e) {
-				throw new NoClassDefFoundError(e.toString());
-			}
-			
-			Constructor[] result = new Constructor[2];
-			try {
-				result[0] = delegateClass
-				.getConstructor(new Class[] {String.class,
-						String.class			});
-				result[1] = delegateClass
-				.getConstructor(new Class[] {Bundle.class,
-						String.class			});
-			}
-			catch (NoSuchMethodException e) {
-				throw new NoSuchMethodError(e.toString());
-			}
-			
-			return result;
-		}
-	}
-	
-	/*
-	 * This is the delegate permission created by the constructor.
+	/**
+	 * The actions in canonical form.
+	 * 
+	 * @serial
 	 */
-	private final Permission			delegate;
+	private volatile String		actions						= null;
+
+	/**
+	 * The actions mask.
+	 */
+	transient int							action_mask;
+
+	/**
+	 * If this AdminPermission was constructed with a filter, this holds a
+	 * Filter matching object used to evaluate the filter in implies.
+	 */
+	transient Filter						filter;
+
+	/**
+	 * The bundle governed by this AdminPermission - only used if filter == null
+	 */
+	transient final Bundle					bundle; 
+
+	/**
+	 * This dictionary holds the properties of the permission, used to match a
+	 * filter in implies. This is not initialized until necessary, and then
+	 * cached in this object.
+	 */
+	private transient volatile Dictionary	properties;
 
 	/**
 	 * Creates a new <code>AdminPermission</code> object that matches all
 	 * bundles and has all actions. Equivalent to AdminPermission("*","*");
 	 */
 	public AdminPermission() {
-		this("*", "*"); //$NON-NLS-1$
+		this(null, ACTION_ALL); 
 	}
 
 	/**
@@ -228,70 +242,41 @@
 	 * 
 	 * @param filter A filter expression that can use signer, location, id, and
 	 *        name keys. A value of &quot;*&quot; or <code>null</code> matches
-	 *        all bundle.
+	 *        all bundle. Filter attribute names are processed in a case
+	 *        sensitive manner.
 	 * @param actions <code>class</code>, <code>execute</code>,
 	 *        <code>extensionLifecycle</code>, <code>lifecycle</code>,
-	 *        <code>listener</code>, <code>metadata</code>,
-	 *        <code>resolve</code>, <code>resource</code>, 
-	 *        <code>startlevel</code> or <code>context</code>. A value of "*" or <code>null</code>
-	 *        indicates all actions
+	 *        <code>listener</code>, <code>metadata</code>, <code>resolve</code>
+	 *        , <code>resource</code>, <code>startlevel</code> or
+	 *        <code>context</code>. A value of "*" or <code>null</code>
+	 *        indicates all actions.
+	 * @throws IllegalArgumentException If the filter has an invalid syntax.
 	 */
 	public AdminPermission(String filter, String actions) {
 		// arguments will be null if called from a PermissionInfo defined with
 		// no args
-		super(filter == null ? "*" : filter);
-		try {
-			try {
-				delegate = (Permission) ImplHolder.initStringString
-						.newInstance(new Object[] {filter, actions});
-			}
-			catch (InvocationTargetException e) {
-				throw e.getTargetException();
-			}
-		}
-		catch (Error e) {
-			throw e;
-		}
-		catch (RuntimeException e) {
-			throw e;
-		}
-		catch (Throwable e) {
-			throw new RuntimeException(e.toString());
-		}
+		this(parseFilter(filter), parseActions(actions));
 	}
 
 	/**
-	 * Creates a new <code>AdminPermission</code> object to be used by the
-	 * code that must check a <code>Permission</code> object.
+	 * Creates a new requested <code>AdminPermission</code> object to be used by
+	 * the code that must perform <code>checkPermission</code>.
+	 * <code>AdminPermission</code> objects created with this constructor cannot
+	 * be added to an <code>AdminPermission</code> permission collection.
 	 * 
-	 * @param bundle A bundle
+	 * @param bundle A bundle.
 	 * @param actions <code>class</code>, <code>execute</code>,
 	 *        <code>extensionLifecycle</code>, <code>lifecycle</code>,
-	 *        <code>listener</code>, <code>metadata</code>,
-	 *        <code>resolve</code>, <code>resource</code>,
-	 *        <code>startlevel</code>, <code>context</code>.
+	 *        <code>listener</code>, <code>metadata</code>, <code>resolve</code>
+	 *        , <code>resource</code>, <code>startlevel</code>,
+	 *        <code>context</code>. A value of "*" or <code>null</code>
+	 *        indicates all actions.
 	 * @since 1.3
 	 */
 	public AdminPermission(Bundle bundle, String actions) {
 		super(createName(bundle));
-		try {
-			try {
-				delegate = (Permission) ImplHolder.initBundleString
-						.newInstance(new Object[] {bundle, actions});
-			}
-			catch (InvocationTargetException e) {
-				throw e.getTargetException();
-			}
-		}
-		catch (Error e) {
-			throw e;
-		}
-		catch (RuntimeException e) {
-			throw e;
-		}
-		catch (Throwable e) {
-			throw new RuntimeException(e.toString());
-		}
+		setTransients(null, parseActions(actions));
+		this.bundle = bundle;
 	}
 
 	/**
@@ -301,59 +286,295 @@
 	 * @return permission name.
 	 */
 	private static String createName(Bundle bundle) {
-		StringBuffer sb = new StringBuffer();
-		sb.append("(id=");
+		if (bundle == null) {
+			throw new IllegalArgumentException("bundle must not be null");
+		}
+		StringBuffer sb = new StringBuffer("(id=");
 		sb.append(bundle.getBundleId());
 		sb.append(")");
 		return sb.toString();
 	}
 
 	/**
-	 * Determines the equality of two <code>AdminPermission</code> objects.
+	 * Package private constructor used by AdminPermissionCollection.
 	 * 
-	 * @param obj The object being compared for equality with this object.
-	 * @return <code>true</code> if <code>obj</code> is equivalent to this
-	 *         <code>AdminPermission</code>; <code>false</code> otherwise.
+	 * @param filter name filter or <code>null</code> for wildcard.
+	 * @param mask action mask
 	 */
-	public boolean equals(Object obj) {
-		if (obj == this) {
-			return true;
-		}
-
-		if (!(obj instanceof AdminPermission)) {
-			return false;
-		}
-
-		AdminPermission p = (AdminPermission) obj;
-
-		return delegate.equals(p.delegate);
+	AdminPermission(Filter filter, int mask) {
+		super((filter == null) ? "*" : filter.toString());
+		setTransients(filter, mask);
+		this.bundle = null;
 	}
 
 	/**
-	 * Returns the hash code value for this object.
+	 * Called by constructors and when deserialized.
 	 * 
-	 * @return Hash code value for this object.
+	 * @param filter Permission's filter or <code>null</code> for wildcard.
+	 * @param mask action mask
 	 */
-	public int hashCode() {
-		return delegate.hashCode();
+	private void setTransients(Filter filter, int mask) {
+		this.filter = filter;
+		if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
+			throw new IllegalArgumentException("invalid action string");
+		}
+		this.action_mask = mask;
 	}
 
 	/**
-	 * Returns the canonical string representation of the
-	 * <code>AdminPermission</code> actions.
+	 * Parse action string into action mask.
 	 * 
-	 * <p>
-	 * Always returns present <code>AdminPermission</code> actions in the
-	 * following order: <code>class</code>, <code>execute</code>,
-	 * <code>extensionLifecycle</code>, <code>lifecycle</code>,
-	 * <code>listener</code>, <code>metadata</code>, <code>resolve</code>,
-	 * <code>resource</code>, <code>startlevel</code>, <code>context</code>.
-	 * 
-	 * @return Canonical string representation of the
-	 *         <code>AdminPermission</code> actions.
+	 * @param actions Action string.
+	 * @return action mask.
 	 */
-	public String getActions() {
-		return delegate.getActions();
+	private static int parseActions(String actions) {
+		if ((actions == null) || actions.equals("*")) {
+			return ACTION_ALL;
+		}
+	
+		boolean seencomma = false;
+	
+		int mask = ACTION_NONE;
+	
+		if (actions == null) {
+			return mask;
+		}
+	
+		char[] a = actions.toCharArray();
+	
+		int i = a.length - 1;
+		if (i < 0)
+			return mask;
+	
+		while (i != -1) {
+			char c;
+	
+			// skip whitespace
+			while ((i != -1)
+					&& ((c = a[i]) == ' ' || c == '\r' || c == '\n'
+							|| c == '\f' || c == '\t'))
+				i--;
+	
+			// check for the known strings
+			int matchlen;
+	
+			if (i >= 4 && (a[i - 4] == 'c' || a[i - 4] == 'C')
+					&& (a[i - 3] == 'l' || a[i - 3] == 'L')
+					&& (a[i - 2] == 'a' || a[i - 2] == 'A')
+					&& (a[i - 1] == 's' || a[i - 1] == 'S')
+					&& (a[i] == 's' || a[i] == 'S')) {
+				matchlen = 5;
+				mask |= ACTION_CLASS | ACTION_RESOLVE;
+	
+			}
+			else
+				if (i >= 6 && (a[i - 6] == 'e' || a[i - 6] == 'E')
+						&& (a[i - 5] == 'x' || a[i - 5] == 'X')
+						&& (a[i - 4] == 'e' || a[i - 4] == 'E')
+						&& (a[i - 3] == 'c' || a[i - 3] == 'C')
+						&& (a[i - 2] == 'u' || a[i - 2] == 'U')
+						&& (a[i - 1] == 't' || a[i - 1] == 'T')
+						&& (a[i] == 'e' || a[i] == 'E')) {
+					matchlen = 7;
+					mask |= ACTION_EXECUTE | ACTION_RESOLVE;
+	
+				}
+				else
+					if (i >= 17 && (a[i - 17] == 'e' || a[i - 17] == 'E')
+							&& (a[i - 16] == 'x' || a[i - 16] == 'X')
+							&& (a[i - 15] == 't' || a[i - 15] == 'T')
+							&& (a[i - 14] == 'e' || a[i - 14] == 'E')
+							&& (a[i - 13] == 'n' || a[i - 13] == 'N')
+							&& (a[i - 12] == 's' || a[i - 12] == 'S')
+							&& (a[i - 11] == 'i' || a[i - 11] == 'I')
+							&& (a[i - 10] == 'o' || a[i - 10] == 'O')
+							&& (a[i - 9] == 'n' || a[i - 9] == 'N')
+							&& (a[i - 8] == 'l' || a[i - 8] == 'L')
+							&& (a[i - 7] == 'i' || a[i - 7] == 'I')
+							&& (a[i - 6] == 'f' || a[i - 6] == 'F')
+							&& (a[i - 5] == 'e' || a[i - 5] == 'E')
+							&& (a[i - 4] == 'c' || a[i - 4] == 'C')
+							&& (a[i - 3] == 'y' || a[i - 3] == 'Y')
+							&& (a[i - 2] == 'c' || a[i - 2] == 'C')
+							&& (a[i - 1] == 'l' || a[i - 1] == 'L')
+							&& (a[i] == 'e' || a[i] == 'E')) {
+						matchlen = 18;
+						mask |= ACTION_EXTENSIONLIFECYCLE;
+	
+					}
+					else
+						if (i >= 8 && (a[i - 8] == 'l' || a[i - 8] == 'L')
+								&& (a[i - 7] == 'i' || a[i - 7] == 'I')
+								&& (a[i - 6] == 'f' || a[i - 6] == 'F')
+								&& (a[i - 5] == 'e' || a[i - 5] == 'E')
+								&& (a[i - 4] == 'c' || a[i - 4] == 'C')
+								&& (a[i - 3] == 'y' || a[i - 3] == 'Y')
+								&& (a[i - 2] == 'c' || a[i - 2] == 'C')
+								&& (a[i - 1] == 'l' || a[i - 1] == 'L')
+								&& (a[i] == 'e' || a[i] == 'E')) {
+							matchlen = 9;
+							mask |= ACTION_LIFECYCLE;
+	
+						}
+						else
+							if (i >= 7 && (a[i - 7] == 'l' || a[i - 7] == 'L')
+									&& (a[i - 6] == 'i' || a[i - 6] == 'I')
+									&& (a[i - 5] == 's' || a[i - 5] == 'S')
+									&& (a[i - 4] == 't' || a[i - 4] == 'T')
+									&& (a[i - 3] == 'e' || a[i - 3] == 'E')
+									&& (a[i - 2] == 'n' || a[i - 2] == 'N')
+									&& (a[i - 1] == 'e' || a[i - 1] == 'E')
+									&& (a[i] == 'r' || a[i] == 'R')) {
+								matchlen = 8;
+								mask |= ACTION_LISTENER;
+	
+							}
+							else
+								if (i >= 7
+										&& (a[i - 7] == 'm' || a[i - 7] == 'M')
+										&& (a[i - 6] == 'e' || a[i - 6] == 'E')
+										&& (a[i - 5] == 't' || a[i - 5] == 'T')
+										&& (a[i - 4] == 'a' || a[i - 4] == 'A')
+										&& (a[i - 3] == 'd' || a[i - 3] == 'D')
+										&& (a[i - 2] == 'a' || a[i - 2] == 'A')
+										&& (a[i - 1] == 't' || a[i - 1] == 'T')
+										&& (a[i] == 'a' || a[i] == 'A')) {
+									matchlen = 8;
+									mask |= ACTION_METADATA;
+	
+								}
+								else
+									if (i >= 6
+											&& (a[i - 6] == 'r' || a[i - 6] == 'R')
+											&& (a[i - 5] == 'e' || a[i - 5] == 'E')
+											&& (a[i - 4] == 's' || a[i - 4] == 'S')
+											&& (a[i - 3] == 'o' || a[i - 3] == 'O')
+											&& (a[i - 2] == 'l' || a[i - 2] == 'L')
+											&& (a[i - 1] == 'v' || a[i - 1] == 'V')
+											&& (a[i] == 'e' || a[i] == 'E')) {
+										matchlen = 7;
+										mask |= ACTION_RESOLVE;
+	
+									}
+									else
+										if (i >= 7
+												&& (a[i - 7] == 'r' || a[i - 7] == 'R')
+												&& (a[i - 6] == 'e' || a[i - 6] == 'E')
+												&& (a[i - 5] == 's' || a[i - 5] == 'S')
+												&& (a[i - 4] == 'o' || a[i - 4] == 'O')
+												&& (a[i - 3] == 'u' || a[i - 3] == 'U')
+												&& (a[i - 2] == 'r' || a[i - 2] == 'R')
+												&& (a[i - 1] == 'c' || a[i - 1] == 'C')
+												&& (a[i] == 'e' || a[i] == 'E')) {
+											matchlen = 8;
+											mask |= ACTION_RESOURCE
+													| ACTION_RESOLVE;
+	
+										}
+										else
+											if (i >= 9
+													&& (a[i - 9] == 's' || a[i - 9] == 'S')
+													&& (a[i - 8] == 't' || a[i - 8] == 'T')
+													&& (a[i - 7] == 'a' || a[i - 7] == 'A')
+													&& (a[i - 6] == 'r' || a[i - 6] == 'R')
+													&& (a[i - 5] == 't' || a[i - 5] == 'T')
+													&& (a[i - 4] == 'l' || a[i - 4] == 'L')
+													&& (a[i - 3] == 'e' || a[i - 3] == 'E')
+													&& (a[i - 2] == 'v' || a[i - 2] == 'V')
+													&& (a[i - 1] == 'e' || a[i - 1] == 'E')
+													&& (a[i] == 'l' || a[i] == 'L')) {
+												matchlen = 10;
+												mask |= ACTION_STARTLEVEL;
+	
+											}
+											else
+												if (i >= 6
+														&& (a[i - 6] == 'c' || a[i - 6] == 'C')
+														&& (a[i - 5] == 'o' || a[i - 5] == 'O')
+														&& (a[i - 4] == 'n' || a[i - 4] == 'N')
+														&& (a[i - 3] == 't' || a[i - 3] == 'T')
+														&& (a[i - 2] == 'e' || a[i - 2] == 'E')
+														&& (a[i - 1] == 'x' || a[i - 1] == 'X')
+														&& (a[i] == 't' || a[i] == 'T')) {
+													matchlen = 7;
+													mask |= ACTION_CONTEXT;
+	
+												}
+												else
+													if (i >= 0 &&
+	
+													(a[i] == '*')) {
+														matchlen = 1;
+														mask |= ACTION_ALL;
+	
+													}
+													else {
+														// parse error
+														throw new IllegalArgumentException(
+																"invalid permission: "
+																		+ actions); 
+													}
+	
+			// make sure we didn't just match the tail of a word
+			// like "ackbarfstartlevel". Also, skip to the comma.
+			seencomma = false;
+			while (i >= matchlen && !seencomma) {
+				switch (a[i - matchlen]) {
+					case ',' :
+						seencomma = true;
+						/* FALLTHROUGH */
+					case ' ' :
+					case '\r' :
+					case '\n' :
+					case '\f' :
+					case '\t' :
+						break;
+					default :
+						throw new IllegalArgumentException(
+								"invalid permission: " + actions); 
+				}
+				i--;
+			}
+	
+			// point i at the location of the comma minus one (or -1).
+			i -= matchlen;
+		}
+	
+		if (seencomma) {
+			throw new IllegalArgumentException("invalid permission: " + 
+					actions);
+		}
+	
+		return mask;
+	}
+
+	/**
+	 * Parse filter string into a Filter object.
+	 * 
+	 * @param filterString The filter string to parse.
+	 * @return a Filter for this bundle. If the specified filterString is
+	 *         <code>null</code> or equals "*", then <code>null</code> is
+	 *         returned to indicate a wildcard.
+	 * @throws IllegalArgumentException If the filter syntax is invalid.
+	 */
+	private static Filter parseFilter(String filterString) {
+		if (filterString == null) {
+			return null;
+		}
+		filterString = filterString.trim();
+		if (filterString.equals("*")) {
+			return null;
+		}
+		
+		try {
+			return FrameworkUtil.createFilter(filterString);
+		}
+		catch (InvalidSyntaxException e) {
+			IllegalArgumentException iae = new IllegalArgumentException(
+					"invalid filter");
+			iae.initCause(e);
+			throw iae;
+		}
 	}
 
 	/**
@@ -378,20 +599,135 @@
 	 * filter is "*" and this object's actions include all of the specified
 	 * permission's actions
 	 * 
-	 * @param p The permission to interrogate.
-	 * 
-	 * @return <code>true</code> if the specified permission is implied by
-	 *         this object; <code>false</code> otherwise.
-	 * @throws RuntimeException if specified permission was not constructed with
-	 *         a bundle or "*"
+	 * @param p The requested permission.
+	 * @return <code>true</code> if the specified permission is implied by this
+	 *         object; <code>false</code> otherwise.
 	 */
 	public boolean implies(Permission p) {
 		if (!(p instanceof AdminPermission)) {
 			return false;
 		}
+		AdminPermission requested = (AdminPermission) p;
+		if (bundle != null) {
+			return false;
+		}
+		// if requested permission has a filter, then it is an invalid argument
+		if (requested.filter != null) {
+			return false;
+		}
+		return implies0(requested, ACTION_NONE);
+	}
 
-		AdminPermission pp = (AdminPermission) p;
-		return delegate.implies(pp.delegate);
+	/**
+	 * Internal implies method. Used by the implies and the permission
+	 * collection implies methods.
+	 * 
+	 * @param requested The requested AdminPermision which has already be
+	 *        validated as a proper argument. The requested AdminPermission must
+	 *        not have a filter expression.
+	 * @param effective The effective actions with which to start.
+	 * @return <code>true</code> if the specified permission is implied by this
+	 *         object; <code>false</code> otherwise.
+	 */
+	boolean implies0(AdminPermission requested, int effective) {
+		/* check actions first - much faster */
+		effective |= action_mask;
+		final int desired = requested.action_mask;
+		if ((effective & desired) != desired) {
+			return false;
+		}
+	
+		/* Get our filter */
+		Filter f = filter;
+		if (f == null) {
+			// it's "*"
+			return true;
+		}
+		/* is requested a wildcard filter? */
+		if (requested.bundle == null) {
+			return false;
+		}
+		return f.matchCase(requested.getProperties());
+	}
+
+	/**
+	 * Returns the canonical string representation of the
+	 * <code>AdminPermission</code> actions.
+	 * 
+	 * <p>
+	 * Always returns present <code>AdminPermission</code> actions in the
+	 * following order: <code>class</code>, <code>execute</code>,
+	 * <code>extensionLifecycle</code>, <code>lifecycle</code>,
+	 * <code>listener</code>, <code>metadata</code>, <code>resolve</code>,
+	 * <code>resource</code>, <code>startlevel</code>, <code>context</code>.
+	 * 
+	 * @return Canonical string representation of the
+	 *         <code>AdminPermission</code> actions.
+	 */
+	public String getActions() {
+		String result = actions;
+		if (result == null) {
+			StringBuffer sb = new StringBuffer();
+	
+			int mask = action_mask;
+			if ((mask & ACTION_CLASS) == ACTION_CLASS) {
+				sb.append(CLASS);
+				sb.append(',');
+			}
+	
+			if ((mask & ACTION_EXECUTE) == ACTION_EXECUTE) {
+				sb.append(EXECUTE);
+				sb.append(',');
+			}
+	
+			if ((mask & ACTION_EXTENSIONLIFECYCLE) == ACTION_EXTENSIONLIFECYCLE) {
+				sb.append(EXTENSIONLIFECYCLE);
+				sb.append(',');
+			}
+	
+			if ((mask & ACTION_LIFECYCLE) == ACTION_LIFECYCLE) {
+				sb.append(LIFECYCLE);
+				sb.append(',');
+			}
+	
+			if ((mask & ACTION_LISTENER) == ACTION_LISTENER) {
+				sb.append(LISTENER);
+				sb.append(',');
+			}
+	
+			if ((mask & ACTION_METADATA) == ACTION_METADATA) {
+				sb.append(METADATA);
+				sb.append(',');
+			}
+	
+			if ((mask & ACTION_RESOLVE) == ACTION_RESOLVE) {
+				sb.append(RESOLVE);
+				sb.append(',');
+			}
+	
+			if ((mask & ACTION_RESOURCE) == ACTION_RESOURCE) {
+				sb.append(RESOURCE);
+				sb.append(',');
+			}
+	
+			if ((mask & ACTION_STARTLEVEL) == ACTION_STARTLEVEL) {
+				sb.append(STARTLEVEL);
+				sb.append(',');
+			}
+	
+			if ((mask & ACTION_CONTEXT) == ACTION_CONTEXT) {
+				sb.append(CONTEXT);
+				sb.append(',');
+			}
+	
+			// remove trailing comma
+			if (sb.length() > 0) {
+				sb.setLength(sb.length() - 1);
+			}
+	
+			actions = result = sb.toString();
+		}
+		return result;
 	}
 
 	/**
@@ -401,6 +737,265 @@
 	 * @return A new <code>PermissionCollection</code> object.
 	 */
 	public PermissionCollection newPermissionCollection() {
-		return delegate.newPermissionCollection();
+		return new AdminPermissionCollection();
+	}
+
+	/**
+	 * Determines the equality of two <code>AdminPermission</code> objects.
+	 * 
+	 * @param obj The object being compared for equality with this object.
+	 * @return <code>true</code> if <code>obj</code> is equivalent to this
+	 *         <code>AdminPermission</code>; <code>false</code> otherwise.
+	 */
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+
+		if (!(obj instanceof AdminPermission)) {
+			return false;
+		}
+
+		AdminPermission ap = (AdminPermission) obj;
+
+		return (action_mask == ap.action_mask)
+				&& ((bundle == ap.bundle) || ((bundle != null) && bundle
+						.equals(ap.bundle)))
+				&& (filter == null ? ap.filter == null : filter
+						.equals(ap.filter));
+	}
+
+	/**
+	 * Returns the hash code value for this object.
+	 * 
+	 * @return Hash code value for this object.
+	 */
+	public int hashCode() {
+		int h = 31 * 17 + getName().hashCode();
+		h = 31 * h + getActions().hashCode();
+		if (bundle != null) {
+			h = 31 * h + bundle.hashCode();
+		}
+		return h;
+	}
+
+	/**
+	 * WriteObject is called to save the state of this permission object to a
+	 * stream. The actions are serialized, and the superclass takes care of the
+	 * name.
+	 */
+	private synchronized void writeObject(java.io.ObjectOutputStream s)
+			throws IOException {
+		if (bundle != null) {
+			throw new NotSerializableException("cannot serialize");
+		}
+		// Write out the actions. The superclass takes care of the name
+		// call getActions to make sure actions field is initialized
+		if (actions == null)
+			getActions();
+		s.defaultWriteObject();
+	}
+
+	/**
+	 * readObject is called to restore the state of this permission from a
+	 * stream.
+	 */
+	private synchronized void readObject(java.io.ObjectInputStream s)
+			throws IOException, ClassNotFoundException {
+		// Read in the data, then initialize the transients
+		s.defaultReadObject();
+		setTransients(parseFilter(getName()), parseActions(actions));
+	}
+
+	/**
+	 * Called by <code><@link AdminPermission#implies(Permission)></code> on an
+	 * AdminPermission which was constructed with a Bundle. This method loads a
+	 * dictionary with the filter-matchable properties of this bundle. The
+	 * dictionary is cached so this lookup only happens once.
+	 * 
+	 * This method should only be called on an AdminPermission which was
+	 * constructed with a bundle
+	 * 
+	 * @return a dictionary of properties for this bundle
+	 */
+	private Dictionary getProperties() {
+		Dictionary result = properties;
+		if (result != null) {
+			return result;
+		}
+		final Dictionary dict = new Hashtable(4);
+		AccessController.doPrivileged(new PrivilegedAction() {
+			public Object run() {
+				dict.put("id", new Long(bundle.getBundleId()));
+				dict.put("location", bundle.getLocation());
+				String name = bundle.getSymbolicName();
+				if (name != null) {
+					dict.put("name", name);
+				}
+				SignerProperty signer = new SignerProperty(bundle);
+				if (signer.isBundleSigned()) {
+					dict.put("signer", signer); 
+				}
+				return null;
+			}
+		});
+		return properties = dict;
+	}
+}
+
+/**
+ * Stores a collection of <code>AdminPermission</code>s.
+ */
+final class AdminPermissionCollection extends PermissionCollection {
+	private static final long	serialVersionUID	= 3906372644575328048L;
+	/**
+	 * Collection of permissions.
+	 * 
+	 * @GuardedBy this
+	 */
+	private transient Map		permissions;
+
+	/**
+	 * Boolean saying if "*" is in the collection.
+	 * 
+	 * @serial
+	 * @GuardedBy this
+	 */
+	private boolean				all_allowed;
+
+	/**
+	 * Create an empty AdminPermissions object.
+	 * 
+	 */
+	public AdminPermissionCollection() {
+		permissions = new HashMap();
+	}
+
+	/**
+	 * Adds a permission to this permission collection.
+	 * 
+	 * @param permission The <code>AdminPermission</code> object to add.
+	 * @throws IllegalArgumentException If the specified permission is not an
+	 *         <code>AdminPermission</code> instance or was constructed with a
+	 *         Bundle object.
+	 * @throws SecurityException If this <code>AdminPermissionCollection</code>
+	 *         object has been marked read-only.
+	 */
+	public void add(Permission permission) {
+		if (!(permission instanceof AdminPermission)) {
+			throw new IllegalArgumentException("invalid permission: "
+					+ permission);
+		}
+		if (isReadOnly()) {
+			throw new SecurityException("attempt to add a Permission to a "
+					+ "readonly PermissionCollection"); 
+		}
+		final AdminPermission ap = (AdminPermission) permission;
+		if (ap.bundle != null) {
+			throw new IllegalArgumentException("cannot add to collection: "
+					+ ap);
+		}
+		final String name = ap.getName();
+		synchronized (this) {
+			Map pc = permissions;
+			AdminPermission existing = (AdminPermission) pc.get(name);
+			if (existing != null) {
+				int oldMask = existing.action_mask;
+				int newMask = ap.action_mask;
+
+				if (oldMask != newMask) {
+					pc.put(name, new AdminPermission(existing.filter, oldMask
+							| newMask));
+				}
+			}
+			else {
+				pc.put(name, ap);
+			}
+			if (!all_allowed) {
+				if (name.equals("*")) {
+					all_allowed = true;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Determines if the specified permissions implies the permissions expressed
+	 * in <code>permission</code>.
+	 * 
+	 * @param permission The Permission object to compare with the
+	 *        <code>AdminPermission</code> objects in this collection.
+	 * @return <code>true</code> if <code>permission</code> is implied by an
+	 *         <code>AdminPermission</code> in this collection,
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean implies(Permission permission) {
+		if (!(permission instanceof AdminPermission)) {
+			return false;
+		}
+
+		AdminPermission requested = (AdminPermission) permission;
+		// if requested permission has a filter, then it is an invalid argument
+		if (requested.filter != null) {
+			return false;
+		}
+		int effective = AdminPermission.ACTION_NONE;
+		Collection perms;
+		synchronized (this) {
+			Map pc = permissions;
+			// short circuit if the "*" Permission was added
+			if (all_allowed) {
+				AdminPermission ap = (AdminPermission) pc.get("*");
+				if (ap != null) {
+					effective |= ap.action_mask;
+					final int desired = requested.action_mask;
+					if ((effective & desired) == desired) {
+						return true;
+					}
+				}
+			}
+			perms = pc.values();
+		}
+
+		// just iterate one by one
+		for (Iterator iter = perms.iterator(); iter.hasNext();) {
+			if (((AdminPermission) iter.next()).implies0(requested, effective)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Returns an enumeration of all <code>AdminPermission</code> objects in the
+	 * container.
+	 * 
+	 * @return Enumeration of all <code>AdminPermission</code> objects.
+	 */
+	public synchronized Enumeration elements() {
+		return Collections.enumeration(permissions.values());
+	}
+	
+	/* serialization logic */
+    private static final ObjectStreamField[]	serialPersistentFields	= {
+			new ObjectStreamField("permissions", Hashtable.class),
+			new ObjectStreamField("all_allowed", Boolean.TYPE)			};
+    
+    private synchronized void writeObject(ObjectOutputStream out)
+			throws IOException {
+		Hashtable hashtable = new Hashtable(permissions);
+		ObjectOutputStream.PutField pfields = out.putFields();
+		pfields.put("permissions", hashtable);
+		pfields.put("all_allowed", all_allowed);
+		out.writeFields();
+	}
+    
+    private synchronized void readObject(java.io.ObjectInputStream in)
+			throws IOException,
+			ClassNotFoundException {
+		ObjectInputStream.GetField gfields = in.readFields();
+		Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+		permissions = new HashMap(hashtable);
+		all_allowed = gfields.get("all_allowed", false);
 	}
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/AllServiceListener.java b/org.osgi.core/src/main/java/org/osgi/framework/AllServiceListener.java
index e126c5c..688f51e 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/AllServiceListener.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/AllServiceListener.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/AllServiceListener.java,v 1.10 2007/02/20 00:16:30 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2005, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2008). 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.
@@ -57,7 +55,7 @@
  * @see ServicePermission
  * @ThreadSafe
  * @since 1.3
- * @version $Revision: 1.10 $
+ * @version $Revision: 5673 $
  */
 
 public interface AllServiceListener extends ServiceListener {
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/Bundle.java b/org.osgi.core/src/main/java/org/osgi/framework/Bundle.java
index b814f82..692bc5e 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/Bundle.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/Bundle.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/Bundle.java,v 1.54 2007/02/21 16:49:05 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -23,6 +21,7 @@
 import java.net.URL;
 import java.util.Dictionary;
 import java.util.Enumeration;
+import java.util.Map;
 
 /**
  * An installed bundle in the Framework.
@@ -65,7 +64,7 @@
  * Framework that created them.
  * 
  * @ThreadSafe
- * @version $Revision: 1.54 $
+ * @version $Revision: 6906 $
  */
 public interface Bundle {
 	/**
@@ -216,6 +215,23 @@
 	public static final int	STOP_TRANSIENT			= 0x00000001;
 
 	/**
+	 * Request that all certificates used to sign the bundle be returned.
+	 * 
+	 * @since 1.5
+	 * @see #getSignerCertificates(int)
+	 */
+	public final static int	SIGNERS_ALL				= 1;
+
+	/**
+	 * Request that only certificates used to sign the bundle that are trusted
+	 * by the framework be returned.
+	 * 
+	 * @since 1.5
+	 * @see #getSignerCertificates(int)
+	 */
+	public final static int	SIGNERS_TRUSTED			= 2;
+
+	/**
 	 * Returns this bundle's current state.
 	 * 
 	 * <p>
@@ -255,8 +271,8 @@
 	 * <li>If this bundle is in the process of being activated or deactivated
 	 * then this method must wait for activation or deactivation to complete
 	 * before continuing. If this does not occur in a reasonable time, a
-	 * <code>BundleException</code> is thrown to indicate this bundle was
-	 * unable to be started.
+	 * <code>BundleException</code> is thrown to indicate this bundle was unable
+	 * to be started.
 	 * 
 	 * <li>If this bundle's state is <code>ACTIVE</code> then this method
 	 * returns immediately.
@@ -264,17 +280,17 @@
 	 * <li>If the {@link #START_TRANSIENT} option is not set then set this
 	 * bundle's autostart setting to <em>Started with declared activation</em>
 	 * if the {@link #START_ACTIVATION_POLICY} option is set or
-	 * <em>Started with eager activation</em> if not set. When the Framework
-	 * is restarted and this bundle's autostart setting is not <em>Stopped</em>,
+	 * <em>Started with eager activation</em> if not set. When the Framework is
+	 * restarted and this bundle's autostart setting is not <em>Stopped</em>,
 	 * this bundle must be automatically started.
 	 * 
-	 * <li>If this bundle's state is not <code>RESOLVED</code>, an attempt
-	 * is made to resolve this bundle. If the Framework cannot resolve this
-	 * bundle, a <code>BundleException</code> is thrown.
+	 * <li>If this bundle's state is not <code>RESOLVED</code>, an attempt is
+	 * made to resolve this bundle. If the Framework cannot resolve this bundle,
+	 * a <code>BundleException</code> is thrown.
 	 * 
 	 * <li>If the {@link #START_ACTIVATION_POLICY} option is set and this
-	 * bundle's declared activation policy is
-	 * {@link Constants#ACTIVATION_LAZY lazy} then:
+	 * bundle's declared activation policy is {@link Constants#ACTIVATION_LAZY
+	 * lazy} then:
 	 * <ul>
 	 * <li>If this bundle's state is <code>STARTING</code> then this method
 	 * returns immediately.
@@ -313,40 +329,40 @@
 	 * 
 	 * <b>Preconditions </b>
 	 * <ul>
-	 * <li><code>getState()</code> in {<code>INSTALLED</code>,
-	 * <code>RESOLVED</code>} or {<code>INSTALLED</code>,
-	 * <code>RESOLVED</code>, <code>STARTING</code>} if this bundle has a
-	 * lazy activation policy.
+	 * <li><code>getState()</code> in &#x007B; <code>INSTALLED</code>,
+	 * <code>RESOLVED</code> &#x007D; or &#x007B; <code>INSTALLED</code>,
+	 * <code>RESOLVED</code>, <code>STARTING</code> &#x007D; if this bundle has
+	 * a lazy activation policy.
 	 * </ul>
 	 * <b>Postconditions, no exceptions thrown </b>
 	 * <ul>
 	 * <li>Bundle autostart setting is modified unless the
 	 * {@link #START_TRANSIENT} option was set.
-	 * <li><code>getState()</code> in {<code>ACTIVE</code>} unless the
-	 * lazy activation policy was used.
+	 * <li><code>getState()</code> in &#x007B; <code>ACTIVE</code> &#x007D;
+	 * unless the lazy activation policy was used.
 	 * <li><code>BundleActivator.start()</code> has been called and did not
 	 * throw an exception unless the lazy activation policy was used.
 	 * </ul>
 	 * <b>Postconditions, when an exception is thrown </b>
 	 * <ul>
-	 * <li>Depending on when the exception occurred, bundle autostart setting
-	 * is modified unless the {@link #START_TRANSIENT} option was set.
-	 * <li><code>getState()</code> not in {<code>STARTING</code>,
-	 * <code>ACTIVE</code>}.
+	 * <li>Depending on when the exception occurred, bundle autostart setting is
+	 * modified unless the {@link #START_TRANSIENT} option was set.
+	 * <li><code>getState()</code> not in &#x007B; <code>STARTING</code>,
+	 * <code>ACTIVE</code> &#x007D;.
 	 * </ul>
 	 * 
 	 * @param options The options for starting this bundle. See
-	 *        {@link #START_TRANSIENT} and {@link #START_ACTIVATION_POLICY}.
-	 *        The Framework must ignore unrecognized options.
+	 *        {@link #START_TRANSIENT} and {@link #START_ACTIVATION_POLICY}. The
+	 *        Framework must ignore unrecognized options.
 	 * @throws BundleException If this bundle could not be started. This could
 	 *         be because a code dependency could not be resolved or the
 	 *         specified <code>BundleActivator</code> could not be loaded or
 	 *         threw an exception or this bundle is a fragment.
-	 * @throws java.lang.IllegalStateException If this bundle has been
-	 *         uninstalled or this bundle tries to change its own state.
-	 * @throws java.lang.SecurityException If the caller does not have the
-	 *         appropriate <code>AdminPermission[this,EXECUTE]</code>, and
-	 *         the Java Runtime Environment supports permissions.
+	 * @throws IllegalStateException If this bundle has been uninstalled or this
+	 *         bundle tries to change its own state.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
 	 * @since 1.4
 	 */
 	public void start(int options) throws BundleException;
@@ -355,17 +371,17 @@
 	 * Starts this bundle with no options.
 	 * 
 	 * <p>
-	 * This method calls <code>start(0)</code>.
+	 * This method performs the same function as calling <code>start(0)</code>.
 	 * 
 	 * @throws BundleException If this bundle could not be started. This could
 	 *         be because a code dependency could not be resolved or the
 	 *         specified <code>BundleActivator</code> could not be loaded or
 	 *         threw an exception or this bundle is a fragment.
-	 * @throws java.lang.IllegalStateException If this bundle has been
-	 *         uninstalled or this bundle tries to change its own state.
-	 * @throws java.lang.SecurityException If the caller does not have the
-	 *         appropriate <code>AdminPermission[this,EXECUTE]</code>, and
-	 *         the Java Runtime Environment supports permissions.
+	 * @throws IllegalStateException If this bundle has been uninstalled or this
+	 *         bundle tries to change its own state.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
 	 * @see #start(int)
 	 */
 	public void start() throws BundleException;
@@ -382,33 +398,34 @@
 	 * <li>If this bundle is in the process of being activated or deactivated
 	 * then this method must wait for activation or deactivation to complete
 	 * before continuing. If this does not occur in a reasonable time, a
-	 * <code>BundleException</code> is thrown to indicate this bundle was
-	 * unable to be stopped.
+	 * <code>BundleException</code> is thrown to indicate this bundle was unable
+	 * to be stopped.
 	 * <li>If the {@link #STOP_TRANSIENT} option is not set then then set this
 	 * bundle's persistent autostart setting to to <em>Stopped</em>. When the
 	 * Framework is restarted and this bundle's autostart setting is
 	 * <em>Stopped</em>, this bundle must not be automatically started.
 	 * 
-	 * <li>If this bundle's state is not <code>ACTIVE</code> then this method
-	 * returns immediately.
+	 * <li>If this bundle's state is not <code>STARTING</code> or
+	 * <code>ACTIVE</code> then this method returns immediately.
 	 * 
 	 * <li>This bundle's state is set to <code>STOPPING</code>.
 	 * 
 	 * <li>A bundle event of type {@link BundleEvent#STOPPING} is fired.
 	 * 
-	 * <li>The {@link BundleActivator#stop} method of this bundle's
-	 * <code>BundleActivator</code>, if one is specified, is called. If that
-	 * method throws an exception, this method must continue to stop this
-	 * bundle. A <code>BundleException</code> must be thrown after completion
-	 * of the remaining steps.
+	 * <li>If this bundle's state was <code>ACTIVE</code> prior to setting the
+	 * state to <code>STOPPING</code>, the {@link BundleActivator#stop} method
+	 * of this bundle's <code>BundleActivator</code>, if one is specified, is
+	 * called. If that method throws an exception, this method must continue to
+	 * stop this bundle and a <code>BundleException</code> must be thrown after
+	 * completion of the remaining steps.
 	 * 
 	 * <li>Any services registered by this bundle must be unregistered.
 	 * <li>Any services used by this bundle must be released.
 	 * <li>Any listeners registered by this bundle must be removed.
 	 * 
 	 * <li>If this bundle's state is <code>UNINSTALLED</code>, because this
-	 * bundle was uninstalled while the <code>BundleActivator.stop</code>
-	 * method was running, a <code>BundleException</code> must be thrown.
+	 * bundle was uninstalled while the <code>BundleActivator.stop</code> method
+	 * was running, a <code>BundleException</code> must be thrown.
 	 * 
 	 * <li>This bundle's state is set to <code>RESOLVED</code>.
 	 * 
@@ -417,16 +434,16 @@
 	 * 
 	 * <b>Preconditions </b>
 	 * <ul>
-	 * <li><code>getState()</code> in {<code>ACTIVE</code>}.
+	 * <li><code>getState()</code> in &#x007B; <code>ACTIVE</code> &#x007D;.
 	 * </ul>
 	 * <b>Postconditions, no exceptions thrown </b>
 	 * <ul>
 	 * <li>Bundle autostart setting is modified unless the
 	 * {@link #STOP_TRANSIENT} option was set.
-	 * <li><code>getState()</code> not in {<code>ACTIVE</code>,
-	 * <code>STOPPING</code>}.
-	 * <li><code>BundleActivator.stop</code> has been called and did not
-	 * throw an exception.
+	 * <li><code>getState()</code> not in &#x007B; <code>ACTIVE</code>,
+	 * <code>STOPPING</code> &#x007D;.
+	 * <li><code>BundleActivator.stop</code> has been called and did not throw
+	 * an exception.
 	 * </ul>
 	 * <b>Postconditions, when an exception is thrown </b>
 	 * <ul>
@@ -439,11 +456,11 @@
 	 *        options.
 	 * @throws BundleException If this bundle's <code>BundleActivator</code>
 	 *         threw an exception or this bundle is a fragment.
-	 * @throws java.lang.IllegalStateException If this bundle has been
-	 *         uninstalled or this bundle tries to change its own state.
-	 * @throws java.lang.SecurityException If the caller does not have the
-	 *         appropriate <code>AdminPermission[this,EXECUTE]</code>, and
-	 *         the Java Runtime Environment supports permissions.
+	 * @throws IllegalStateException If this bundle has been uninstalled or this
+	 *         bundle tries to change its own state.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
 	 * @since 1.4
 	 */
 	public void stop(int options) throws BundleException;
@@ -452,31 +469,40 @@
 	 * Stops this bundle with no options.
 	 * 
 	 * <p>
-	 * This method calls <code>stop(0)</code>.
+	 * This method performs the same function as calling <code>stop(0)</code>.
 	 * 
 	 * @throws BundleException If this bundle's <code>BundleActivator</code>
 	 *         threw an exception or this bundle is a fragment.
-	 * @throws java.lang.IllegalStateException If this bundle has been
-	 *         uninstalled or this bundle tries to change its own state.
-	 * @throws java.lang.SecurityException If the caller does not have the
-	 *         appropriate <code>AdminPermission[this,EXECUTE]</code>, and
-	 *         the Java Runtime Environment supports permissions.
+	 * @throws IllegalStateException If this bundle has been uninstalled or this
+	 *         bundle tries to change its own state.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
 	 * @see #start(int)
 	 */
 	public void stop() throws BundleException;
 
 	/**
-	 * Updates this bundle.
+	 * Updates this bundle from an <code>InputStream</code>.
 	 * 
 	 * <p>
-	 * If this bundle's state is <code>ACTIVE</code>, it must be stopped
-	 * before the update and started after the update successfully completes.
+	 * If the specified <code>InputStream</code> is <code>null</code>, the
+	 * Framework must create the <code>InputStream</code> from which to read the
+	 * updated bundle by interpreting, in an implementation dependent manner,
+	 * this bundle's {@link Constants#BUNDLE_UPDATELOCATION
+	 * Bundle-UpdateLocation} Manifest header, if present, or this bundle's
+	 * original location.
 	 * 
 	 * <p>
-	 * If this bundle has exported any packages, these packages must not be
-	 * updated. Instead, the previous package version must remain exported until
-	 * the <code>PackageAdmin.refreshPackages</code> method has been has been
-	 * called or the Framework is relaunched.
+	 * If this bundle's state is <code>ACTIVE</code>, it must be stopped before
+	 * the update and started after the update successfully completes.
+	 * 
+	 * <p>
+	 * If this bundle has exported any packages that are imported by another
+	 * bundle, these packages must not be updated. Instead, the previous package
+	 * version must remain exported until the
+	 * <code>PackageAdmin.refreshPackages</code> method has been has been called
+	 * or the Framework is relaunched.
 	 * 
 	 * <p>
 	 * The following steps are required to update a bundle:
@@ -484,36 +510,20 @@
 	 * <li>If this bundle's state is <code>UNINSTALLED</code> then an
 	 * <code>IllegalStateException</code> is thrown.
 	 * 
-	 * <li>If this bundle's state is <code>ACTIVE</code>,
-	 * <code>STARTING</code> or <code>STOPPING</code>, this bundle is
-	 * stopped as described in the <code>Bundle.stop</code> method. If
-	 * <code>Bundle.stop</code> throws an exception, the exception is rethrown
-	 * terminating the update.
+	 * <li>If this bundle's state is <code>ACTIVE</code>, <code>STARTING</code>
+	 * or <code>STOPPING</code>, this bundle is stopped as described in the
+	 * <code>Bundle.stop</code> method. If <code>Bundle.stop</code> throws an
+	 * exception, the exception is rethrown terminating the update.
 	 * 
-	 * <li>The download location of the new version of this bundle is
-	 * determined from either this bundle's
-	 * {@link Constants#BUNDLE_UPDATELOCATION} Manifest header (if available) or
-	 * this bundle's original location.
-	 * 
-	 * <li>The location is interpreted in an implementation dependent manner,
-	 * typically as a URL, and the new version of this bundle is obtained from
-	 * this location.
-	 * 
-	 * <li>The new version of this bundle is installed. If the Framework is
-	 * unable to install the new version of this bundle, the original version of
-	 * this bundle must be restored and a <code>BundleException</code> must be
-	 * thrown after completion of the remaining steps.
-	 * 
-	 * <li>If this bundle has declared an Bundle-RequiredExecutionEnvironment
-	 * header, then the listed execution environments must be verified against
-	 * the installed execution environments. If they do not all match, the
-	 * original version of this bundle must be restored and a
+	 * <li>The updated version of this bundle is read from the input stream and
+	 * installed. If the Framework is unable to install the updated version of
+	 * this bundle, the original version of this bundle must be restored and a
 	 * <code>BundleException</code> must be thrown after completion of the
 	 * remaining steps.
 	 * 
 	 * <li>This bundle's state is set to <code>INSTALLED</code>.
 	 * 
-	 * <li>If the new version of this bundle was successfully installed, a
+	 * <li>If the updated version of this bundle was successfully installed, a
 	 * bundle event of type {@link BundleEvent#UPDATED} is fired.
 	 * 
 	 * <li>If this bundle's state was originally <code>ACTIVE</code>, the
@@ -525,57 +535,59 @@
 	 * 
 	 * <b>Preconditions </b>
 	 * <ul>
-	 * <li><code>getState()</code> not in {<code>UNINSTALLED</code>}.
+	 * <li><code>getState()</code> not in &#x007B; <code>UNINSTALLED</code>
+	 * &#x007D;.
 	 * </ul>
 	 * <b>Postconditions, no exceptions thrown </b>
 	 * <ul>
-	 * <li><code>getState()</code> in {<code>INSTALLED</code>,
-	 * <code>RESOLVED</code>,<code>ACTIVE</code>}.
+	 * <li><code>getState()</code> in &#x007B; <code>INSTALLED</code>,
+	 * <code>RESOLVED</code>, <code>ACTIVE</code> &#x007D;.
 	 * <li>This bundle has been updated.
 	 * </ul>
 	 * <b>Postconditions, when an exception is thrown </b>
 	 * <ul>
-	 * <li><code>getState()</code> in {<code>INSTALLED</code>,
-	 * <code>RESOLVED</code>,<code>ACTIVE</code>}.
+	 * <li><code>getState()</code> in &#x007B; <code>INSTALLED</code>,
+	 * <code>RESOLVED</code>, <code>ACTIVE</code> &#x007D;.
 	 * <li>Original bundle is still used; no update occurred.
 	 * </ul>
 	 * 
-	 * @throws BundleException If the update fails.
-	 * @throws java.lang.IllegalStateException If this bundle has been
-	 *         uninstalled or this bundle tries to change its own state.
-	 * @throws java.lang.SecurityException If the caller does not have the
-	 *         appropriate <code>AdminPermission[this,LIFECYCLE]</code> for
-	 *         both the current bundle and the updated bundle, and the Java
-	 *         Runtime Environment supports permissions.
+	 * @param input The <code>InputStream</code> from which to read the new
+	 *        bundle or <code>null</code> to indicate the Framework must create
+	 *        the input stream from this bundle's
+	 *        {@link Constants#BUNDLE_UPDATELOCATION Bundle-UpdateLocation}
+	 *        Manifest header, if present, or this bundle's original location.
+	 *        The input stream must always be closed when this method completes,
+	 *        even if an exception is thrown.
+	 * @throws BundleException If the input stream cannot be read or the update
+	 *         fails.
+	 * @throws IllegalStateException If this bundle has been uninstalled or this
+	 *         bundle tries to change its own state.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,LIFECYCLE]</code> for both the current
+	 *         bundle and the updated bundle, and the Java Runtime Environment
+	 *         supports permissions.
 	 * @see #stop()
 	 * @see #start()
 	 */
-	public void update() throws BundleException;
+	public void update(InputStream input) throws BundleException;
 
 	/**
-	 * Updates this bundle from an <code>InputStream</code>.
+	 * Updates this bundle.
 	 * 
 	 * <p>
-	 * This method performs all the steps listed in <code>Bundle.update()</code>,
-	 * except the new version of this bundle must be read from the supplied
-	 * <code>InputStream</code>, rather than a <code>URL</code>.
-	 * <p>
-	 * This method must always close the <code>InputStream</code> when it is
-	 * done, even if an exception is thrown.
+	 * This method performs the same function as calling
+	 * {@link #update(InputStream)} with a <code>null</code> InputStream.
 	 * 
-	 * @param in The <code>InputStream</code> from which to read the new
-	 *        bundle.
-	 * @throws BundleException If the provided stream cannot be read or the
-	 *         update fails.
-	 * @throws java.lang.IllegalStateException If this bundle has been
-	 *         uninstalled or this bundle tries to change its own state.
-	 * @throws java.lang.SecurityException If the caller does not have the
-	 *         appropriate <code>AdminPermission[this,LIFECYCLE]</code> for
-	 *         both the current bundle and the updated bundle, and the Java
-	 *         Runtime Environment supports permissions.
-	 * @see #update()
+	 * @throws BundleException If the update fails.
+	 * @throws IllegalStateException If this bundle has been uninstalled or this
+	 *         bundle tries to change its own state.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,LIFECYCLE]</code> for both the current
+	 *         bundle and the updated bundle, and the Java Runtime Environment
+	 *         supports permissions.
+	 * @see #update(InputStream)
 	 */
-	public void update(InputStream in) throws BundleException;
+	public void update() throws BundleException;
 
 	/**
 	 * Uninstalls this bundle.
@@ -598,11 +610,11 @@
 	 * <li>If this bundle's state is <code>UNINSTALLED</code> then an
 	 * <code>IllegalStateException</code> is thrown.
 	 * 
-	 * <li>If this bundle's state is <code>ACTIVE</code>,
-	 * <code>STARTING</code> or <code>STOPPING</code>, this bundle is
-	 * stopped as described in the <code>Bundle.stop</code> method. If
-	 * <code>Bundle.stop</code> throws an exception, a Framework event of type
-	 * {@link FrameworkEvent#ERROR} is fired containing the exception.
+	 * <li>If this bundle's state is <code>ACTIVE</code>, <code>STARTING</code>
+	 * or <code>STOPPING</code>, this bundle is stopped as described in the
+	 * <code>Bundle.stop</code> method. If <code>Bundle.stop</code> throws an
+	 * exception, a Framework event of type {@link FrameworkEvent#ERROR} is
+	 * fired containing the exception.
 	 * 
 	 * <li>This bundle's state is set to <code>UNINSTALLED</code>.
 	 * 
@@ -614,27 +626,30 @@
 	 * 
 	 * <b>Preconditions </b>
 	 * <ul>
-	 * <li><code>getState()</code> not in {<code>UNINSTALLED</code>}.
+	 * <li><code>getState()</code> not in &#x007B; <code>UNINSTALLED</code>
+	 * &#x007D;.
 	 * </ul>
 	 * <b>Postconditions, no exceptions thrown </b>
 	 * <ul>
-	 * <li><code>getState()</code> in {<code>UNINSTALLED</code>}.
+	 * <li><code>getState()</code> in &#x007B; <code>UNINSTALLED</code>
+	 * &#x007D;.
 	 * <li>This bundle has been uninstalled.
 	 * </ul>
 	 * <b>Postconditions, when an exception is thrown </b>
 	 * <ul>
-	 * <li><code>getState()</code> not in {<code>UNINSTALLED</code>}.
+	 * <li><code>getState()</code> not in &#x007B; <code>UNINSTALLED</code>
+	 * &#x007D;.
 	 * <li>This Bundle has not been uninstalled.
 	 * </ul>
 	 * 
 	 * @throws BundleException If the uninstall failed. This can occur if
 	 *         another thread is attempting to change this bundle's state and
 	 *         does not complete in a timely manner.
-	 * @throws java.lang.IllegalStateException If this bundle has been
-	 *         uninstalled or this bundle tries to change its own state.
-	 * @throws java.lang.SecurityException If the caller does not have the
-	 *         appropriate <code>AdminPermission[this,LIFECYCLE]</code>, and
-	 *         the Java Runtime Environment supports permissions.
+	 * @throws IllegalStateException If this bundle has been uninstalled or this
+	 *         bundle tries to change its own state.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+	 *         Runtime Environment supports permissions.
 	 * @see #stop()
 	 */
 	public void uninstall() throws BundleException;
@@ -650,7 +665,9 @@
 	 * case-insensitive manner.
 	 * 
 	 * If a Manifest header value starts with &quot;%&quot;, it must be
-	 * localized according to the default locale.
+	 * localized according to the default locale. If no localization is found
+	 * for a header value, the header value without the leading &quot;%&quot; is
+	 * returned.
 	 * 
 	 * <p>
 	 * For example, the following Manifest headers and values are included if
@@ -671,14 +688,12 @@
 	 * 
 	 * @return A <code>Dictionary</code> object containing this bundle's
 	 *         Manifest headers and values.
-	 * 
-	 * @throws java.lang.SecurityException If the caller does not have the
+	 * @throws SecurityException If the caller does not have the
 	 *         appropriate <code>AdminPermission[this,METADATA]</code>, and
 	 *         the Java Runtime Environment supports permissions.
-	 * 
 	 * @see Constants#BUNDLE_LOCALIZATION
 	 */
-	public Dictionary getHeaders();
+	public Dictionary/* <String,String> */getHeaders();
 
 	/**
 	 * Returns this bundle's unique identifier. This bundle is assigned a unique
@@ -718,7 +733,7 @@
 	 * while this bundle is in the <code>UNINSTALLED</code> state.
 	 * 
 	 * @return The string representation of this bundle's location identifier.
-	 * @throws java.lang.SecurityException If the caller does not have the
+	 * @throws SecurityException If the caller does not have the
 	 *         appropriate <code>AdminPermission[this,METADATA]</code>, and
 	 *         the Java Runtime Environment supports permissions.
 	 */
@@ -742,7 +757,7 @@
 	 * 
 	 * @return An array of <code>ServiceReference</code> objects or
 	 *         <code>null</code>.
-	 * @throws java.lang.IllegalStateException If this bundle has been
+	 * @throws IllegalStateException If this bundle has been
 	 *         uninstalled.
 	 * @see ServiceRegistration
 	 * @see ServiceReference
@@ -769,7 +784,7 @@
 	 * 
 	 * @return An array of <code>ServiceReference</code> objects or
 	 *         <code>null</code>.
-	 * @throws java.lang.IllegalStateException If this bundle has been
+	 * @throws IllegalStateException If this bundle has been
 	 *         uninstalled.
 	 * @see ServiceReference
 	 * @see ServicePermission
@@ -795,43 +810,43 @@
 	 * the same set of permissions.
 	 * 
 	 * @param permission The permission to verify.
-	 * 
 	 * @return <code>true</code> if this bundle has the specified permission
 	 *         or the permissions possessed by this bundle imply the specified
 	 *         permission; <code>false</code> if this bundle does not have the
 	 *         specified permission or <code>permission</code> is not an
 	 *         <code>instanceof</code> <code>java.security.Permission</code>.
-	 * 
-	 * @throws java.lang.IllegalStateException If this bundle has been
+	 * @throws IllegalStateException If this bundle has been
 	 *         uninstalled.
 	 */
 	public boolean hasPermission(Object permission);
 
 	/**
-	 * Find the specified resource from this bundle.
+	 * Find the specified resource from this bundle's class loader.
 	 * 
 	 * This bundle's class loader is called to search for the specified
-	 * resource. If this bundle's state is <code>INSTALLED</code>, this
-	 * method must attempt to resolve this bundle before attempting to get the
+	 * resource. If this bundle's state is <code>INSTALLED</code>, this method
+	 * must attempt to resolve this bundle before attempting to get the
 	 * specified resource. If this bundle cannot be resolved, then only this
 	 * bundle must be searched for the specified resource. Imported packages
 	 * cannot be searched when this bundle has not been resolved. If this bundle
 	 * is a fragment bundle then <code>null</code> is returned.
+	 * <p>
+	 * Note: Jar and zip files are not required to include directory entries.
+	 * URLs to directory entries will not be returned if the bundle contents do
+	 * not contain directory entries.
 	 * 
 	 * @param name The name of the resource. See
-	 *        <code>java.lang.ClassLoader.getResource</code> for a description
-	 *        of the format of a resource name.
-	 * @return A URL to the named resource, or <code>null</code> if the
-	 *         resource could not be found or if this bundle is a fragment
-	 *         bundle or if the caller does not have the appropriate
-	 *         <code>AdminPermission[this,RESOURCE]</code>, and the Java
-	 *         Runtime Environment supports permissions.
-	 * 
-	 * @since 1.1
-	 * @throws java.lang.IllegalStateException If this bundle has been
-	 *         uninstalled.
+	 *        <code>ClassLoader.getResource</code> for a description of the
+	 *        format of a resource name.
+	 * @return A URL to the named resource, or <code>null</code> if the resource
+	 *         could not be found or if this bundle is a fragment bundle or if
+	 *         the caller does not have the appropriate
+	 *         <code>AdminPermission[this,RESOURCE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
+	 * @throws IllegalStateException If this bundle has been uninstalled.
 	 * @see #getEntry
 	 * @see #findEntries
+	 * @since 1.1
 	 */
 	public URL getResource(String name);
 
@@ -851,13 +866,13 @@
 	 * default locale. Localizations are searched for in the following order:
 	 * 
 	 * <pre>
-	 *   bn + "_" + Ls + "_" + Cs + "_" + Vs
-     *   bn + "_" + Ls + "_" + Cs
-     *   bn + "_" + Ls
-     *   bn + "_" + Ld + "_" + Cd + "_" + Vd
-     *   bn + "_" + Ld + "_" + Cd
-     *   bn + "_" + Ld
-	 *     bn
+	 *   bn + &quot;_&quot; + Ls + &quot;_&quot; + Cs + &quot;_&quot; + Vs
+	 *   bn + &quot;_&quot; + Ls + &quot;_&quot; + Cs
+	 *   bn + &quot;_&quot; + Ls
+	 *   bn + &quot;_&quot; + Ld + &quot;_&quot; + Cd + &quot;_&quot; + Vd
+	 *   bn + &quot;_&quot; + Ld + &quot;_&quot; + Cd
+	 *   bn + &quot;_&quot; + Ld
+	 *   bn
 	 * </pre>
 	 * 
 	 * Where <code>bn</code> is this bundle's localization basename,
@@ -870,7 +885,9 @@
 	 * values must be localized using the default locale. If the empty string
 	 * (&quot;&quot;) is specified as the locale string, the header values must
 	 * not be localized and the raw (unlocalized) header values, including any
-	 * leading &quot;%&quot;, must be returned.
+	 * leading &quot;%&quot;, must be returned. If no localization is found for
+	 * a header value, the header value without the leading &quot;%&quot; is
+	 * returned.
 	 * 
 	 * <p>
 	 * This method must continue to return Manifest header information while
@@ -886,35 +903,34 @@
 	 *        leading &quot;%&quot;.
 	 * @return A <code>Dictionary</code> object containing this bundle's
 	 *         Manifest headers and values.
-	 * 
-	 * @throws java.lang.SecurityException If the caller does not have the
+	 * @throws SecurityException If the caller does not have the
 	 *         appropriate <code>AdminPermission[this,METADATA]</code>, and
 	 *         the Java Runtime Environment supports permissions.
-	 * 
 	 * @see #getHeaders()
 	 * @see Constants#BUNDLE_LOCALIZATION
 	 * @since 1.3
 	 */
-	public Dictionary getHeaders(String locale);
+	public Dictionary/* <String,String> */getHeaders(String locale);
 
 	/**
 	 * Returns the symbolic name of this bundle as specified by its
-	 * <code>Bundle-SymbolicName</code> manifest header. The name must be
-	 * unique, it is recommended to use a reverse domain name naming convention
-	 * like that used for java packages. If this bundle does not have a
-	 * specified symbolic name then <code>null</code> is returned.
+	 * <code>Bundle-SymbolicName</code> manifest header. The bundle symbolic
+	 * name together with a version must identify a unique bundle. The bundle
+	 * symbolic name should be based on the reverse domain name naming
+	 * convention like that used for java packages.
 	 * 
 	 * <p>
 	 * This method must continue to return this bundle's symbolic name while
 	 * this bundle is in the <code>UNINSTALLED</code> state.
 	 * 
-	 * @return The symbolic name of this bundle.
+	 * @return The symbolic name of this bundle or <code>null</code> if this
+	 *         bundle does not have a symbolic name.
 	 * @since 1.3
 	 */
 	public String getSymbolicName();
 
 	/**
-	 * Loads the specified class using this bundle's classloader.
+	 * Loads the specified class using this bundle's class loader.
 	 * 
 	 * <p>
 	 * If this bundle is a fragment bundle then this method must throw a
@@ -937,47 +953,49 @@
 	 * 
 	 * @param name The name of the class to load.
 	 * @return The Class object for the requested class.
-	 * @throws java.lang.ClassNotFoundException If no such class can be found or
+	 * @throws ClassNotFoundException If no such class can be found or
 	 *         if this bundle is a fragment bundle or if the caller does not
 	 *         have the appropriate <code>AdminPermission[this,CLASS]</code>,
 	 *         and the Java Runtime Environment supports permissions.
-	 * @throws java.lang.IllegalStateException If this bundle has been
+	 * @throws IllegalStateException If this bundle has been
 	 *         uninstalled.
 	 * @since 1.3
 	 */
 	public Class loadClass(String name) throws ClassNotFoundException;
 
 	/**
-	 * Find the specified resources from this bundle.
+	 * Find the specified resources from this bundle's class loader.
 	 * 
 	 * This bundle's class loader is called to search for the specified
-	 * resources. If this bundle's state is <code>INSTALLED</code>, this
-	 * method must attempt to resolve this bundle before attempting to get the
+	 * resources. If this bundle's state is <code>INSTALLED</code>, this method
+	 * must attempt to resolve this bundle before attempting to get the
 	 * specified resources. If this bundle cannot be resolved, then only this
 	 * bundle must be searched for the specified resources. Imported packages
 	 * cannot be searched when a bundle has not been resolved. If this bundle is
 	 * a fragment bundle then <code>null</code> is returned.
+	 * <p>
+	 * Note: Jar and zip files are not required to include directory entries.
+	 * URLs to directory entries will not be returned if the bundle contents do
+	 * not contain directory entries.
 	 * 
 	 * @param name The name of the resource. See
-	 *        <code>java.lang.ClassLoader.getResources</code> for a
-	 *        description of the format of a resource name.
+	 *        <code>ClassLoader.getResources</code> for a description of the
+	 *        format of a resource name.
 	 * @return An enumeration of URLs to the named resources, or
 	 *         <code>null</code> if the resource could not be found or if this
 	 *         bundle is a fragment bundle or if the caller does not have the
-	 *         appropriate <code>AdminPermission[this,RESOURCE]</code>, and
-	 *         the Java Runtime Environment supports permissions.
-	 * 
+	 *         appropriate <code>AdminPermission[this,RESOURCE]</code>, and the
+	 *         Java Runtime Environment supports permissions.
+	 * @throws IllegalStateException If this bundle has been uninstalled.
+	 * @throws IOException If there is an I/O error.
 	 * @since 1.3
-	 * @throws java.lang.IllegalStateException If this bundle has been
-	 *         uninstalled.
-	 * @throws java.io.IOException If there is an I/O error.
 	 */
-	public Enumeration getResources(String name) throws IOException;
+	public Enumeration/* <URL> */getResources(String name) throws IOException;
 
 	/**
 	 * Returns an Enumeration of all the paths (<code>String</code> objects)
 	 * to entries within this bundle whose longest sub-path matches the
-	 * specified path. This bundle's classloader is not used to search for
+	 * specified path. This bundle's class loader is not used to search for
 	 * entries. Only the contents of this bundle are searched.
 	 * <p>
 	 * The specified path is always relative to the root of this bundle and may
@@ -987,6 +1005,10 @@
 	 * Returned paths indicating subdirectory paths end with a &quot;/&quot;.
 	 * The returned paths are all relative to the root of this bundle and must
 	 * not begin with &quot;/&quot;.
+	 * <p>
+	 * Note: Jar and zip files are not required to include directory entries.
+	 * Paths to directory entries will not be returned if the bundle contents do
+	 * not contain directory entries.
 	 * 
 	 * @param path The path name for which to return entry paths.
 	 * @return An Enumeration of the entry paths (<code>String</code>
@@ -994,28 +1016,31 @@
 	 *         the caller does not have the appropriate
 	 *         <code>AdminPermission[this,RESOURCE]</code> and the Java
 	 *         Runtime Environment supports permissions.
-	 * @throws java.lang.IllegalStateException If this bundle has been
+	 * @throws IllegalStateException If this bundle has been
 	 *         uninstalled.
 	 * @since 1.3
 	 */
-	public Enumeration getEntryPaths(String path);
+	public Enumeration/* <String> */getEntryPaths(String path);
 
 	/**
 	 * Returns a URL to the entry at the specified path in this bundle. This
-	 * bundle's classloader is not used to search for the entry. Only the
+	 * bundle's class loader is not used to search for the entry. Only the
 	 * contents of this bundle are searched for the entry.
 	 * <p>
 	 * The specified path is always relative to the root of this bundle and may
 	 * begin with &quot;/&quot;. A path value of &quot;/&quot; indicates the
 	 * root of this bundle.
+	 * <p>
+	 * Note: Jar and zip files are not required to include directory entries.
+	 * URLs to directory entries will not be returned if the bundle contents do
+	 * not contain directory entries.
 	 * 
 	 * @param path The path name of the entry.
 	 * @return A URL to the entry, or <code>null</code> if no entry could be
 	 *         found or if the caller does not have the appropriate
 	 *         <code>AdminPermission[this,RESOURCE]</code> and the Java
 	 *         Runtime Environment supports permissions.
-	 * 
-	 * @throws java.lang.IllegalStateException If this bundle has been
+	 * @throws IllegalStateException If this bundle has been
 	 *         uninstalled.
 	 * @since 1.3
 	 */
@@ -1036,7 +1061,7 @@
 
 	/**
 	 * Returns entries in this bundle and its attached fragments. This bundle's
-	 * classloader is not used to search for entries. Only the contents of this
+	 * class loader is not used to search for entries. Only the contents of this
 	 * bundle and its attached fragments are searched for the specified entries.
 	 * 
 	 * If this bundle's state is <code>INSTALLED</code>, this method must
@@ -1064,36 +1089,43 @@
 	 * Enumeration e = b.findEntries(&quot;OSGI-INF&quot;, &quot;*.xml&quot;, true);
 	 * 
 	 * // Find a specific localization file
-	 * Enumeration e = b.findEntries(&quot;OSGI-INF/l10n&quot;, 
-	 *                               &quot;bundle_nl_DU.properties&quot;, 
-	 *                               false);
+	 * Enumeration e = b
+	 * 		.findEntries(&quot;OSGI-INF/l10n&quot;, &quot;bundle_nl_DU.properties&quot;, false);
 	 * if (e.hasMoreElements())
 	 * 	return (URL) e.nextElement();
 	 * </pre>
 	 * 
+	 * <p>
+	 * Note: Jar and zip files are not required to include directory entries.
+	 * URLs to directory entries will not be returned if the bundle contents do
+	 * not contain directory entries.
+	 * 
 	 * @param path The path name in which to look. The path is always relative
 	 *        to the root of this bundle and may begin with &quot;/&quot;. A
 	 *        path value of &quot;/&quot; indicates the root of this bundle.
 	 * @param filePattern The file name pattern for selecting entries in the
 	 *        specified path. The pattern is only matched against the last
-	 *        element of the entry path and it supports substring matching, as
-	 *        specified in the Filter specification, using the wildcard
-	 *        character (&quot;*&quot;). If null is specified, this is
-	 *        equivalent to &quot;*&quot; and matches all files.
+	 *        element of the entry path. If the entry is a directory then the
+	 *        trailing &quot;/&quot; is not used for pattern matching. Substring
+	 *        matching is supported, as specified in the Filter specification,
+	 *        using the wildcard character (&quot;*&quot;). If null is
+	 *        specified, this is equivalent to &quot;*&quot; and matches all
+	 *        files.
 	 * @param recurse If <code>true</code>, recurse into subdirectories.
 	 *        Otherwise only return entries from the specified path.
 	 * @return An enumeration of URL objects for each matching entry, or
-	 *         <code>null</code> if an entry could not be found or if the
-	 *         caller does not have the appropriate
-	 *         <code>AdminPermission[this,RESOURCE]</code>, and the Java
-	 *         Runtime Environment supports permissions. The URLs are sorted
-	 *         such that entries from this bundle are returned first followed by
-	 *         the entries from attached fragments in ascending bundle id order.
-	 *         If this bundle is a fragment, then only matching entries in this
+	 *         <code>null</code> if an entry could not be found or if the caller
+	 *         does not have the appropriate
+	 *         <code>AdminPermission[this,RESOURCE]</code>, and the Java Runtime
+	 *         Environment supports permissions. The URLs are sorted such that
+	 *         entries from this bundle are returned first followed by the
+	 *         entries from attached fragments in ascending bundle id order. If
+	 *         this bundle is a fragment, then only matching entries in this
 	 *         fragment are returned.
+	 * @throws IllegalStateException If this bundle has been uninstalled.
 	 * @since 1.3
 	 */
-	public Enumeration findEntries(String path, String filePattern,
+	public Enumeration/* <URL> */findEntries(String path, String filePattern,
 			boolean recurse);
 
 	/**
@@ -1111,10 +1143,52 @@
 	 * @return A <code>BundleContext</code> for this bundle or
 	 *         <code>null</code> if this bundle has no valid
 	 *         <code>BundleContext</code>.
-	 * @throws java.lang.SecurityException If the caller does not have the
+	 * @throws SecurityException If the caller does not have the
 	 *         appropriate <code>AdminPermission[this,CONTEXT]</code>, and
 	 *         the Java Runtime Environment supports permissions.
 	 * @since 1.4
 	 */
 	public BundleContext getBundleContext();
+
+	/**
+	 * Return the certificates for the signers of this bundle and the
+	 * certificate chains for those signers.
+	 * 
+	 * @param signersType If {@link #SIGNERS_ALL} is specified, then information
+	 *        on all signers of this bundle is returned. If
+	 *        {@link #SIGNERS_TRUSTED} is specified, then only information on
+	 *        the signers of this bundle trusted by the framework is returned.
+	 * @return The <code>X509Certificate</code>s for the signers of this bundle
+	 *         and the <code>X509Certificate</code> chains for those signers.
+	 *         The keys of the <code>Map</code> are the
+	 *         <code>X509Certificate</code>s of the signers of this bundle. The
+	 *         value for a key is a <code>List</code> containing the
+	 *         <code>X509Certificate</code> chain for the signer. The first item
+	 *         in the <code>List</code> is the signer's
+	 *         <code>X509Certificate</code> which is then followed by the rest
+	 *         of the <code>X509Certificate</code> chain. The returned
+	 *         <code>Map</code> will be empty if there are no signers. The
+	 *         returned <code>Map</code> is the property of the caller who is
+	 *         free to modify it.
+	 * @throws IllegalArgumentException If the specified
+	 *         <code>signersType</code> is not {@link #SIGNERS_ALL} or
+	 *         {@link #SIGNERS_TRUSTED}.
+	 * @since 1.5
+	 */
+	public Map/* <X509Certificate, List<X509Certificate>> */getSignerCertificates(
+			int signersType);
+	
+	/**
+	 * Returns the version of this bundle as specified by its
+	 * <code>Bundle-Version</code> manifest header. If this bundle does not have a
+	 * specified version then {@link Version#emptyVersion} is returned.
+	 * 
+	 * <p>
+	 * This method must continue to return this bundle's version while
+	 * this bundle is in the <code>UNINSTALLED</code> state.
+	 * 
+	 * @return The version of this bundle.
+	 * @since 1.5
+	 */
+	public Version getVersion();
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleActivator.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleActivator.java
index a3344e6..56660b1 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundleActivator.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleActivator.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundleActivator.java,v 1.14 2007/02/21 16:49:05 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -47,7 +45,7 @@
  * object can be created by <code>Class.newInstance()</code>.
  * 
  * @NotThreadSafe
- * @version $Revision: 1.14 $
+ * @version $Revision: 6361 $
  */
 
 public interface BundleActivator {
@@ -61,7 +59,7 @@
 	 * This method must complete and return to its caller in a timely manner.
 	 * 
 	 * @param context The execution context of the bundle being started.
-	 * @throws java.lang.Exception If this method throws an exception, this
+	 * @throws Exception If this method throws an exception, this
 	 *         bundle is marked as stopped and the Framework will remove this
 	 *         bundle's listeners, unregister all services registered by this
 	 *         bundle, and release all services used by this bundle.
@@ -80,7 +78,7 @@
 	 * This method must complete and return to its caller in a timely manner.
 	 * 
 	 * @param context The execution context of the bundle being stopped.
-	 * @throws java.lang.Exception If this method throws an exception, the
+	 * @throws Exception If this method throws an exception, the
 	 *         bundle is still marked as stopped, and the Framework will remove
 	 *         the bundle's listeners, unregister all services registered by the
 	 *         bundle, and release all services used by the bundle.
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleContext.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleContext.java
index c7d1768..44b3801 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundleContext.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleContext.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundleContext.java,v 1.22 2007/02/21 16:49:05 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -70,7 +68,7 @@
  * objects and they are only valid within the Framework that created them.
  * 
  * @ThreadSafe
- * @version $Revision: 1.22 $
+ * @version $Revision: 6781 $
  */
 
 public interface BundleContext {
@@ -80,36 +78,15 @@
 	 * method returns <code>null</code> if the property is not found.
 	 * 
 	 * <p>
-	 * The Framework defines the following standard property keys:
-	 * </p>
-	 * <ul>
-	 * <li>{@link Constants#FRAMEWORK_VERSION} - The OSGi Framework version.
-	 * </li>
-	 * <li>{@link Constants#FRAMEWORK_VENDOR} - The Framework implementation
-	 * vendor.</li>
-	 * <li>{@link Constants#FRAMEWORK_LANGUAGE} - The language being used. See
-	 * ISO 639 for possible values.</li>
-	 * <li>{@link Constants#FRAMEWORK_OS_NAME} - The host computer operating
-	 * system.</li>
-	 * <li>{@link Constants#FRAMEWORK_OS_VERSION} - The host computer
-	 * operating system version number.</li>
-	 * <li>{@link Constants#FRAMEWORK_PROCESSOR} - The host computer processor
-	 * name.</li>
-	 * </ul>
-	 * <p>
-	 * All bundles must have permission to read these properties.
-	 * 
-	 * <p>
-	 * Note: The last four standard properties are used by the
-	 * {@link Constants#BUNDLE_NATIVECODE} <code>Manifest</code> header's
-	 * matching algorithm for selecting native language code.
+	 * All bundles must have permission to read properties whose names start
+	 * with &quot;org.osgi.&quot;.
 	 * 
 	 * @param key The name of the requested property.
-	 * @return The value of the requested property, or <code>null</code> if
-	 *         the property is undefined.
-	 * @throws java.lang.SecurityException If the caller does not have the
-	 *         appropriate <code>PropertyPermission</code> to read the
-	 *         property, and the Java Runtime Environment supports permissions.
+	 * @return The value of the requested property, or <code>null</code> if the
+	 *         property is undefined.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>PropertyPermission</code> to read the property, and the
+	 *         Java Runtime Environment supports permissions.
 	 */
 	public String getProperty(String key);
 
@@ -119,53 +96,51 @@
 	 * 
 	 * @return The <code>Bundle</code> object associated with this
 	 *         <code>BundleContext</code>.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
+	 * @throws IllegalStateException If this BundleContext is no
 	 *         longer valid.
 	 */
 	public Bundle getBundle();
 
 	/**
-	 * Installs a bundle from the specified location string. A bundle is
-	 * obtained from <code>location</code> as interpreted by the Framework in
-	 * an implementation dependent manner.
+	 * Installs a bundle from the specified <code>InputStream</code> object.
+	 * 
 	 * <p>
-	 * Every installed bundle is uniquely identified by its location string,
-	 * typically in the form of a URL.
+	 * If the specified <code>InputStream</code> is <code>null</code>, the
+	 * Framework must create the <code>InputStream</code> from which to read the
+	 * bundle by interpreting, in an implementation dependent manner, the
+	 * specified <code>location</code>.
+	 * 
+	 * <p>
+	 * The specified <code>location</code> identifier will be used as the
+	 * identity of the bundle. Every installed bundle is uniquely identified by
+	 * its location identifier which is typically in the form of a URL.
 	 * 
 	 * <p>
 	 * The following steps are required to install a bundle:
 	 * <ol>
-	 * <li>If a bundle containing the same location string is already
+	 * <li>If a bundle containing the same location identifier is already
 	 * installed, the <code>Bundle</code> object for that bundle is returned.
 	 * 
-	 * <li>The bundle's content is read from the location string. If this
-	 * fails, a {@link BundleException} is thrown.
-	 * 
-	 * <li>The bundle's <code>Bundle-NativeCode</code> dependencies are
-	 * resolved. If this fails, a <code>BundleException</code> is thrown.
+	 * <li>The bundle's content is read from the input stream. If this fails, a
+	 * {@link BundleException} is thrown.
 	 * 
 	 * <li>The bundle's associated resources are allocated. The associated
 	 * resources minimally consist of a unique identifier and a persistent
 	 * storage area if the platform has file system support. If this step fails,
 	 * a <code>BundleException</code> is thrown.
 	 * 
-	 * <li>If the bundle has declared an Bundle-RequiredExecutionEnvironment
-	 * header, then the listed execution environments must be verified against
-	 * the installed execution environments. If none of the listed execution 
-	 * environments match an installed execution environment, a
-	 * <code>BundleException</code> must be thrown.
-	 * 
 	 * <li>The bundle's state is set to <code>INSTALLED</code>.
 	 * 
 	 * <li>A bundle event of type {@link BundleEvent#INSTALLED} is fired.
 	 * 
-	 * <li>The <code>Bundle</code> object for the newly or previously
-	 * installed bundle is returned.
+	 * <li>The <code>Bundle</code> object for the newly or previously installed
+	 * bundle is returned.
 	 * </ol>
 	 * 
 	 * <b>Postconditions, no exceptions thrown </b>
 	 * <ul>
-	 * <li><code>getState()</code> in {<code>INSTALLED</code>,<code>RESOLVED</code>}.
+	 * <li><code>getState()</code> in &#x007B; <code>INSTALLED</code>,
+	 * <code>RESOLVED</code> &#x007D;.
 	 * <li>Bundle has a unique ID.
 	 * </ul>
 	 * <b>Postconditions, when an exception is thrown </b>
@@ -174,48 +149,42 @@
 	 * </ul>
 	 * 
 	 * @param location The location identifier of the bundle to install.
-	 * @return The <code>Bundle</code> object of the installed bundle.
-	 * @throws BundleException If the installation failed.
-	 * @throws java.lang.SecurityException If the caller does not have the
-	 *         appropriate <code>AdminPermission[installed bundle,LIFECYCLE]</code>, and the
-	 *         Java Runtime Environment supports permissions.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
-	 *         longer valid.
-	 */
-	public Bundle installBundle(String location)
-			throws BundleException;
-
-	/**
-	 * Installs a bundle from the specified <code>InputStream</code> object.
-	 * 
-	 * <p>
-	 * This method performs all of the steps listed in
-	 * <code>BundleContext.installBundle(String location)</code>, except that
-	 * the bundle's content will be read from the <code>InputStream</code>
-	 * object. The location identifier string specified will be used as the
-	 * identity of the bundle.
-	 * 
-	 * <p>
-	 * This method must always close the <code>InputStream</code> object, even
-	 * if an exception is thrown.
-	 * 
-	 * @param location The location identifier of the bundle to install.
 	 * @param input The <code>InputStream</code> object from which this bundle
-	 *        will be read.
+	 *        will be read or <code>null</code> to indicate the Framework must
+	 *        create the input stream from the specified location identifier.
+	 *        The input stream must always be closed when this method completes,
+	 *        even if an exception is thrown.
 	 * @return The <code>Bundle</code> object of the installed bundle.
-	 * @throws BundleException If the provided stream cannot be read or the
+	 * @throws BundleException If the input stream cannot be read or the
 	 *         installation failed.
-	 * @throws java.lang.SecurityException If the caller does not have the
-	 *         appropriate <code>AdminPermission[installed bundle,LIFECYCLE]</code>, and the
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[installed bundle,LIFECYCLE]</code>, and the
 	 *         Java Runtime Environment supports permissions.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
-	 *         longer valid.
-	 * @see #installBundle(java.lang.String)
+	 * @throws IllegalStateException If this BundleContext is no longer valid.
 	 */
 	public Bundle installBundle(String location, InputStream input)
 			throws BundleException;
 
 	/**
+	 * Installs a bundle from the specified <code>location</code> identifier.
+	 * 
+	 * <p>
+	 * This method performs the same function as calling
+	 * {@link #installBundle(String,InputStream)} with the specified
+	 * <code>location</code> identifier and a <code>null</code> InputStream.
+	 * 
+	 * @param location The location identifier of the bundle to install.
+	 * @return The <code>Bundle</code> object of the installed bundle.
+	 * @throws BundleException If the installation failed.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[installed bundle,LIFECYCLE]</code>, and the
+	 *         Java Runtime Environment supports permissions.
+	 * @throws IllegalStateException If this BundleContext is no longer valid.
+	 * @see #installBundle(String, InputStream)
+	 */
+	public Bundle installBundle(String location) throws BundleException;
+
+	/**
 	 * Returns the bundle with the specified identifier.
 	 * 
 	 * @param id The identifier of the bundle to retrieve.
@@ -279,18 +248,16 @@
 	 * 
 	 * @param listener The <code>ServiceListener</code> object to be added.
 	 * @param filter The filter criteria.
-	 * 
 	 * @throws InvalidSyntaxException If <code>filter</code> contains an
 	 *         invalid filter string that cannot be parsed.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
+	 * @throws IllegalStateException If this BundleContext is no
 	 *         longer valid.
-	 * 
 	 * @see ServiceEvent
 	 * @see ServiceListener
 	 * @see ServicePermission
 	 */
-	public void addServiceListener(ServiceListener listener,
-			String filter) throws InvalidSyntaxException;
+	public void addServiceListener(ServiceListener listener, String filter)
+			throws InvalidSyntaxException;
 
 	/**
 	 * Adds the specified <code>ServiceListener</code> object to the context
@@ -303,9 +270,8 @@
 	 * with <code>filter</code> set to <code>null</code>.
 	 * 
 	 * @param listener The <code>ServiceListener</code> object to be added.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
+	 * @throws IllegalStateException If this BundleContext is no
 	 *         longer valid.
-	 * 
 	 * @see #addServiceListener(ServiceListener, String)
 	 */
 	public void addServiceListener(ServiceListener listener);
@@ -319,7 +285,7 @@
 	 * of listeners, this method does nothing.
 	 * 
 	 * @param listener The <code>ServiceListener</code> to be removed.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
+	 * @throws IllegalStateException If this BundleContext is no
 	 *         longer valid.
 	 */
 	public void removeServiceListener(ServiceListener listener);
@@ -335,13 +301,13 @@
 	 * does nothing.
 	 * 
 	 * @param listener The <code>BundleListener</code> to be added.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
+	 * @throws IllegalStateException If this BundleContext is no
 	 *         longer valid.
-	 * @throws java.lang.SecurityException If listener is a
+	 * @throws SecurityException If listener is a
 	 *         <code>SynchronousBundleListener</code> and the caller does not
-	 *         have the appropriate <code>AdminPermission[context bundle,LISTENER]</code>,
-	 *         and the Java Runtime Environment supports permissions.
-	 * 
+	 *         have the appropriate
+	 *         <code>AdminPermission[context bundle,LISTENER]</code>, and the
+	 *         Java Runtime Environment supports permissions.
 	 * @see BundleEvent
 	 * @see BundleListener
 	 */
@@ -356,12 +322,13 @@
 	 * of listeners, this method does nothing.
 	 * 
 	 * @param listener The <code>BundleListener</code> object to be removed.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
+	 * @throws IllegalStateException If this BundleContext is no
 	 *         longer valid.
-	 * @throws java.lang.SecurityException If listener is a
+	 * @throws SecurityException If listener is a
 	 *         <code>SynchronousBundleListener</code> and the caller does not
-	 *         have the appropriate <code>AdminPermission[context bundle,LISTENER]</code>,
-	 *         and the Java Runtime Environment supports permissions.
+	 *         have the appropriate
+	 *         <code>AdminPermission[context bundle,LISTENER]</code>, and the
+	 *         Java Runtime Environment supports permissions.
 	 */
 	public void removeBundleListener(BundleListener listener);
 
@@ -376,9 +343,8 @@
 	 * does nothing.
 	 * 
 	 * @param listener The <code>FrameworkListener</code> object to be added.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
+	 * @throws IllegalStateException If this BundleContext is no
 	 *         longer valid.
-	 * 
 	 * @see FrameworkEvent
 	 * @see FrameworkListener
 	 */
@@ -394,7 +360,7 @@
 	 * 
 	 * @param listener The <code>FrameworkListener</code> object to be
 	 *        removed.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
+	 * @throws IllegalStateException If this BundleContext is no
 	 *         longer valid.
 	 */
 	public void removeFrameworkListener(FrameworkListener listener);
@@ -417,21 +383,21 @@
 	 * <p>
 	 * The following steps are required to register a service:
 	 * <ol>
-	 * <li>If <code>service</code> is not a <code>ServiceFactory</code>,
-	 * an <code>IllegalArgumentException</code> is thrown if
-	 * <code>service</code> is not an <code>instanceof</code> all the
-	 * classes named.
-	 * <li>The Framework adds these service properties to the specified
-	 * <code>Dictionary</code> (which may be <code>null</code>): a property
-	 * named {@link Constants#SERVICE_ID} identifying the registration number of
-	 * the service and a property named {@link Constants#OBJECTCLASS} containing
-	 * all the specified classes. If any of these properties have already been
-	 * specified by the registering bundle, their values will be overwritten by
-	 * the Framework.
-	 * <li>The service is added to the Framework service registry and may now
-	 * be used by other bundles.
-	 * <li>A service event of type {@link ServiceEvent#REGISTERED} is
-	 * fired.
+	 * <li>If <code>service</code> is not a <code>ServiceFactory</code>, an
+	 * <code>IllegalArgumentException</code> is thrown if <code>service</code>
+	 * is not an <code>instanceof</code> all the specified class names.
+	 * <li>The Framework adds the following service properties to the service
+	 * properties from the specified <code>Dictionary</code> (which may be
+	 * <code>null</code>): <br/>
+	 * A property named {@link Constants#SERVICE_ID} identifying the
+	 * registration number of the service <br/>
+	 * A property named {@link Constants#OBJECTCLASS} containing all the
+	 * specified classes. <br/>
+	 * Properties with these names in the specified <code>Dictionary</code> will
+	 * be ignored.
+	 * <li>The service is added to the Framework service registry and may now be
+	 * used by other bundles.
+	 * <li>A service event of type {@link ServiceEvent#REGISTERED} is fired.
 	 * <li>A <code>ServiceRegistration</code> object for this registration is
 	 * returned.
 	 * </ol>
@@ -447,32 +413,24 @@
 	 *        Changes should not be made to this object after calling this
 	 *        method. To update the service's properties the
 	 *        {@link ServiceRegistration#setProperties} method must be called.
-	 *        The set of properties may be <code>null</code> if the service
-	 *        has no properties.
-	 * 
+	 *        The set of properties may be <code>null</code> if the service has
+	 *        no properties.
 	 * @return A <code>ServiceRegistration</code> object for use by the bundle
 	 *         registering the service to update the service's properties or to
 	 *         unregister the service.
-	 * 
-	 * @throws java.lang.IllegalArgumentException If one of the following is
-	 *         true:
+	 * @throws IllegalArgumentException If one of the following is true:
 	 *         <ul>
-	 *         <li><code>service</code> is <code>null</code>.
-	 *         <li><code>service</code> is not a <code>ServiceFactory</code>
-	 *         object and is not an instance of all the named classes in
-	 *         <code>clazzes</code>.
-	 *         <li><code>properties</code> contains case variants of the same
-	 *         key name.
+	 *         <li><code>service</code> is <code>null</code>. <li><code>service
+	 *         </code> is not a <code>ServiceFactory</code> object and is not an
+	 *         instance of all the named classes in <code>clazzes</code>. <li>
+	 *         <code>properties</code> contains case variants of the same key
+	 *         name.
 	 *         </ul>
-	 * 
-	 * @throws java.lang.SecurityException If the caller does not have the
+	 * @throws SecurityException If the caller does not have the
 	 *         <code>ServicePermission</code> to register the service for all
 	 *         the named classes and the Java Runtime Environment supports
 	 *         permissions.
-	 * 
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
-	 *         longer valid.
-	 * 
+	 * @throws IllegalStateException If this BundleContext is no longer valid.
 	 * @see ServiceRegistration
 	 * @see ServiceFactory
 	 */
@@ -485,161 +443,129 @@
 	 * 
 	 * <p>
 	 * This method is otherwise identical to
-	 * {@link #registerService(java.lang.String[], java.lang.Object,
-	 * java.util.Dictionary)} and is provided as a convenience when
-	 * <code>service</code> will only be registered under a single class name.
-	 * Note that even in this case the value of the service's
-	 * {@link Constants#OBJECTCLASS} property will be an array of strings,
-	 * rather than just a single string.
+	 * {@link #registerService(String[], Object, Dictionary)} and is provided as
+	 * a convenience when <code>service</code> will only be registered under a
+	 * single class name. Note that even in this case the value of the service's
+	 * {@link Constants#OBJECTCLASS} property will be an array of string, rather
+	 * than just a single string.
 	 * 
 	 * @param clazz The class name under which the service can be located.
 	 * @param service The service object or a <code>ServiceFactory</code>
 	 *        object.
-	 * @param properties The properties for this service. 
-	 * 
+	 * @param properties The properties for this service.
 	 * @return A <code>ServiceRegistration</code> object for use by the bundle
 	 *         registering the service to update the service's properties or to
 	 *         unregister the service.
-	 *         
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
-	 *         longer valid.
-	 * @see #registerService(java.lang.String[], java.lang.Object,
-	 *      java.util.Dictionary)
+	 * @throws IllegalStateException If this BundleContext is no longer valid.
+	 * @see #registerService(String[], Object, Dictionary)
 	 */
-	public ServiceRegistration registerService(String clazz,
-			Object service, Dictionary properties);
+	public ServiceRegistration registerService(String clazz, Object service,
+			Dictionary properties);
 
 	/**
 	 * Returns an array of <code>ServiceReference</code> objects. The returned
 	 * array of <code>ServiceReference</code> objects contains services that
 	 * were registered under the specified class, match the specified filter
-	 * criteria, and the packages for the class names under which the services
+	 * expression, and the packages for the class names under which the services
 	 * were registered match the context bundle's packages as defined in
 	 * {@link ServiceReference#isAssignableTo(Bundle, String)}.
 	 * 
 	 * <p>
-	 * The list is valid at the time of the call to this method, however since
+	 * The list is valid at the time of the call to this method. However since
 	 * the Framework is a very dynamic environment, services can be modified or
-	 * unregistered at anytime.
+	 * unregistered at any time.
 	 * 
 	 * <p>
-	 * <code>filter</code> is used to select the registered service whose
-	 * properties objects contain keys and values which satisfy the filter. See
-	 * {@link Filter} for a description of the filter string syntax.
+	 * The specified <code>filter</code> expression is used to select the
+	 * registered services whose service properties contain keys and values
+	 * which satisfy the filter expression. See {@link Filter} for a description
+	 * of the filter syntax. If the specified <code>filter</code> is
+	 * <code>null</code>, all registered services are considered to match the
+	 * filter. If the specified <code>filter</code> expression cannot be parsed,
+	 * an {@link InvalidSyntaxException} will be thrown with a human readable
+	 * message where the filter became unparsable.
 	 * 
 	 * <p>
-	 * If <code>filter</code> is <code>null</code>, all registered services
-	 * are considered to match the filter. If <code>filter</code> cannot be
-	 * parsed, an {@link InvalidSyntaxException} will be thrown with a human
-	 * readable message where the filter became unparsable.
-	 * 
-	 * <p>
-	 * The following steps are required to select a set of
-	 * <code>ServiceReference</code> objects:
-	 * <ol>
-	 * <li>If the filter string is not <code>null</code>, the filter string
-	 * is parsed and the set <code>ServiceReference</code> objects of
-	 * registered services that satisfy the filter is produced. If the filter
-	 * string is <code>null</code>, then all registered services are
-	 * considered to satisfy the filter.
-	 * <li>If the Java Runtime Environment supports permissions, the set of
-	 * <code>ServiceReference</code> objects produced by the previous step is
-	 * reduced by checking that the caller has the
-	 * <code>ServicePermission</code> to get at least one of the class names
-	 * under which the service was registered. If the caller does not have the
-	 * correct permission for a particular <code>ServiceReference</code>
-	 * object, then it is removed from the set.
-	 * <li>If <code>clazz</code> is not <code>null</code>, the set is
-	 * further reduced to those services that are an <code>instanceof</code>
-	 * and were registered under the specified class. The complete list of
-	 * classes of which a service is an instance and which were specified when
-	 * the service was registered is available from the service's
-	 * {@link Constants#OBJECTCLASS} property.
-	 * <li>The set is reduced one final time by cycling through each
-	 * <code>ServiceReference</code> object and calling
+	 * The result is an array of <code>ServiceReference</code> objects for all
+	 * services that meet all of the following conditions:
+	 * <ul>
+	 * <li>If the specified class name, <code>clazz</code>, is not
+	 * <code>null</code>, the service must have been registered with the
+	 * specified class name. The complete list of class names with which a
+	 * service was registered is available from the service's
+	 * {@link Constants#OBJECTCLASS objectClass} property.
+	 * <li>If the specified <code>filter</code> is not <code>null</code>, the
+	 * filter expression must match the service.
+	 * <li>If the Java Runtime Environment supports permissions, the caller must
+	 * have <code>ServicePermission</code> with the <code>GET</code> action for
+	 * at least one of the class names under which the service was registered.
+	 * <li>For each class name with which the service was registered, calling
 	 * {@link ServiceReference#isAssignableTo(Bundle, String)} with the context
-	 * bundle and each class name under which the <code>ServiceReference</code>
-	 * object was registered. For any given <code>ServiceReference</code>
-	 * object, if any call to
-	 * {@link ServiceReference#isAssignableTo(Bundle, String)} returns
-	 * <code>false</code>, then it is removed from the set of
-	 * <code>ServiceReference</code> objects.
-	 * <li>An array of the remaining <code>ServiceReference</code> objects is
-	 * returned.
-	 * </ol>
+	 * bundle and the class name on the service's <code>ServiceReference</code>
+	 * object must return <code>true</code>
+	 * </ul>
 	 * 
 	 * @param clazz The class name with which the service was registered or
 	 *        <code>null</code> for all services.
-	 * @param filter The filter criteria.
+	 * @param filter The filter expression or <code>null</code> for all
+	 *        services.
 	 * @return An array of <code>ServiceReference</code> objects or
-	 *         <code>null</code> if no services are registered which satisfy
-	 *         the search.
-	 * @throws InvalidSyntaxException If <code>filter</code> contains an
-	 *         invalid filter string that cannot be parsed.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
-	 *         longer valid.
+	 *         <code>null</code> if no services are registered which satisfy the
+	 *         search.
+	 * @throws InvalidSyntaxException If the specified <code>filter</code>
+	 *         contains an invalid filter expression that cannot be parsed.
+	 * @throws IllegalStateException If this BundleContext is no longer valid.
 	 */
-	public ServiceReference[] getServiceReferences(String clazz,
-			String filter) throws InvalidSyntaxException;
+	public ServiceReference[] getServiceReferences(String clazz, String filter)
+			throws InvalidSyntaxException;
 
 	/**
 	 * Returns an array of <code>ServiceReference</code> objects. The returned
 	 * array of <code>ServiceReference</code> objects contains services that
 	 * were registered under the specified class and match the specified filter
-	 * criteria.
+	 * expression.
 	 * 
 	 * <p>
-	 * The list is valid at the time of the call to this method, however since
+	 * The list is valid at the time of the call to this method. However since
 	 * the Framework is a very dynamic environment, services can be modified or
-	 * unregistered at anytime.
+	 * unregistered at any time.
 	 * 
 	 * <p>
-	 * <code>filter</code> is used to select the registered service whose
-	 * properties objects contain keys and values which satisfy the filter. See
-	 * {@link Filter} for a description of the filter string syntax.
+	 * The specified <code>filter</code> expression is used to select the
+	 * registered services whose service properties contain keys and values
+	 * which satisfy the filter expression. See {@link Filter} for a description
+	 * of the filter syntax. If the specified <code>filter</code> is
+	 * <code>null</code>, all registered services are considered to match the
+	 * filter. If the specified <code>filter</code> expression cannot be parsed,
+	 * an {@link InvalidSyntaxException} will be thrown with a human readable
+	 * message where the filter became unparsable.
 	 * 
 	 * <p>
-	 * If <code>filter</code> is <code>null</code>, all registered services
-	 * are considered to match the filter. If <code>filter</code> cannot be
-	 * parsed, an {@link InvalidSyntaxException} will be thrown with a human
-	 * readable message where the filter became unparsable.
-	 * 
-	 * <p>
-	 * The following steps are required to select a set of
-	 * <code>ServiceReference</code> objects:
-	 * <ol>
-	 * <li>If the filter string is not <code>null</code>, the filter string
-	 * is parsed and the set <code>ServiceReference</code> objects of
-	 * registered services that satisfy the filter is produced. If the filter
-	 * string is <code>null</code>, then all registered services are
-	 * considered to satisfy the filter.
-	 * <li>If the Java Runtime Environment supports permissions, the set of
-	 * <code>ServiceReference</code> objects produced by the previous step is
-	 * reduced by checking that the caller has the
-	 * <code>ServicePermission</code> to get at least one of the class names
-	 * under which the service was registered. If the caller does not have the
-	 * correct permission for a particular <code>ServiceReference</code>
-	 * object, then it is removed from the set.
-	 * <li>If <code>clazz</code> is not <code>null</code>, the set is
-	 * further reduced to those services that are an <code>instanceof</code>
-	 * and were registered under the specified class. The complete list of
-	 * classes of which a service is an instance and which were specified when
-	 * the service was registered is available from the service's
-	 * {@link Constants#OBJECTCLASS} property.
-	 * <li>An array of the remaining <code>ServiceReference</code> objects is
-	 * returned.
-	 * </ol>
+	 * The result is an array of <code>ServiceReference</code> objects for all
+	 * services that meet all of the following conditions:
+	 * <ul>
+	 * <li>If the specified class name, <code>clazz</code>, is not
+	 * <code>null</code>, the service must have been registered with the
+	 * specified class name. The complete list of class names with which a
+	 * service was registered is available from the service's
+	 * {@link Constants#OBJECTCLASS objectClass} property.
+	 * <li>If the specified <code>filter</code> is not <code>null</code>, the
+	 * filter expression must match the service.
+	 * <li>If the Java Runtime Environment supports permissions, the caller must
+	 * have <code>ServicePermission</code> with the <code>GET</code> action for
+	 * at least one of the class names under which the service was registered.
+	 * </ul>
 	 * 
 	 * @param clazz The class name with which the service was registered or
 	 *        <code>null</code> for all services.
-	 * @param filter The filter criteria.
+	 * @param filter The filter expression or <code>null</code> for all
+	 *        services.
 	 * @return An array of <code>ServiceReference</code> objects or
-	 *         <code>null</code> if no services are registered which satisfy
-	 *         the search.
-	 * @throws InvalidSyntaxException If <code>filter</code> contains an
-	 *         invalid filter string that cannot be parsed.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
-	 *         longer valid.
+	 *         <code>null</code> if no services are registered which satisfy the
+	 *         search.
+	 * @throws InvalidSyntaxException If the specified <code>filter</code>
+	 *         contains an invalid filter expression that cannot be parsed.
+	 * @throws IllegalStateException If this BundleContext is no longer valid.
 	 * @since 1.3
 	 */
 	public ServiceReference[] getAllServiceReferences(String clazz,
@@ -650,14 +576,14 @@
 	 * implements and was registered under the specified class.
 	 * 
 	 * <p>
-	 * This <code>ServiceReference</code> object is valid at the time of the
-	 * call to this method, however as the Framework is a very dynamic
-	 * environment, services can be modified or unregistered at anytime.
+	 * The returned <code>ServiceReference</code> object is valid at the time of
+	 * the call to this method. However as the Framework is a very dynamic
+	 * environment, services can be modified or unregistered at any time.
 	 * 
 	 * <p>
 	 * This method is the same as calling
 	 * {@link BundleContext#getServiceReferences(String, String)} with a
-	 * <code>null</code> filter string. It is provided as a convenience for
+	 * <code>null</code> filter expression. It is provided as a convenience for
 	 * when the caller is interested in any service that implements the
 	 * specified class.
 	 * <p>
@@ -669,16 +595,16 @@
 	 * service that was registered first is returned.
 	 * 
 	 * @param clazz The class name with which the service was registered.
-	 * @return A <code>ServiceReference</code> object, or <code>null</code>
-	 *         if no services are registered which implement the named class.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
-	 *         longer valid.
+	 * @return A <code>ServiceReference</code> object, or <code>null</code> if
+	 *         no services are registered which implement the named class.
+	 * @throws IllegalStateException If this BundleContext is no longer valid.
 	 * @see #getServiceReferences(String, String)
 	 */
 	public ServiceReference getServiceReference(String clazz);
 
 	/**
-	 * Returns the specified service object for a service.
+	 * Returns the service object referenced by the specified
+	 * <code>ServiceReference</code> object.
 	 * <p>
 	 * A bundle's use of a service is tracked by the bundle's use count of that
 	 * service. Each time a service's service object is returned by
@@ -697,8 +623,7 @@
 	 * <p>
 	 * The following steps are required to get the service object:
 	 * <ol>
-	 * <li>If the service has been unregistered, <code>null</code> is
-	 * returned.
+	 * <li>If the service has been unregistered, <code>null</code> is returned.
 	 * <li>The context bundle's use count for this service is incremented by
 	 * one.
 	 * <li>If the context bundle's use count for the service is currently one
@@ -710,25 +635,31 @@
 	 * for the service is greater than zero, subsequent calls to get the
 	 * services's service object for the context bundle will return the cached
 	 * service object. <br>
-	 * If the service object returned by the <code>ServiceFactory</code>
-	 * object is not an <code>instanceof</code> all the classes named when the
-	 * service was registered or the <code>ServiceFactory</code> object throws
-	 * an exception, <code>null</code> is returned and a Framework event of
-	 * type {@link FrameworkEvent#ERROR} is fired.
+	 * If the service object returned by the <code>ServiceFactory</code> object
+	 * is not an <code>instanceof</code> all the classes named when the service
+	 * was registered or the <code>ServiceFactory</code> object throws an
+	 * exception, <code>null</code> is returned and a Framework event of type
+	 * {@link FrameworkEvent#ERROR} containing a {@link ServiceException}
+	 * describing the error is fired.
 	 * <li>The service object for the service is returned.
 	 * </ol>
 	 * 
 	 * @param reference A reference to the service.
 	 * @return A service object for the service associated with
-	 *         <code>reference</code> or <code>null</code> if the service is
-	 *         not registered or does not implement the classes under which it
-	 *         was registered in the case of a <code>ServiceFactory</code>.
-	 * @throws java.lang.SecurityException If the caller does not have the
-	 *         <code>ServicePermission</code> to get the service using at
-	 *         least one of the named classes the service was registered under
-	 *         and the Java Runtime Environment supports permissions.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
+	 *         <code>reference</code> or <code>null</code> if the service is not
+	 *         registered, the service object returned by a
+	 *         <code>ServiceFactory</code> does not implement the classes under
+	 *         which it was registered or the <code>ServiceFactory</code> threw
+	 *         an exception.
+	 * @throws SecurityException If the caller does not have the
+	 *         <code>ServicePermission</code> to get the service using at least
+	 *         one of the named classes the service was registered under and the
+	 *         Java Runtime Environment supports permissions.
+	 * @throws IllegalStateException If this BundleContext is no
 	 *         longer valid.
+	 * @throws IllegalArgumentException If the specified
+	 *         <code>ServiceReference</code> was not created by the same
+	 *         framework instance as this <code>BundleContext</code>.
 	 * @see #ungetService(ServiceReference)
 	 * @see ServiceFactory
 	 */
@@ -754,8 +685,8 @@
 	 * <li>The context bundle's use count for this service is decremented by
 	 * one.
 	 * <li>If the context bundle's use count for the service is currently zero
-	 * and the service was registered with a <code>ServiceFactory</code>
-	 * object, the
+	 * and the service was registered with a <code>ServiceFactory</code> object,
+	 * the
 	 * {@link ServiceFactory#ungetService(Bundle, ServiceRegistration, Object)}
 	 * method is called to release the service object for the context bundle.
 	 * <li><code>true</code> is returned.
@@ -765,8 +696,11 @@
 	 * @return <code>false</code> if the context bundle's use count for the
 	 *         service is zero or if the service has been unregistered;
 	 *         <code>true</code> otherwise.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
+	 * @throws IllegalStateException If this BundleContext is no
 	 *         longer valid.
+	 * @throws IllegalArgumentException If the specified
+	 *         <code>ServiceReference</code> was not created by the same
+	 *         framework instance as this <code>BundleContext</code>.
 	 * @see #getService
 	 * @see ServiceFactory
 	 */
@@ -794,14 +728,14 @@
 	 * @return A <code>File</code> object that represents the requested file
 	 *         or <code>null</code> if the platform does not have file system
 	 *         support.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
+	 * @throws IllegalStateException If this BundleContext is no
 	 *         longer valid.
 	 */
 	public File getDataFile(String filename);
 
 	/**
-	 * Creates a <code>Filter</code> object. This <code>Filter</code> object
-	 * may be used to match a <code>ServiceReference</code> object or a
+	 * Creates a <code>Filter</code> object. This <code>Filter</code> object may
+	 * be used to match a <code>ServiceReference</code> object or a
 	 * <code>Dictionary</code> object.
 	 * 
 	 * <p>
@@ -810,16 +744,13 @@
 	 * 
 	 * @param filter The filter string.
 	 * @return A <code>Filter</code> object encapsulating the filter string.
-	 * @throws InvalidSyntaxException If <code>filter</code> contains an
-	 *         invalid filter string that cannot be parsed.
+	 * @throws InvalidSyntaxException If <code>filter</code> contains an invalid
+	 *         filter string that cannot be parsed.
 	 * @throws NullPointerException If <code>filter</code> is null.
-	 * @throws java.lang.IllegalStateException If this BundleContext is no
-	 *         longer valid.
-	 * 
-	 * @since 1.1
+	 * @throws IllegalStateException If this BundleContext is no longer valid.
 	 * @see "Framework specification for a description of the filter string syntax."
 	 * @see FrameworkUtil#createFilter(String)
+	 * @since 1.1
 	 */
-	public Filter createFilter(String filter)
-			throws InvalidSyntaxException;
+	public Filter createFilter(String filter) throws InvalidSyntaxException;
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleEvent.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleEvent.java
index 29f6fa0..7a8fb8d 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundleEvent.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleEvent.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundleEvent.java,v 1.19 2007/02/20 00:14:12 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -34,7 +32,7 @@
  * @Immutable
  * @see BundleListener
  * @see SynchronousBundleListener
- * @version $Revision: 1.19 $
+ * @version $Revision: 6542 $
  */
 
 public class BundleEvent extends EventObject {
@@ -51,8 +49,6 @@
 
 	/**
 	 * The bundle has been installed.
-	 * <p>
-	 * The value of <code>INSTALLED</code> is 0x00000001.
 	 * 
 	 * @see BundleContext#installBundle(String)
 	 */
@@ -64,8 +60,6 @@
 	 * The bundle's
 	 * {@link BundleActivator#start(BundleContext) BundleActivator start} method
 	 * has been executed if the bundle has a bundle activator class.
-	 * <p>
-	 * The value of <code>STARTED</code> is 0x00000002.
 	 * 
 	 * @see Bundle#start()
 	 */
@@ -77,8 +71,6 @@
 	 * The bundle's
 	 * {@link BundleActivator#stop(BundleContext) BundleActivator stop} method
 	 * has been executed if the bundle has a bundle activator class.
-	 * <p>
-	 * The value of <code>STOPPED</code> is 0x00000004.
 	 * 
 	 * @see Bundle#stop()
 	 */
@@ -86,8 +78,6 @@
 
 	/**
 	 * The bundle has been updated.
-	 * <p>
-	 * The value of <code>UPDATED</code> is 0x00000008.
 	 * 
 	 * @see Bundle#update()
 	 */
@@ -95,8 +85,6 @@
 
 	/**
 	 * The bundle has been uninstalled.
-	 * <p>
-	 * The value of <code>UNINSTALLED</code> is 0x00000010.
 	 * 
 	 * @see Bundle#uninstall
 	 */
@@ -104,8 +92,6 @@
 
 	/**
 	 * The bundle has been resolved.
-	 * <p>
-	 * The value of <code>RESOLVED</code> is 0x00000020.
 	 * 
 	 * @see Bundle#RESOLVED
 	 * @since 1.3
@@ -114,8 +100,6 @@
 
 	/**
 	 * The bundle has been unresolved.
-	 * <p>
-	 * The value of <code>UNRESOLVED</code> is 0x00000040.
 	 * 
 	 * @see Bundle#INSTALLED
 	 * @since 1.3
@@ -130,8 +114,6 @@
 	 * is about to be called if the bundle has a bundle activator class. This
 	 * event is only delivered to {@link SynchronousBundleListener}s. It is not
 	 * delivered to <code>BundleListener</code>s.
-	 * <p>
-	 * The value of <code>STARTING</code> is 0x00000080.
 	 * 
 	 * @see Bundle#start()
 	 * @since 1.3
@@ -146,8 +128,6 @@
 	 * is about to be called if the bundle has a bundle activator class. This
 	 * event is only delivered to {@link SynchronousBundleListener}s. It is not
 	 * delivered to <code>BundleListener</code>s.
-	 * <p>
-	 * The value of <code>STOPPING</code> is 0x00000100.
 	 * 
 	 * @see Bundle#stop()
 	 * @since 1.3
@@ -163,8 +143,6 @@
 	 * <code>BundleContext</code>. This event is only delivered to
 	 * {@link SynchronousBundleListener}s. It is not delivered to
 	 * <code>BundleListener</code>s.
-	 * <p>
-	 * The value of <code>LAZY_ACTIVATION</code> is 0x00000200.
 	 * 
 	 * @since 1.4
 	 */
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleException.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleException.java
index 2203e0f..500d147 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundleException.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleException.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundleException.java,v 1.15 2006/07/11 13:15:54 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). 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.
@@ -23,84 +21,198 @@
  * occurred.
  * 
  * <p>
- * <code>BundleException</code> object is created by the Framework to denote
+ * A <code>BundleException</code> object is created by the Framework to denote
  * an exception condition in the lifecycle of a bundle.
  * <code>BundleException</code>s should not be created by bundle developers.
+ * A type code is used to identify the exception type for future extendability.
  * 
  * <p>
- * This exception is updated to conform to the general purpose exception
- * chaining mechanism.
+ * OSGi Alliance reserves the right to extend the set of types.
  * 
- * @version $Revision: 1.15 $
+ * <p>
+ * This exception conforms to the general purpose exception chaining mechanism.
+ * 
+ * @version $Revision: 6083 $
  */
 
 public class BundleException extends Exception {
-	static final long	serialVersionUID	= 3571095144220455665L;
+	static final long		serialVersionUID		= 3571095144220455665L;
 	/**
-	 * Nested exception.
+	 * Type of bundle exception.
+	 * 
+	 * @since 1.5
 	 */
-	private final Throwable	cause;
+	private final int		type;
 
 	/**
-	 * Creates a <code>BundleException</code> that wraps another exception.
+	 * No exception type is unspecified.
+	 * 
+	 * @since 1.5
+	 */
+	public static final int	UNSPECIFIED				= 0;
+	/**
+	 * The operation was unsupported.
+	 * 
+	 * @since 1.5
+	 */
+	public static final int	UNSUPPORTED_OPERATION	= 1;
+	/**
+	 * The operation was invalid.
+	 * 
+	 * @since 1.5
+	 */
+	public static final int	INVALID_OPERATION		= 2;
+	/**
+	 * The bundle manifest was in error.
+	 * 
+	 * @since 1.5
+	 */
+	public static final int	MANIFEST_ERROR			= 3;
+	/**
+	 * The bundle was not resolved.
+	 * 
+	 * @since 1.5
+	 */
+	public static final int	RESOLVE_ERROR			= 4;
+	/**
+	 * The bundle activator was in error.
+	 * 
+	 * @since 1.5
+	 */
+	public static final int	ACTIVATOR_ERROR			= 5;
+	/**
+	 * The operation failed due to insufficient permissions.
+	 * 
+	 * @since 1.5
+	 */
+	public static final int	SECURITY_ERROR			= 6;
+	/**
+	 * The operation failed to complete the requested lifecycle state change.
+	 * 
+	 * @since 1.5
+	 */
+	public static final int	STATECHANGE_ERROR		= 7;
+
+	/**
+	 * The bundle could not be resolved due to an error with the
+	 * Bundle-NativeCode header.
+	 * 
+	 * @since 1.5
+	 */
+	public static final int	NATIVECODE_ERROR		= 8;
+
+	/**
+	 * The install or update operation failed because another 
+	 * already installed bundle has the same symbolic name and version.
+	 * @since 1.5
+	 */
+	public static final int	DUPLICATE_BUNDLE_ERROR	= 9;
+	
+    /**
+	 * The start transient operation failed because the start level of the
+	 * bundle is greater than the current framework start level
+	 * 
+	 * @since 1.5
+	 */
+	public static final int	START_TRANSIENT_ERROR	= 10;
+
+	/**
+	 * Creates a <code>BundleException</code> with the specified message and
+	 * exception cause.
 	 * 
 	 * @param msg The associated message.
 	 * @param cause The cause of this exception.
 	 */
 	public BundleException(String msg, Throwable cause) {
-		super(msg);
-		this.cause = cause;
+		this(msg, UNSPECIFIED, cause);
 	}
 
 	/**
-	 * Creates a <code>BundleException</code> object with the specified
-	 * message.
+	 * Creates a <code>BundleException</code> with the specified message.
 	 * 
 	 * @param msg The message.
 	 */
 	public BundleException(String msg) {
-		super(msg);
-		this.cause = null;
+		this(msg, UNSPECIFIED);
 	}
 
 	/**
-	 * Returns any nested exceptions included in this exception.
+	 * Creates a <code>BundleException</code> with the specified message, type
+	 * and exception cause.
+	 * 
+	 * @param msg The associated message.
+	 * @param type The type for this exception.
+	 * @param cause The cause of this exception.
+	 * @since 1.5
+	 */
+	public BundleException(String msg, int type, Throwable cause) {
+		super(msg, cause);
+		this.type = type;
+	}
+
+	/**
+	 * Creates a <code>BundleException</code> with the specified message and
+	 * type.
+	 * 
+	 * @param msg The message.
+	 * @param type The type for this exception.
+	 * @since 1.5
+	 */
+	public BundleException(String msg, int type) {
+		super(msg);
+		this.type = type;
+	}
+
+	/**
+	 * Returns the cause of this exception or <code>null</code> if no cause was
+	 * specified when this exception was created.
 	 * 
 	 * <p>
 	 * This method predates the general purpose exception chaining mechanism.
-	 * The {@link #getCause()} method is now the preferred means of obtaining
-	 * this information.
+	 * The <code>getCause()</code> method is now the preferred means of
+	 * obtaining this information.
 	 * 
-	 * @return The nested exception; <code>null</code> if there is no nested
-	 *         exception.
+	 * @return The result of calling <code>getCause()</code>.
 	 */
 	public Throwable getNestedException() {
-		return cause;
+		return getCause();
 	}
 
 	/**
-	 * Returns the cause of this exception or <code>null</code> if no cause
-	 * was specified when this exception was created.
+	 * Returns the cause of this exception or <code>null</code> if no cause was
+	 * set.
 	 * 
-	 * @return The cause of this exception or <code>null</code> if no cause
-	 *         was specified.
+	 * @return The cause of this exception or <code>null</code> if no cause was
+	 *         set.
 	 * @since 1.3
 	 */
-	public Throwable getCause() {
-		return cause;
+    public Throwable getCause() {
+		return super.getCause();
 	}
 
 	/**
-	 * The cause of this exception can only be set when constructed.
+	 * Initializes the cause of this exception to the specified value.
 	 * 
-	 * @param cause Cause of the exception.
-	 * @return This object.
-	 * @throws java.lang.IllegalStateException This method will always throw an
-	 *         <code>IllegalStateException</code> since the cause of this
-	 *         exception can only be set when constructed.
+	 * @param cause The cause of this exception.
+	 * @return This exception.
+	 * @throws IllegalArgumentException If the specified cause is this
+	 *         exception.
+	 * @throws IllegalStateException If the cause of this exception has already
+	 *         been set.
 	 * @since 1.3
 	 */
 	public Throwable initCause(Throwable cause) {
-		throw new IllegalStateException();
+		return super.initCause(cause);
+	}
+
+	/**
+	 * Returns the type for this exception or <code>UNSPECIFIED</code> if the
+	 * type was unspecified or unknown.
+	 * 
+	 * @return The type of this exception.
+	 * @since 1.5
+	 */
+	public int getType() {
+		return type;
 	}
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleListener.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleListener.java
index e9bc6d4..9dd7151 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundleListener.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleListener.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundleListener.java,v 1.13 2007/02/21 16:49:05 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). 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.
@@ -36,7 +34,7 @@
  * 
  * @see BundleEvent
  * @NotThreadSafe
- * @version $Revision: 1.13 $
+ * @version $Revision: 5673 $
  */
 
 public interface BundleListener extends EventListener {
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundlePermission.java b/org.osgi.core/src/main/java/org/osgi/framework/BundlePermission.java
index c313bf7..8677e69 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundlePermission.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundlePermission.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundlePermission.java,v 1.16 2007/02/20 00:06:02 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). 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.
@@ -19,32 +17,46 @@
 package org.osgi.framework;
 
 import java.io.IOException;
-import java.security.*;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Map;
 
 /**
  * A bundle's authority to require or provide a bundle or to receive or attach
  * fragments.
  * 
  * <p>
- * A bundle symbolic name defines a unique fully qualified name.
- * <p>
- * For example:
+ * A bundle symbolic name defines a unique fully qualified name. Wildcards may
+ * be used.
  * 
  * <pre>
- * <code>
+ * name ::= &lt;symbolic name&gt; | &lt;symbolic name ending in &quot;.*&quot;&gt; | *
+ * </pre>
+ * 
+ * Examples:
+ * 
+ * <pre>
  * org.osgi.example.bundle
- * </code>
+ * org.osgi.example.*
+ * *
  * </pre>
  * 
  * <p>
- * <code>BundlePermission</code> has four actions: <code>PROVIDE</code>,
- * <code>REQUIRE</code>,<code>HOST</code>, and <code>FRAGMENT</code>.
- * The <code>PROVIDE</code> action implies the <code>REQUIRE</code> action.
+ * <code>BundlePermission</code> has four actions: <code>provide</code>,
+ * <code>require</code>,<code>host</code>, and <code>fragment</code>. The
+ * <code>provide</code> action implies the <code>require</code> action.
  * 
  * @since 1.3
- * @version $Revision: 1.16 $
+ * @ThreadSafe
+ * @version $Revision: 6860 $
  */
 
 public final class BundlePermission extends BasicPermission {
@@ -52,12 +64,14 @@
 	private static final long	serialVersionUID	= 3257846601685873716L;
 
 	/**
-	 * The action string <code>provide</code>.
+	 * The action string <code>provide</code>. The <code>provide</code> action
+	 * implies the <code>require</code> action.
 	 */
 	public final static String	PROVIDE				= "provide";
 
 	/**
-	 * The action string <code>require</code>.
+	 * The action string <code>require</code>. The <code>require</code> action
+	 * is implied by the <code>provide</code> action.
 	 */
 	public final static String	REQUIRE				= "require";
 
@@ -79,18 +93,18 @@
 															| ACTION_REQUIRE
 															| ACTION_HOST
 															| ACTION_FRAGMENT;
-	private final static int	ACTION_NONE			= 0;
+	final static int			ACTION_NONE			= 0;
 	/**
 	 * The actions mask.
 	 */
-	private transient int		action_mask			= ACTION_NONE;
+	private transient int		action_mask;
 
 	/**
 	 * The actions in canonical form.
 	 * 
 	 * @serial
 	 */
-	private String				actions				= null;
+	private volatile String		actions				= null;
 
 	/**
 	 * Defines the authority to provide and/or require and or specify a host
@@ -104,24 +118,23 @@
 	 * for that symbolic name; a bundle that specifies a fragment host must have
 	 * the appropriate <code>BundlePermission</code> for that symbolic name.
 	 * 
-	 * @param symbolicName the bundle symbolic name.
-	 * @param actions <code>PROVIDE</code>,<code>REQUIRE</code>,
-	 *        <code>HOST</code>,<code>FRAGMENT</code> (canonical order).
+	 * @param symbolicName The bundle symbolic name.
+	 * @param actions <code>provide</code>,<code>require</code>,
+	 *        <code>host</code>,<code>fragment</code> (canonical order).
 	 */
-
 	public BundlePermission(String symbolicName, String actions) {
-		this(symbolicName, getMask(actions));
+		this(symbolicName, parseActions(actions));
 	}
 
 	/**
-	 * Bundle private constructor used by BundlePermissionCollection.
+	 * Package private constructor used by BundlePermissionCollection.
 	 * 
 	 * @param symbolicName the bundle symbolic name
 	 * @param mask the action mask
 	 */
 	BundlePermission(String symbolicName, int mask) {
 		super(symbolicName);
-		init(mask);
+		setTransients(mask);
 	}
 
 	/**
@@ -129,7 +142,7 @@
 	 * 
 	 * @param mask
 	 */
-	private void init(int mask) {
+	private synchronized void setTransients(int mask) {
 		if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
 			throw new IllegalArgumentException("invalid action string");
 		}
@@ -138,25 +151,36 @@
 	}
 
 	/**
+	 * Returns the current action mask.
+	 * <p>
+	 * Used by the BundlePermissionCollection class.
+	 * 
+	 * @return Current action mask.
+	 */
+	synchronized int getActionsMask() {
+		return action_mask;
+	}
+
+	/**
 	 * Parse action string into action mask.
 	 * 
 	 * @param actions Action string.
 	 * @return action mask.
 	 */
-	private static int getMask(String actions) {
+	private static int parseActions(String actions) {
 		boolean seencomma = false;
 
 		int mask = ACTION_NONE;
 
 		if (actions == null) {
-			return (mask);
+			return mask;
 		}
 
 		char[] a = actions.toCharArray();
 
 		int i = a.length - 1;
 		if (i < 0)
-			return (mask);
+			return mask;
 
 		while (i != -1) {
 			char c;
@@ -224,7 +248,7 @@
 				switch (a[i - matchlen]) {
 					case ',' :
 						seencomma = true;
-					/* FALLTHROUGH */
+						/* FALLTHROUGH */
 					case ' ' :
 					case '\r' :
 					case '\n' :
@@ -246,7 +270,7 @@
 			throw new IllegalArgumentException("invalid permission: " + actions);
 		}
 
-		return (mask);
+		return mask;
 	}
 
 	/**
@@ -268,21 +292,20 @@
 	 *       x.y,&quot;provide&quot; -&gt; x.y.z, &quot;provide&quot;  is false
 	 * </pre>
 	 * 
-	 * @param p The target permission to interrogate.
-	 * @return <code>true</code> if the specified
-	 *         <code>BundlePermission</code> action is implied by this object;
-	 *         <code>false</code> otherwise.
+	 * @param p The requested permission.
+	 * @return <code>true</code> if the specified <code>BundlePermission</code>
+	 *         action is implied by this object; <code>false</code> otherwise.
 	 */
-
 	public boolean implies(Permission p) {
-		if (p instanceof BundlePermission) {
-			BundlePermission target = (BundlePermission) p;
-
-			return (((action_mask & target.action_mask) == target.action_mask) && super
-					.implies(p));
+		if (!(p instanceof BundlePermission)) {
+			return false;
 		}
+		BundlePermission requested = (BundlePermission) p;
 
-		return (false);
+		final int effective = getActionsMask();
+		final int desired = requested.getActionsMask();
+		return ((effective & desired) == desired)
+				&& super.implies(requested);
 	}
 
 	/**
@@ -291,13 +314,15 @@
 	 * 
 	 * <p>
 	 * Always returns present <code>BundlePermission</code> actions in the
-	 * following order: <code>PROVIDE</code>,<code>REQUIRE</code>,
-	 * <code>HOST</code>,<code>FRAGMENT.
-	 * @return Canonical string representation of the <code>BundlePermission</code> actions.
+	 * following order: <code>provide</code>, <code>require</code>,
+	 * <code>host</code>, <code>fragment</code>.
+	 * 
+	 * @return Canonical string representation of the <code>BundlePermission
+	 *         </code> actions.
 	 */
-
 	public String getActions() {
-		if (actions == null) {
+		String result = actions;
+		if (result == null) {
 			StringBuffer sb = new StringBuffer();
 			boolean comma = false;
 
@@ -326,10 +351,9 @@
 				sb.append(FRAGMENT);
 			}
 
-			actions = sb.toString();
+			actions = result = sb.toString();
 		}
-
-		return (actions);
+		return result;
 	}
 
 	/**
@@ -339,7 +363,7 @@
 	 * @return A new <code>PermissionCollection</code> object.
 	 */
 	public PermissionCollection newPermissionCollection() {
-		return (new BundlePermissionCollection());
+		return new BundlePermissionCollection();
 	}
 
 	/**
@@ -352,22 +376,23 @@
 	 * @param obj The object to test for equality with this
 	 *        <code>BundlePermission</code> object.
 	 * @return <code>true</code> if <code>obj</code> is a
-	 *         <code>BundlePermission</code>, and has the same bundle
-	 *         symbolic name and actions as this <code>BundlePermission</code>
-	 *         object; <code>false</code> otherwise.
+	 *         <code>BundlePermission</code>, and has the same bundle symbolic
+	 *         name and actions as this <code>BundlePermission</code> object;
+	 *         <code>false</code> otherwise.
 	 */
 	public boolean equals(Object obj) {
 		if (obj == this) {
-			return (true);
+			return true;
 		}
 
 		if (!(obj instanceof BundlePermission)) {
-			return (false);
+			return false;
 		}
 
-		BundlePermission p = (BundlePermission) obj;
+		BundlePermission bp = (BundlePermission) obj;
 
-		return ((action_mask == p.action_mask) && getName().equals(p.getName()));
+		return (getActionsMask() == bp.getActionsMask())
+				&& getName().equals(bp.getName());
 	}
 
 	/**
@@ -375,20 +400,10 @@
 	 * 
 	 * @return A hash code value for this object.
 	 */
-
 	public int hashCode() {
-		return (getName().hashCode() ^ getActions().hashCode());
-	}
-
-	/**
-	 * Returns the current action mask.
-	 * <p>
-	 * Used by the BundlePermissionCollection class.
-	 * 
-	 * @return Current action mask.
-	 */
-	int getMask() {
-		return (action_mask);
+		int h = 31 * 17 + getName().hashCode();
+		h = 31 * h + getActions().hashCode();
+		return h;
 	}
 
 	/**
@@ -396,7 +411,6 @@
 	 * <code>BundlePermission</code> object to a stream. The actions are
 	 * serialized, and the superclass takes care of the name.
 	 */
-
 	private synchronized void writeObject(java.io.ObjectOutputStream s)
 			throws IOException {
 		// Write out the actions. The superclass takes care of the name
@@ -414,7 +428,7 @@
 			throws IOException, ClassNotFoundException {
 		// Read in the action, then initialize the rest
 		s.defaultReadObject();
-		init(getMask(actions));
+		setTransients(parseActions(actions));
 	}
 }
 
@@ -427,23 +441,20 @@
  */
 
 final class BundlePermissionCollection extends PermissionCollection {
-
-	/**
-	 * Comment for <code>serialVersionUID</code>
-	 */
 	private static final long	serialVersionUID	= 3258407326846433079L;
 
 	/**
 	 * Table of permissions.
 	 * 
-	 * @serial
+	 * @GuardedBy this
 	 */
-	private Hashtable			permissions;
+	private transient Map		permissions;
 
 	/**
 	 * Boolean saying if "*" is in the collection.
 	 * 
 	 * @serial
+	 * @GuardedBy this
 	 */
 	private boolean				all_allowed;
 
@@ -451,53 +462,51 @@
 	 * Create an empty BundlePermissions object.
 	 * 
 	 */
-
 	public BundlePermissionCollection() {
-		permissions = new Hashtable();
+		permissions = new HashMap();
 		all_allowed = false;
 	}
 
 	/**
-	 * Adds a permission to the <code>BundlePermission</code> objects. The key
-	 * for the hash is the symbolic name.
+	 * Add a permission to this permission collection.
 	 * 
 	 * @param permission The <code>BundlePermission</code> object to add.
-	 * 
 	 * @throws IllegalArgumentException If the permission is not a
 	 *         <code>BundlePermission</code> instance.
 	 * @throws SecurityException If this <code>BundlePermissionCollection</code>
 	 *         object has been marked read-only.
 	 */
-
-	public void add(Permission permission) {
-		if (!(permission instanceof BundlePermission))
+	public void add(final Permission permission) {
+		if (!(permission instanceof BundlePermission)) {
 			throw new IllegalArgumentException("invalid permission: "
 					+ permission);
-		if (isReadOnly())
+		}
+		if (isReadOnly()) {
 			throw new SecurityException("attempt to add a Permission to a "
 					+ "readonly PermissionCollection");
+		}
+		final BundlePermission bp = (BundlePermission) permission;
+		final String name = bp.getName();
+		synchronized (this) {
+			Map pc = permissions;
+			BundlePermission existing = (BundlePermission) pc.get(name);
+			if (existing != null) {
+				final int oldMask = existing.getActionsMask();
+				final int newMask = bp.getActionsMask();
+				if (oldMask != newMask) {
+					pc.put(name, new BundlePermission(name, oldMask
+							| newMask));
 
-		BundlePermission bp = (BundlePermission) permission;
-		String name = bp.getName();
-
-		BundlePermission existing = (BundlePermission) permissions.get(name);
-
-		if (existing != null) {
-			int oldMask = existing.getMask();
-			int newMask = bp.getMask();
-			if (oldMask != newMask) {
-				permissions.put(name, new BundlePermission(name, oldMask
-						| newMask));
-
+				}
 			}
-		}
-		else {
-			permissions.put(name, permission);
-		}
+			else {
+				pc.put(name, bp);
+			}
 
-		if (!all_allowed) {
-			if (name.equals("*"))
-				all_allowed = true;
+			if (!all_allowed) {
+				if (name.equals("*"))
+					all_allowed = true;
+			}
 		}
 	}
 
@@ -507,68 +516,60 @@
 	 * 
 	 * @param permission The Permission object to compare with this
 	 *        <code>BundlePermission</code> object.
-	 * 
-	 * @return <code>true</code> if <code>permission</code> is a proper
-	 *         subset of a permission in the set; <code>false</code>
-	 *         otherwise.
+	 * @return <code>true</code> if <code>permission</code> is a proper subset
+	 *         of a permission in the set; <code>false</code> otherwise.
 	 */
+	public boolean implies(final Permission permission) {
+		if (!(permission instanceof BundlePermission)) {
+			return false;
+		}
+		BundlePermission requested = (BundlePermission) permission;
+		String requestedName = requested.getName();
+		final int desired = requested.getActionsMask();
+		int effective = BundlePermission.ACTION_NONE;
+		BundlePermission bp;
 
-	public boolean implies(Permission permission) {
-		if (!(permission instanceof BundlePermission))
-			return (false);
-
-		BundlePermission bp = (BundlePermission) permission;
-		BundlePermission x;
-
-		int desired = bp.getMask();
-		int effective = 0;
-
-		// short circuit if the "*" Permission was added
-		if (all_allowed) {
-			x = (BundlePermission) permissions.get("*");
-			if (x != null) {
-				effective |= x.getMask();
-				if ((effective & desired) == desired)
-					return (true);
+		synchronized (this) {
+			Map pc = permissions;
+			/* short circuit if the "*" Permission was added */
+			if (all_allowed) {
+				bp = (BundlePermission) pc.get("*");
+				if (bp != null) {
+					effective |= bp.getActionsMask();
+					if ((effective & desired) == desired) {
+						return true;
+					}
+				}
 			}
-		}
-
-		// strategy:
-		// Check for full match first. Then work our way up the
-		// name looking for matches on a.b.*
-
-		String name = bp.getName();
-
-		x = (BundlePermission) permissions.get(name);
-
-		if (x != null) {
-			// we have a direct hit!
-			effective |= x.getMask();
-			if ((effective & desired) == desired)
-				return (true);
-		}
-
-		// work our way up the tree...
-		int last, offset;
-
-		offset = name.length() - 1;
-
-		while ((last = name.lastIndexOf(".", offset)) != -1) {
-
-			name = name.substring(0, last + 1) + "*";
-			x = (BundlePermission) permissions.get(name);
-
-			if (x != null) {
-				effective |= x.getMask();
-				if ((effective & desired) == desired)
-					return (true);
+			bp = (BundlePermission) pc.get(requestedName);
+			// strategy:
+			// Check for full match first. Then work our way up the
+			// name looking for matches on a.b.*
+			if (bp != null) {
+				// we have a direct hit!
+				effective |= bp.getActionsMask();
+				if ((effective & desired) == desired) {
+					return true;
+				}
 			}
-			offset = last - 1;
+			// work our way up the tree...
+			int last;
+			int offset = requestedName.length() - 1;
+			while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+				requestedName = requestedName.substring(0, last + 1) + "*";
+				bp = (BundlePermission) pc.get(requestedName);
+				if (bp != null) {
+					effective |= bp.getActionsMask();
+					if ((effective & desired) == desired) {
+						return true;
+					}
+				}
+				offset = last - 1;
+			}
+			// we don't have to check for "*" as it was already checked
+			// at the top (all_allowed), so we just return false
+			return false;
 		}
-
-		// we don't have to check for "*" as it was already checked
-		// at the top (all_allowed), so we just return false
-		return (false);
 	}
 
 	/**
@@ -577,8 +578,29 @@
 	 * 
 	 * @return Enumeration of all <code>BundlePermission</code> objects.
 	 */
+	public synchronized Enumeration elements() {
+		return Collections.enumeration(permissions.values());
+	}
+	
+	/* serialization logic */
+	private static final ObjectStreamField[]	serialPersistentFields	= {
+			new ObjectStreamField("permissions", Hashtable.class),
+			new ObjectStreamField("all_allowed", Boolean.TYPE)			};
 
-	public Enumeration elements() {
-		return (permissions.elements());
+	private synchronized void writeObject(ObjectOutputStream out)
+			throws IOException {
+		Hashtable hashtable = new Hashtable(permissions);
+		ObjectOutputStream.PutField pfields = out.putFields();
+		pfields.put("permissions", hashtable);
+		pfields.put("all_allowed", all_allowed);
+		out.writeFields();
+	}
+
+	private synchronized void readObject(java.io.ObjectInputStream in)
+			throws IOException, ClassNotFoundException {
+		ObjectInputStream.GetField gfields = in.readFields();
+		Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+		permissions = new HashMap(hashtable);
+		all_allowed = gfields.get("all_allowed", false);
 	}
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleReference.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleReference.java
new file mode 100644
index 0000000..f9c4183
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleReference.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). 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.framework;
+
+/**
+ * A reference to a Bundle.
+ * 
+ * @since 1.5
+ * @ThreadSafe
+ * @version $Revision: 6860 $
+ */
+public interface BundleReference {
+	/**
+	 * Returns the <code>Bundle</code> object associated with this
+	 * <code>BundleReference</code>.
+	 * 
+	 * @return The <code>Bundle</code> object associated with this
+	 *         <code>BundleReference</code>.
+	 */
+	public Bundle getBundle();
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/Configurable.java b/org.osgi.core/src/main/java/org/osgi/framework/Configurable.java
index cd40557..b30910c 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/Configurable.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/Configurable.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/Configurable.java,v 1.12 2007/02/20 00:07:22 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -28,7 +26,7 @@
  * <code>instanceof Configurable</code>.
  * 
  * @deprecated As of 1.2. Please use Configuration Admin service.
- * @version $Revision: 1.12 $
+ * @version $Revision: 6361 $
  */
 public interface Configurable {
 	/**
@@ -44,7 +42,7 @@
 	 * returning the configuration object.
 	 * 
 	 * @return The configuration object for this service.
-	 * @throws java.lang.SecurityException If the caller does not have an
+	 * @throws SecurityException If the caller does not have an
 	 *         appropriate permission and the Java Runtime Environment supports
 	 *         permissions.
 	 * @deprecated As of 1.2. Please use Configuration Admin service.
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/Constants.java b/org.osgi.core/src/main/java/org/osgi/framework/Constants.java
index 0ee3a33..16a10d8 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/Constants.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/Constants.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/Constants.java,v 1.32 2007/02/20 00:07:22 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -24,10 +22,10 @@
  * 
  * <p>
  * The values associated with these keys are of type
- * <code>java.lang.String</code>, unless otherwise indicated.
+ * <code>String</code>, unless otherwise indicated.
  * 
  * @since 1.1
- * @version $Revision: 1.32 $
+ * @version $Revision: 6552 $
  */
 
 public interface Constants {
@@ -46,8 +44,7 @@
 	public static final String	SYSTEM_BUNDLE_SYMBOLICNAME				= "system.bundle";
 
 	/**
-	 * Manifest header (named &quot;Bundle-Category&quot;) identifying the
-	 * bundle's category.
+	 * Manifest header identifying the bundle's category.
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
 	 * object returned by the <code>Bundle.getHeaders</code> method.
@@ -55,9 +52,8 @@
 	public static final String	BUNDLE_CATEGORY							= "Bundle-Category";
 
 	/**
-	 * Manifest header (named &quot;Bundle-ClassPath&quot;) identifying a list
-	 * of directories and embedded JAR files, which are bundle resources used to
-	 * extend the bundle's classpath.
+	 * Manifest header identifying a list of directories and embedded JAR files,
+	 * which are bundle resources used to extend the bundle's classpath.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -66,8 +62,7 @@
 	public static final String	BUNDLE_CLASSPATH						= "Bundle-ClassPath";
 
 	/**
-	 * Manifest header (named &quot;Bundle-Copyright&quot;) identifying the
-	 * bundle's copyright information.
+	 * Manifest header identifying the bundle's copyright information.
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
 	 * object returned by the <code>Bundle.getHeaders</code> method.
@@ -75,8 +70,8 @@
 	public static final String	BUNDLE_COPYRIGHT						= "Bundle-Copyright";
 
 	/**
-	 * Manifest header (named &quot;Bundle-Description&quot;) containing a brief
-	 * description of the bundle's functionality.
+	 * Manifest header containing a brief description of the bundle's
+	 * functionality.
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
 	 * object returned by the <code>Bundle.getHeaders</code> method.
@@ -84,8 +79,7 @@
 	public static final String	BUNDLE_DESCRIPTION						= "Bundle-Description";
 
 	/**
-	 * Manifest header (named &quot;Bundle-Name&quot;) identifying the bundle's
-	 * name.
+	 * Manifest header identifying the bundle's name.
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
 	 * object returned by the <code>Bundle.getHeaders</code> method.
@@ -93,9 +87,9 @@
 	public static final String	BUNDLE_NAME								= "Bundle-Name";
 
 	/**
-	 * Manifest header (named &quot;Bundle-NativeCode&quot;) identifying a
-	 * number of hardware environments and the native language code libraries
-	 * that the bundle is carrying for each of these environments.
+	 * Manifest header identifying a number of hardware environments and the
+	 * native language code libraries that the bundle is carrying for each of
+	 * these environments.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -104,8 +98,8 @@
 	public static final String	BUNDLE_NATIVECODE						= "Bundle-NativeCode";
 
 	/**
-	 * Manifest header (named &quot;Export-Package&quot;) identifying the
-	 * packages that the bundle offers to the Framework for export.
+	 * Manifest header identifying the packages that the bundle offers to the
+	 * Framework for export.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -114,9 +108,9 @@
 	public static final String	EXPORT_PACKAGE							= "Export-Package";
 
 	/**
-	 * Manifest header (named &quot;Export-Service&quot;) identifying the fully
-	 * qualified class names of the services that the bundle may register (used
-	 * for informational purposes only).
+	 * Manifest header identifying the fully qualified class names of the
+	 * services that the bundle may register (used for informational purposes
+	 * only).
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -127,8 +121,7 @@
 	public static final String	EXPORT_SERVICE							= "Export-Service";
 
 	/**
-	 * Manifest header (named &quot;Import-Package&quot;) identifying the
-	 * packages on which the bundle depends.
+	 * Manifest header identifying the packages on which the bundle depends.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -137,8 +130,8 @@
 	public static final String	IMPORT_PACKAGE							= "Import-Package";
 
 	/**
-	 * Manifest header (named &quot;DynamicImport-Package&quot;) identifying the
-	 * packages that the bundle may dynamically import during execution.
+	 * Manifest header identifying the packages that the bundle may dynamically
+	 * import during execution.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -149,9 +142,8 @@
 	public static final String	DYNAMICIMPORT_PACKAGE					= "DynamicImport-Package";
 
 	/**
-	 * Manifest header (named &quot;Import-Service&quot;) identifying the fully
-	 * qualified class names of the services that the bundle requires (used for
-	 * informational purposes only).
+	 * Manifest header identifying the fully qualified class names of the
+	 * services that the bundle requires (used for informational purposes only).
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -162,8 +154,7 @@
 	public static final String	IMPORT_SERVICE							= "Import-Service";
 
 	/**
-	 * Manifest header (named &quot;Bundle-Vendor&quot;) identifying the
-	 * bundle's vendor.
+	 * Manifest header identifying the bundle's vendor.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -172,8 +163,7 @@
 	public static final String	BUNDLE_VENDOR							= "Bundle-Vendor";
 
 	/**
-	 * Manifest header (named &quot;Bundle-Version&quot;) identifying the
-	 * bundle's version.
+	 * Manifest header identifying the bundle's version.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -182,9 +172,8 @@
 	public static final String	BUNDLE_VERSION							= "Bundle-Version";
 
 	/**
-	 * Manifest header (named &quot;Bundle-DocURL&quot;) identifying the
-	 * bundle's documentation URL, from which further information about the
-	 * bundle may be obtained.
+	 * Manifest header identifying the bundle's documentation URL, from which
+	 * further information about the bundle may be obtained.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -193,9 +182,8 @@
 	public static final String	BUNDLE_DOCURL							= "Bundle-DocURL";
 
 	/**
-	 * Manifest header (named &quot;Bundle-ContactAddress&quot;) identifying the
-	 * contact address where problems with the bundle may be reported; for
-	 * example, an email address.
+	 * Manifest header identifying the contact address where problems with the
+	 * bundle may be reported; for example, an email address.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -204,8 +192,7 @@
 	public static final String	BUNDLE_CONTACTADDRESS					= "Bundle-ContactAddress";
 
 	/**
-	 * Manifest header attribute (named &quot;Bundle-Activator&quot;)
-	 * identifying the bundle's activator class.
+	 * Manifest header attribute identifying the bundle's activator class.
 	 * 
 	 * <p>
 	 * If present, this header specifies the name of the bundle resource class
@@ -220,9 +207,8 @@
 	public static final String	BUNDLE_ACTIVATOR						= "Bundle-Activator";
 
 	/**
-	 * Manifest header (named &quot;Bundle-UpdateLocation&quot;) identifying the
-	 * location from which a new bundle version is obtained during a bundle
-	 * update operation.
+	 * Manifest header identifying the location from which a new bundle version
+	 * is obtained during a bundle update operation.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -231,9 +217,8 @@
 	public static final String	BUNDLE_UPDATELOCATION					= "Bundle-UpdateLocation";
 
 	/**
-	 * Manifest header attribute (named &quot;specification-version&quot;)
-	 * identifying the version of a package specified in the Export-Package or
-	 * Import-Package manifest header.
+	 * Manifest header attribute identifying the version of a package specified
+	 * in the Export-Package or Import-Package manifest header.
 	 * 
 	 * @deprecated As of 1.3. This has been replaced by
 	 *             {@link #VERSION_ATTRIBUTE}.
@@ -241,9 +226,8 @@
 	public static final String	PACKAGE_SPECIFICATION_VERSION			= "specification-version";
 
 	/**
-	 * Manifest header attribute (named &quot;processor&quot;) identifying the
-	 * processor required to run native bundle code specified in the
-	 * Bundle-NativeCode manifest header).
+	 * Manifest header attribute identifying the processor required to run
+	 * native bundle code specified in the Bundle-NativeCode manifest header).
 	 * 
 	 * <p>
 	 * The attribute value is encoded in the Bundle-NativeCode manifest header
@@ -252,13 +236,15 @@
 	 * <pre>
 	 *     Bundle-NativeCode: http.so ; processor=x86 ...
 	 * </pre>
+	 * 
+	 * @see #BUNDLE_NATIVECODE
 	 */
 	public static final String	BUNDLE_NATIVECODE_PROCESSOR				= "processor";
 
 	/**
-	 * Manifest header attribute (named &quot;osname&quot;) identifying the
-	 * operating system required to run native bundle code specified in the
-	 * Bundle-NativeCode manifest header).
+	 * Manifest header attribute identifying the operating system required to
+	 * run native bundle code specified in the Bundle-NativeCode manifest
+	 * header).
 	 * <p>
 	 * The attribute value is encoded in the Bundle-NativeCode manifest header
 	 * like:
@@ -266,13 +252,15 @@
 	 * <pre>
 	 *     Bundle-NativeCode: http.so ; osname=Linux ...
 	 * </pre>
+	 * 
+	 * @see #BUNDLE_NATIVECODE
 	 */
 	public static final String	BUNDLE_NATIVECODE_OSNAME				= "osname";
 
 	/**
-	 * Manifest header attribute (named &quot;osversion&quot;) identifying the
-	 * operating system version required to run native bundle code specified in
-	 * the Bundle-NativeCode manifest header).
+	 * Manifest header attribute identifying the operating system version
+	 * required to run native bundle code specified in the Bundle-NativeCode
+	 * manifest header).
 	 * <p>
 	 * The attribute value is encoded in the Bundle-NativeCode manifest header
 	 * like:
@@ -280,13 +268,15 @@
 	 * <pre>
 	 *     Bundle-NativeCode: http.so ; osversion=&quot;2.34&quot; ...
 	 * </pre>
+	 * 
+	 * @see #BUNDLE_NATIVECODE
 	 */
 	public static final String	BUNDLE_NATIVECODE_OSVERSION				= "osversion";
 
 	/**
-	 * Manifest header attribute (named &quot;language&quot;) identifying the
-	 * language in which the native bundle code is written specified in the
-	 * Bundle-NativeCode manifest header. See ISO 639 for possible values.
+	 * Manifest header attribute identifying the language in which the native
+	 * bundle code is written specified in the Bundle-NativeCode manifest
+	 * header. See ISO 639 for possible values.
 	 * <p>
 	 * The attribute value is encoded in the Bundle-NativeCode manifest header
 	 * like:
@@ -294,15 +284,16 @@
 	 * <pre>
 	 *     Bundle-NativeCode: http.so ; language=nl_be ...
 	 * </pre>
+	 * 
+	 * @see #BUNDLE_NATIVECODE
 	 */
 	public static final String	BUNDLE_NATIVECODE_LANGUAGE				= "language";
 
 	/**
-	 * Manifest header (named &quot;Bundle-RequiredExecutionEnvironment&quot;)
-	 * identifying the required execution environment for the bundle. The
-	 * service platform may run this bundle if any of the execution environments
-	 * named in this header matches one of the execution environments it
-	 * implements.
+	 * Manifest header identifying the required execution environment for the
+	 * bundle. The service platform may run this bundle if any of the execution
+	 * environments named in this header matches one of the execution
+	 * environments it implements.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -312,269 +303,10 @@
 	 */
 	public static final String	BUNDLE_REQUIREDEXECUTIONENVIRONMENT		= "Bundle-RequiredExecutionEnvironment";
 
-	/*
-	 * Framework environment properties.
-	 */
-
 	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.framework.version&quot;) identifying the Framework
-	 * version.
+	 * Manifest header identifying the bundle's symbolic name.
 	 * 
 	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 */
-	public static final String	FRAMEWORK_VERSION						= "org.osgi.framework.version";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.framework.vendor&quot;) identifying the Framework
-	 * implementation vendor.
-	 * 
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 */
-	public static final String	FRAMEWORK_VENDOR						= "org.osgi.framework.vendor";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.framework.language&quot;) identifying the Framework
-	 * implementation language (see ISO 639 for possible values).
-	 * 
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 */
-	public static final String	FRAMEWORK_LANGUAGE						= "org.osgi.framework.language";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.framework.os.name&quot;) identifying the Framework
-	 * host-computer's operating system.
-	 * 
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 */
-	public static final String	FRAMEWORK_OS_NAME						= "org.osgi.framework.os.name";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.framework.os.version&quot;) identifying the Framework
-	 * host-computer's operating system version number.
-	 * 
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 */
-	public static final String	FRAMEWORK_OS_VERSION					= "org.osgi.framework.os.version";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.framework.processor&quot;) identifying the Framework
-	 * host-computer's processor name.
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 */
-	public static final String	FRAMEWORK_PROCESSOR						= "org.osgi.framework.processor";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.framework.executionenvironment&quot;) identifying
-	 * execution environments provided by the Framework.
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 * 
-	 * @since 1.2
-	 */
-	public static final String	FRAMEWORK_EXECUTIONENVIRONMENT			= "org.osgi.framework.executionenvironment";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.framework.bootdelegation&quot;) identifying packages for
-	 * which the Framework must delegate class loading to the boot class path.
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 * 
-	 * @since 1.3
-	 */
-	public static final String	FRAMEWORK_BOOTDELEGATION				= "org.osgi.framework.bootdelegation";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.framework.system.packages&quot;) identifying package which
-	 * the system bundle must export.
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 * 
-	 * @since 1.3
-	 */
-	public static final String	FRAMEWORK_SYSTEMPACKAGES				= "org.osgi.framework.system.packages";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.supports.framework.extension&quot;) identifying whether
-	 * the Framework supports framework extension bundles. As of version 1.4,
-	 * the value of this property must be <code>true</code>. The Framework
-	 * must support framework extension bundles.
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 * 
-	 * @since 1.3
-	 */
-	public static final String	SUPPORTS_FRAMEWORK_EXTENSION			= "org.osgi.supports.framework.extension";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.supports.bootclasspath.extension&quot;) identifying
-	 * whether the Framework supports bootclasspath extension bundles. If the
-	 * value of this property is <code>true</code>, then the Framework
-	 * supports bootclasspath extension bundles. The default value is
-	 * <code>false</code>.
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 * 
-	 * @since 1.3
-	 */
-	public static final String	SUPPORTS_BOOTCLASSPATH_EXTENSION		= "org.osgi.supports.bootclasspath.extension";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.supports.framework.fragment&quot;) identifying whether the
-	 * Framework supports fragment bundles. As of version 1.4, the value of this
-	 * property must be <code>true</code>. The Framework must support
-	 * fragment bundles.
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 * 
-	 * @since 1.3
-	 */
-	public static final String	SUPPORTS_FRAMEWORK_FRAGMENT				= "org.osgi.supports.framework.fragment";
-
-	/**
-	 * Framework environment property (named
-	 * &quot;org.osgi.supports.framework.requirebundle&quot;) identifying
-	 * whether the Framework supports the <code>Require-Bundle</code> manifest
-	 * header. As of version 1.4, the value of this property must be
-	 * <code>true</code>. The Framework must support the
-	 * <code>Require-Bundle</code> manifest header.
-	 * <p>
-	 * The value of this property may be retrieved by calling the
-	 * <code>BundleContext.getProperty</code> method.
-	 * 
-	 * @since 1.3
-	 */
-	public static final String	SUPPORTS_FRAMEWORK_REQUIREBUNDLE		= "org.osgi.supports.framework.requirebundle";
-
-	/*
-	 * Service properties.
-	 */
-
-	/**
-	 * Service property (named &quot;objectClass&quot;) identifying all of the
-	 * class names under which a service was registered in the Framework (of
-	 * type <code>java.lang.String[]</code>).
-	 * 
-	 * <p>
-	 * This property is set by the Framework when a service is registered.
-	 */
-	public static final String	OBJECTCLASS								= "objectClass";
-
-	/**
-	 * Service property (named &quot;service.id&quot;) identifying a service's
-	 * registration number (of type <code>java.lang.Long</code>).
-	 * 
-	 * <p>
-	 * The value of this property is assigned by the Framework when a service is
-	 * registered. The Framework assigns a unique value that is larger than all
-	 * previously assigned values since the Framework was started. These values
-	 * are NOT persistent across restarts of the Framework.
-	 */
-	public static final String	SERVICE_ID								= "service.id";
-
-	/**
-	 * Service property (named &quot;service.pid&quot;) identifying a service's
-	 * persistent identifier.
-	 * 
-	 * <p>
-	 * This property may be supplied in the <code>properties</code>
-	 * <code>Dictionary</code>
-	 * object passed to the <code>BundleContext.registerService</code> method.
-	 * 
-	 * <p>
-	 * A service's persistent identifier uniquely identifies the service and
-	 * persists across multiple Framework invocations.
-	 * 
-	 * <p>
-	 * By convention, every bundle has its own unique namespace, starting with
-	 * the bundle's identifier (see {@link Bundle#getBundleId}) and followed by
-	 * a dot (.). A bundle may use this as the prefix of the persistent
-	 * identifiers for the services it registers.
-	 */
-	public static final String	SERVICE_PID								= "service.pid";
-
-	/**
-	 * Service property (named &quot;service.ranking&quot;) identifying a
-	 * service's ranking number (of type <code>java.lang.Integer</code>).
-	 * 
-	 * <p>
-	 * This property may be supplied in the <code>properties
-	 * Dictionary</code>
-	 * object passed to the <code>BundleContext.registerService</code> method.
-	 * 
-	 * <p>
-	 * The service ranking is used by the Framework to determine the <i>default
-	 * </i> service to be returned from a call to the
-	 * {@link BundleContext#getServiceReference} method: If more than one
-	 * service implements the specified class, the <code>ServiceReference</code>
-	 * object with the highest ranking is returned.
-	 * 
-	 * <p>
-	 * The default ranking is zero (0). A service with a ranking of
-	 * <code>Integer.MAX_VALUE</code> is very likely to be returned as the
-	 * default service, whereas a service with a ranking of
-	 * <code>Integer.MIN_VALUE</code> is very unlikely to be returned.
-	 * 
-	 * <p>
-	 * If the supplied property value is not of type
-	 * <code>java.lang.Integer</code>, it is deemed to have a ranking value
-	 * of zero.
-	 */
-	public static final String	SERVICE_RANKING							= "service.ranking";
-
-	/**
-	 * Service property (named &quot;service.vendor&quot;) identifying a
-	 * service's vendor.
-	 * 
-	 * <p>
-	 * This property may be supplied in the properties <code>Dictionary</code>
-	 * object passed to the <code>BundleContext.registerService</code> method.
-	 */
-	public static final String	SERVICE_VENDOR							= "service.vendor";
-
-	/**
-	 * Service property (named &quot;service.description&quot;) identifying a
-	 * service's description.
-	 * 
-	 * <p>
-	 * This property may be supplied in the properties <code>Dictionary</code>
-	 * object passed to the <code>BundleContext.registerService</code> method.
-	 */
-	public static final String	SERVICE_DESCRIPTION						= "service.description";
-
-	/**
-	 * Manifest header (named &quot;Bundle-SymbolicName&quot;) identifying the
-	 * bundle's symbolic name.
-	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
 	 * object returned by the <code>Bundle.getHeaders</code> method.
 	 * 
@@ -583,8 +315,8 @@
 	public final static String	BUNDLE_SYMBOLICNAME						= "Bundle-SymbolicName";
 
 	/**
-	 * Manifest header directive (named &quot;singleton&quot;) identifying
-	 * whether a bundle is a singleton. The default value is <code>false</code>.
+	 * Manifest header directive identifying whether a bundle is a singleton.
+	 * The default value is <code>false</code>.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Bundle-SymbolicName manifest header
@@ -594,14 +326,19 @@
 	 *     Bundle-SymbolicName: com.acme.module.test; singleton:=true
 	 * </pre>
 	 * 
+	 * <p>
+	 * The attribute value may be retrieved from the <code>Dictionary</code>
+	 * object returned by the <code>Bundle.getHeaders</code> method.
+	 * 
+	 * @see #BUNDLE_SYMBOLICNAME
 	 * @since 1.3
 	 */
 	public final static String	SINGLETON_DIRECTIVE						= "singleton";
 
 	/**
-	 * Manifest header directive (named &quot;fragment-attachment&quot;)
-	 * identifying if and when a fragment may attach to a host bundle. The
-	 * default value is <code>&quot;always&quot;</code>.
+	 * Manifest header directive identifying if and when a fragment may attach
+	 * to a host bundle. The default value is
+	 * {@link #FRAGMENT_ATTACHMENT_ALWAYS always}.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Bundle-SymbolicName manifest header
@@ -611,19 +348,19 @@
 	 *     Bundle-SymbolicName: com.acme.module.test; fragment-attachment:=&quot;never&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#FRAGMENT_ATTACHMENT_ALWAYS
-	 * @see Constants#FRAGMENT_ATTACHMENT_RESOLVETIME
-	 * @see Constants#FRAGMENT_ATTACHMENT_NEVER
+	 * @see #BUNDLE_SYMBOLICNAME
+	 * @see #FRAGMENT_ATTACHMENT_ALWAYS
+	 * @see #FRAGMENT_ATTACHMENT_RESOLVETIME
+	 * @see #FRAGMENT_ATTACHMENT_NEVER
 	 * @since 1.3
 	 */
 	public final static String	FRAGMENT_ATTACHMENT_DIRECTIVE			= "fragment-attachment";
 
 	/**
-	 * Manifest header directive value (named &quot;always&quot;) identifying a
-	 * fragment attachment type of always. A fragment attachment type of always
-	 * indicates that fragments are allowed to attach to the host bundle at any
-	 * time (while the host is resolved or during the process of resolving the
-	 * host bundle).
+	 * Manifest header directive value identifying a fragment attachment type of
+	 * always. A fragment attachment type of always indicates that fragments are
+	 * allowed to attach to the host bundle at any time (while the host is
+	 * resolved or during the process of resolving the host bundle).
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Bundle-SymbolicName manifest header
@@ -633,17 +370,16 @@
 	 *     Bundle-SymbolicName: com.acme.module.test; fragment-attachment:=&quot;always&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#FRAGMENT_ATTACHMENT_DIRECTIVE
+	 * @see #FRAGMENT_ATTACHMENT_DIRECTIVE
 	 * @since 1.3
 	 */
 	public final static String	FRAGMENT_ATTACHMENT_ALWAYS				= "always";
 
 	/**
-	 * Manifest header directive value (named &quot;resolve-time&quot;)
-	 * identifying a fragment attachment type of resolve-time. A fragment
-	 * attachment type of resolve-time indicates that fragments are allowed to
-	 * attach to the host bundle only during the process of resolving the host
-	 * bundle.
+	 * Manifest header directive value identifying a fragment attachment type of
+	 * resolve-time. A fragment attachment type of resolve-time indicates that
+	 * fragments are allowed to attach to the host bundle only during the
+	 * process of resolving the host bundle.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Bundle-SymbolicName manifest header
@@ -653,16 +389,15 @@
 	 *     Bundle-SymbolicName: com.acme.module.test; fragment-attachment:=&quot;resolve-time&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#FRAGMENT_ATTACHMENT_DIRECTIVE
+	 * @see #FRAGMENT_ATTACHMENT_DIRECTIVE
 	 * @since 1.3
 	 */
 	public final static String	FRAGMENT_ATTACHMENT_RESOLVETIME			= "resolve-time";
 
 	/**
-	 * Manifest header directive value (named &quot;never&quot;) identifying a
-	 * fragment attachment type of never. A fragment attachment type of never
-	 * indicates that no fragments are allowed to attach to the host bundle at
-	 * any time.
+	 * Manifest header directive value identifying a fragment attachment type of
+	 * never. A fragment attachment type of never indicates that no fragments
+	 * are allowed to attach to the host bundle at any time.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Bundle-SymbolicName manifest header
@@ -672,14 +407,15 @@
 	 *     Bundle-SymbolicName: com.acme.module.test; fragment-attachment:=&quot;never&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#FRAGMENT_ATTACHMENT_DIRECTIVE
+	 * @see #FRAGMENT_ATTACHMENT_DIRECTIVE
 	 * @since 1.3
 	 */
 	public final static String	FRAGMENT_ATTACHMENT_NEVER				= "never";
 
 	/**
-	 * Manifest header (named &quot;Bundle-Localization&quot;) identifying the
-	 * base name of the bundle's localization entries.
+	 * Manifest header identifying the base name of the bundle's localization
+	 * entries.
+	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
 	 * object returned by the <code>Bundle.getHeaders</code> method.
@@ -698,8 +434,8 @@
 	public final static String	BUNDLE_LOCALIZATION_DEFAULT_BASENAME	= "OSGI-INF/l10n/bundle";
 
 	/**
-	 * Manifest header (named &quot;Require-Bundle&quot;) identifying the
-	 * symbolic names of other bundles required by the bundle.
+	 * Manifest header identifying the symbolic names of other bundles required
+	 * by the bundle.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -710,9 +446,10 @@
 	public final static String	REQUIRE_BUNDLE							= "Require-Bundle";
 
 	/**
-	 * Manifest header attribute (named &quot;bundle-version&quot;) identifying
-	 * a range of versions for a bundle specified in the Require-Bundle or
-	 * Fragment-Host manifest headers. The default value is <code>0.0.0</code>.
+	 * Manifest header attribute identifying a range of versions for a bundle
+	 * specified in the <code>Require-Bundle</code> or
+	 * <code>Fragment-Host</code> manifest headers. The default value is
+	 * <code>0.0.0</code>.
 	 * 
 	 * <p>
 	 * The attribute value is encoded in the Require-Bundle manifest header
@@ -729,13 +466,14 @@
 	 * specified as a single version means a version range that includes any
 	 * bundle version greater than or equal to the specified version.
 	 * 
+	 * @see #REQUIRE_BUNDLE
 	 * @since 1.3
 	 */
 	public static final String	BUNDLE_VERSION_ATTRIBUTE				= "bundle-version";
 
 	/**
-	 * Manifest header (named &quot;Fragment-Host&quot;) identifying the
-	 * symbolic name of another bundle for which that the bundle is a fragment.
+	 * Manifest header identifying the symbolic name of another bundle for which
+	 * that the bundle is a fragment.
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -746,8 +484,8 @@
 	public final static String	FRAGMENT_HOST							= "Fragment-Host";
 
 	/**
-	 * Manifest header attribute (named &quot;selection-filter&quot;) is used
-	 * for selection by filtering based upon system properties.
+	 * Manifest header attribute is used for selection by filtering based upon
+	 * system properties.
 	 * 
 	 * <p>
 	 * The attribute value is encoded in manifest headers like:
@@ -756,19 +494,19 @@
 	 *     Bundle-NativeCode: libgtk.so; selection-filter=&quot;(ws=gtk)&quot;; ...
 	 * </pre>
 	 * 
+	 * @see #BUNDLE_NATIVECODE
 	 * @since 1.3
 	 */
 	public final static String	SELECTION_FILTER_ATTRIBUTE				= "selection-filter";
 
 	/**
-	 * Manifest header (named &quot;Bundle-ManifestVersion&quot;) identifying
-	 * the bundle manifest version. A bundle manifest may express the version of
-	 * the syntax in which it is written by specifying a bundle manifest
-	 * version. Bundles exploiting OSGi R4, or later, syntax must specify a
-	 * bundle manifest version.
+	 * Manifest header identifying the bundle manifest version. A bundle
+	 * manifest may express the version of the syntax in which it is written by
+	 * specifying a bundle manifest version. Bundles exploiting OSGi Release 4,
+	 * or later, syntax must specify a bundle manifest version.
 	 * <p>
-	 * The bundle manifest version defined by OSGi R4 or, more specifically, by
-	 * V1.3 of the OSGi Framework Specification is "2".
+	 * The bundle manifest version defined by OSGi Release 4 or, more
+	 * specifically, by version 1.3 of the OSGi Core Specification is "2".
 	 * 
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
@@ -779,9 +517,8 @@
 	public final static String	BUNDLE_MANIFESTVERSION					= "Bundle-ManifestVersion";
 
 	/**
-	 * Manifest header attribute (named &quot;version&quot;) identifying the
-	 * version of a package specified in the Export-Package or Import-Package
-	 * manifest header.
+	 * Manifest header attribute identifying the version of a package specified
+	 * in the Export-Package or Import-Package manifest header.
 	 * 
 	 * <p>
 	 * The attribute value is encoded in the Export-Package or Import-Package
@@ -791,14 +528,15 @@
 	 *     Import-Package: org.osgi.framework; version=&quot;1.1&quot;
 	 * </pre>
 	 * 
+	 * @see #EXPORT_PACKAGE
+	 * @see #IMPORT_PACKAGE
 	 * @since 1.3
 	 */
 	public final static String	VERSION_ATTRIBUTE						= "version";
 
 	/**
-	 * Manifest header attribute (named &quot;bundle-symbolic-name&quot;)
-	 * identifying the symbolic name of a bundle that exports a package
-	 * specified in the Import-Package manifest header.
+	 * Manifest header attribute identifying the symbolic name of a bundle that
+	 * exports a package specified in the Import-Package manifest header.
 	 * 
 	 * <p>
 	 * The attribute value is encoded in the Import-Package manifest header
@@ -808,13 +546,15 @@
 	 *     Import-Package: org.osgi.framework; bundle-symbolic-name=&quot;com.acme.module.test&quot;
 	 * </pre>
 	 * 
+	 * @see #IMPORT_PACKAGE
 	 * @since 1.3
 	 */
 	public final static String	BUNDLE_SYMBOLICNAME_ATTRIBUTE			= "bundle-symbolic-name";
 
 	/**
-	 * Manifest header directive (named &quot;resolution&quot;) identifying the
-	 * resolution type in the Import-Package or Require-Bundle manifest header.
+	 * Manifest header directive identifying the resolution type in the
+	 * Import-Package or Require-Bundle manifest header. The default value is
+	 * {@link #RESOLUTION_MANDATORY mandatory}.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Import-Package or Require-Bundle
@@ -825,18 +565,19 @@
 	 *     Require-Bundle: com.acme.module.test; resolution:=&quot;optional&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#RESOLUTION_MANDATORY
-	 * @see Constants#RESOLUTION_OPTIONAL
+	 * @see #IMPORT_PACKAGE
+	 * @see #REQUIRE_BUNDLE
+	 * @see #RESOLUTION_MANDATORY
+	 * @see #RESOLUTION_OPTIONAL
 	 * @since 1.3
 	 */
 	public final static String	RESOLUTION_DIRECTIVE					= "resolution";
 
 	/**
-	 * Manifest header directive value (named &quot;mandatory&quot;) identifying
-	 * a mandatory resolution type. A mandatory resolution type indicates that
-	 * the import package or require bundle must be resolved when the bundle is
-	 * resolved. If such an import or require bundle cannot be resolved, the
-	 * module fails to resolve.
+	 * Manifest header directive value identifying a mandatory resolution type.
+	 * A mandatory resolution type indicates that the import package or require
+	 * bundle must be resolved when the bundle is resolved. If such an import or
+	 * require bundle cannot be resolved, the module fails to resolve.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Import-Package or Require-Bundle
@@ -847,18 +588,18 @@
 	 *     Require-Bundle: com.acme.module.test; resolution:=&quot;manditory&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#RESOLUTION_DIRECTIVE
+	 * @see #RESOLUTION_DIRECTIVE
 	 * @since 1.3
 	 */
 	public final static String	RESOLUTION_MANDATORY					= "mandatory";
 
 	/**
-	 * Manifest header directive value (named &quot;optional&quot;) identifying
-	 * an optional resolution type. An optional resolution type indicates that
-	 * the import or require bundle is optional and the bundle may be resolved
-	 * without the import or require bundle being resolved. If the import or
-	 * require bundle is not resolved when the bundle is resolved, the import or
-	 * require bundle may not be resolved before the bundle is refreshed.
+	 * Manifest header directive value identifying an optional resolution type.
+	 * An optional resolution type indicates that the import or require bundle
+	 * is optional and the bundle may be resolved without the import or require
+	 * bundle being resolved. If the import or require bundle is not resolved
+	 * when the bundle is resolved, the import or require bundle may not be
+	 * resolved before the bundle is refreshed.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Import-Package or Require-Bundle
@@ -869,14 +610,14 @@
 	 *     Require-Bundle: com.acme.module.test; resolution:=&quot;optional&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#RESOLUTION_DIRECTIVE
+	 * @see #RESOLUTION_DIRECTIVE
 	 * @since 1.3
 	 */
 	public final static String	RESOLUTION_OPTIONAL						= "optional";
 
 	/**
-	 * Manifest header directive (named &quot;uses&quot;) identifying a list of
-	 * packages that an exported package uses.
+	 * Manifest header directive identifying a list of packages that an exported
+	 * package uses.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Export-Package manifest header
@@ -886,20 +627,23 @@
 	 *     Export-Package: org.osgi.util.tracker; uses:=&quot;org.osgi.framework&quot;
 	 * </pre>
 	 * 
+	 * @see #EXPORT_PACKAGE
 	 * @since 1.3
 	 */
 	public final static String	USES_DIRECTIVE							= "uses";
 
 	/**
-	 * Manifest header directive (named &quot;include&quot;).
+	 * Manifest header directive identifying a list of classes to include in the
+	 * exported package.
+	 * 
 	 * <p>
-	 * This directive is used by the Import-Package manifest header to identify
+	 * This directive is used by the Export-Package manifest header to identify
 	 * a list of classes of the specified package which must be allowed to be
-	 * exported. The directive value is encoded in the Import-Package manifest
+	 * exported. The directive value is encoded in the Export-Package manifest
 	 * header like:
 	 * 
 	 * <pre>
-	 *     Import-Package: org.osgi.framework; include:=&quot;MyClass*&quot;
+	 *     Export-Package: org.osgi.framework; include:=&quot;MyClass*&quot;
 	 * </pre>
 	 * 
 	 * <p>
@@ -912,12 +656,15 @@
 	 *     Bundle-ActivationPolicy: lazy; include:=&quot;org.osgi.framework&quot;
 	 * </pre>
 	 * 
+	 * @see #EXPORT_PACKAGE
+	 * @see #BUNDLE_ACTIVATIONPOLICY
 	 * @since 1.3
 	 */
 	public final static String	INCLUDE_DIRECTIVE						= "include";
 
 	/**
-	 * Manifest header directive (named &quot;exclude&quot;).
+	 * Manifest header directive identifying a list of classes to exclude in the
+	 * exported package..
 	 * <p>
 	 * This directive is used by the Export-Package manifest header to identify
 	 * a list of classes of the specified package which must not be allowed to
@@ -938,14 +685,16 @@
 	 *     Bundle-ActivationPolicy: lazy; exclude:=&quot;org.osgi.framework&quot;
 	 * </pre>
 	 * 
+	 * @see #EXPORT_PACKAGE
+	 * @see #BUNDLE_ACTIVATIONPOLICY
 	 * @since 1.3
 	 */
 	public final static String	EXCLUDE_DIRECTIVE						= "exclude";
 
 	/**
-	 * Manifest header directive (named &quot;mandatory&quot;) identifying names
-	 * of matching attributes which must be specified by matching Import-Package
-	 * statements in the Export-Package manifest header.
+	 * Manifest header directive identifying names of matching attributes which
+	 * must be specified by matching Import-Package statements in the
+	 * Export-Package manifest header.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Export-Package manifest header
@@ -955,13 +704,15 @@
 	 *     Export-Package: org.osgi.framework; mandatory:=&quot;bundle-symbolic-name&quot;
 	 * </pre>
 	 * 
+	 * @see #EXPORT_PACKAGE
 	 * @since 1.3
 	 */
 	public final static String	MANDATORY_DIRECTIVE						= "mandatory";
 
 	/**
-	 * Manifest header directive (named &quot;visibility&quot;) identifying the
-	 * visibility of a reqiured bundle in the Require-Bundle manifest header.
+	 * Manifest header directive identifying the visibility of a required bundle
+	 * in the Require-Bundle manifest header. The default value is
+	 * {@link #VISIBILITY_PRIVATE private}.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Require-Bundle manifest header
@@ -971,17 +722,18 @@
 	 *     Require-Bundle: com.acme.module.test; visibility:=&quot;reexport&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#VISIBILITY_PRIVATE
-	 * @see Constants#VISIBILITY_REEXPORT
+	 * @see #REQUIRE_BUNDLE
+	 * @see #VISIBILITY_PRIVATE
+	 * @see #VISIBILITY_REEXPORT
 	 * @since 1.3
 	 */
 	public final static String	VISIBILITY_DIRECTIVE					= "visibility";
 
 	/**
-	 * Manifest header directive value (named &quot;private&quot;) identifying a
-	 * private visibility type. A private visibility type indicates that any
-	 * packages that are exported by the required bundle are not made visible on
-	 * the export signature of the requiring bundle.
+	 * Manifest header directive value identifying a private visibility type. A
+	 * private visibility type indicates that any packages that are exported by
+	 * the required bundle are not made visible on the export signature of the
+	 * requiring bundle.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Require-Bundle manifest header
@@ -991,17 +743,17 @@
 	 *     Require-Bundle: com.acme.module.test; visibility:=&quot;private&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#VISIBILITY_DIRECTIVE
+	 * @see #VISIBILITY_DIRECTIVE
 	 * @since 1.3
 	 */
 	public final static String	VISIBILITY_PRIVATE						= "private";
 
 	/**
-	 * Manifest header directive value (named &quot;reexport&quot;) identifying
-	 * a reexport visibility type. A reexport visibility type indicates any
-	 * packages that are exported by the required bundle are re-exported by the
-	 * requiring bundle. Any arbitrary arbitrary matching attributes with which
-	 * they were exported by the required bundle are deleted.
+	 * Manifest header directive value identifying a reexport visibility type. A
+	 * reexport visibility type indicates any packages that are exported by the
+	 * required bundle are re-exported by the requiring bundle. Any arbitrary
+	 * arbitrary matching attributes with which they were exported by the
+	 * required bundle are deleted.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Require-Bundle manifest header
@@ -1011,13 +763,13 @@
 	 *     Require-Bundle: com.acme.module.test; visibility:=&quot;reexport&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#VISIBILITY_DIRECTIVE
+	 * @see #VISIBILITY_DIRECTIVE
 	 * @since 1.3
 	 */
 	public final static String	VISIBILITY_REEXPORT						= "reexport";
+
 	/**
-	 * Manifest header directive (named &quot;extension&quot;) identifying the
-	 * type of the extension fragment.
+	 * Manifest header directive identifying the type of the extension fragment.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Fragment-Host manifest header like:
@@ -1026,17 +778,17 @@
 	 *     Fragment-Host: system.bundle; extension:=&quot;framework&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#EXTENSION_FRAMEWORK
-	 * @see Constants#EXTENSION_BOOTCLASSPATH
+	 * @see #FRAGMENT_HOST
+	 * @see #EXTENSION_FRAMEWORK
+	 * @see #EXTENSION_BOOTCLASSPATH
 	 * @since 1.3
 	 */
 	public final static String	EXTENSION_DIRECTIVE						= "extension";
 
 	/**
-	 * Manifest header directive value (named &quot;framework&quot;) identifying
-	 * the type of extension fragment. An extension fragment type of framework
-	 * indicates that the extension fragment is to be loaded by the framework's
-	 * class loader.
+	 * Manifest header directive value identifying the type of extension
+	 * fragment. An extension fragment type of framework indicates that the
+	 * extension fragment is to be loaded by the framework's class loader.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Fragment-Host manifest header like:
@@ -1045,16 +797,15 @@
 	 *     Fragment-Host: system.bundle; extension:=&quot;framework&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#EXTENSION_DIRECTIVE
+	 * @see #EXTENSION_DIRECTIVE
 	 * @since 1.3
 	 */
 	public final static String	EXTENSION_FRAMEWORK						= "framework";
 
 	/**
-	 * Manifest header directive value (named &quot;bootclasspath&quot;)
-	 * identifying the type of extension fragment. An extension fragment type of
-	 * bootclasspath indicates that the extension fragment is to be loaded by
-	 * the boot class loader.
+	 * Manifest header directive value identifying the type of extension
+	 * fragment. An extension fragment type of bootclasspath indicates that the
+	 * extension fragment is to be loaded by the boot class loader.
 	 * 
 	 * <p>
 	 * The directive value is encoded in the Fragment-Host manifest header like:
@@ -1063,34 +814,33 @@
 	 *     Fragment-Host: system.bundle; extension:=&quot;bootclasspath&quot;
 	 * </pre>
 	 * 
-	 * @see Constants#EXTENSION_DIRECTIVE
+	 * @see #EXTENSION_DIRECTIVE
 	 * @since 1.3
 	 */
 	public final static String	EXTENSION_BOOTCLASSPATH					= "bootclasspath";
 
 	/**
-	 * Manifest header (named &quot;Bundle-ActivationPolicy&quot;) identifying
-	 * the bundle's activation policy.
+	 * Manifest header identifying the bundle's activation policy.
 	 * <p>
 	 * The attribute value may be retrieved from the <code>Dictionary</code>
 	 * object returned by the <code>Bundle.getHeaders</code> method.
 	 * 
 	 * @since 1.4
-	 * @see Constants#ACTIVATION_LAZY
-	 * @see Constants#INCLUDE_DIRECTIVE
-	 * @see Constants#EXCLUDE_DIRECTIVE
+	 * @see #ACTIVATION_LAZY
+	 * @see #INCLUDE_DIRECTIVE
+	 * @see #EXCLUDE_DIRECTIVE
 	 */
 	public final static String	BUNDLE_ACTIVATIONPOLICY					= "Bundle-ActivationPolicy";
 
 	/**
-	 * Bundle activation policy (named &quot;lazy&quot;) declaring the bundle
-	 * must be activated when the first class load is made from the bundle.
+	 * Bundle activation policy declaring the bundle must be activated when the
+	 * first class load is made from the bundle.
 	 * <p>
 	 * A bundle with the lazy activation policy that is started with the
 	 * {@link Bundle#START_ACTIVATION_POLICY START_ACTIVATION_POLICY} option
 	 * will wait in the {@link Bundle#STARTING STARTING} state until the first
 	 * class load from the bundle occurs. The bundle will then be activated
-	 * before the class is returned to the requestor.
+	 * before the class is returned to the requester.
 	 * <p>
 	 * The activation policy value is specified as in the
 	 * Bundle-ActivationPolicy manifest header like:
@@ -1099,11 +849,464 @@
 	 *       Bundle-ActivationPolicy: lazy
 	 * </pre>
 	 * 
-	 * @see Constants#BUNDLE_ACTIVATIONPOLICY
+	 * @see #BUNDLE_ACTIVATIONPOLICY
 	 * @see Bundle#start(int)
 	 * @see Bundle#START_ACTIVATION_POLICY
 	 * @since 1.4
 	 */
 	public final static String	ACTIVATION_LAZY							= "lazy";
 
-}
\ No newline at end of file
+	/**
+	 * Framework environment property identifying the Framework version.
+	 * 
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 */
+	public static final String	FRAMEWORK_VERSION						= "org.osgi.framework.version";
+
+	/**
+	 * Framework environment property identifying the Framework implementation
+	 * vendor.
+	 * 
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 */
+	public static final String	FRAMEWORK_VENDOR						= "org.osgi.framework.vendor";
+
+	/**
+	 * Framework environment property identifying the Framework implementation
+	 * language (see ISO 639 for possible values).
+	 * 
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 */
+	public static final String	FRAMEWORK_LANGUAGE						= "org.osgi.framework.language";
+
+	/**
+	 * Framework environment property identifying the Framework host-computer's
+	 * operating system.
+	 * 
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 */
+	public static final String	FRAMEWORK_OS_NAME						= "org.osgi.framework.os.name";
+
+	/**
+	 * Framework environment property identifying the Framework host-computer's
+	 * operating system version number.
+	 * 
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 */
+	public static final String	FRAMEWORK_OS_VERSION					= "org.osgi.framework.os.version";
+
+	/**
+	 * Framework environment property identifying the Framework host-computer's
+	 * processor name.
+	 * 
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 */
+	public static final String	FRAMEWORK_PROCESSOR						= "org.osgi.framework.processor";
+
+	/**
+	 * Framework environment property identifying execution environments
+	 * provided by the Framework.
+	 * 
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 * 
+	 * @since 1.2
+	 */
+	public static final String	FRAMEWORK_EXECUTIONENVIRONMENT			= "org.osgi.framework.executionenvironment";
+
+	/**
+	 * Framework environment property identifying packages for which the
+	 * Framework must delegate class loading to the parent class loader of the
+	 * bundle.
+	 * 
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 * 
+	 * @see #FRAMEWORK_BUNDLE_PARENT
+	 * @since 1.3
+	 */
+	public static final String	FRAMEWORK_BOOTDELEGATION				= "org.osgi.framework.bootdelegation";
+
+	/**
+	 * Framework environment property identifying packages which the system
+	 * bundle must export.
+	 * 
+	 * <p>
+	 * If this property is not specified then the framework must calculate a
+	 * reasonable default value for the current execution environment.
+	 * 
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 * 
+	 * @since 1.3
+	 */
+	public static final String	FRAMEWORK_SYSTEMPACKAGES				= "org.osgi.framework.system.packages";
+
+	/**
+	 * Framework environment property identifying extra packages which the
+	 * system bundle must export from the current execution environment.
+	 * 
+	 * <p>
+	 * This property is useful for configuring extra system packages in addition
+	 * to the system packages calculated by the framework.
+	 * 
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 * 
+	 * @see #FRAMEWORK_SYSTEMPACKAGES
+	 * @since 1.5
+	 */
+	public static final String	FRAMEWORK_SYSTEMPACKAGES_EXTRA			= "org.osgi.framework.system.packages.extra";
+
+	/**
+	 * Framework environment property identifying whether the Framework supports
+	 * framework extension bundles.
+	 * 
+	 * <p>
+	 * As of version 1.4, the value of this property must be <code>true</code>.
+	 * The Framework must support framework extension bundles.
+	 * 
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 * 
+	 * @since 1.3
+	 */
+	public static final String	SUPPORTS_FRAMEWORK_EXTENSION			= "org.osgi.supports.framework.extension";
+
+	/**
+	 * Framework environment property identifying whether the Framework supports
+	 * bootclasspath extension bundles.
+	 * 
+	 * <p>
+	 * If the value of this property is <code>true</code>, then the Framework
+	 * supports bootclasspath extension bundles. The default value is
+	 * <code>false</code>.
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 * 
+	 * @since 1.3
+	 */
+	public static final String	SUPPORTS_BOOTCLASSPATH_EXTENSION		= "org.osgi.supports.bootclasspath.extension";
+
+	/**
+	 * Framework environment property identifying whether the Framework supports
+	 * fragment bundles.
+	 * 
+	 * <p>
+	 * As of version 1.4, the value of this property must be <code>true</code>.
+	 * The Framework must support fragment bundles.
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 * 
+	 * @since 1.3
+	 */
+	public static final String	SUPPORTS_FRAMEWORK_FRAGMENT				= "org.osgi.supports.framework.fragment";
+
+	/**
+	 * Framework environment property identifying whether the Framework supports
+	 * the {@link #REQUIRE_BUNDLE Require-Bundle} manifest header.
+	 * 
+	 * <p>
+	 * As of version 1.4, the value of this property must be <code>true</code>.
+	 * The Framework must support the <code>Require-Bundle</code> manifest
+	 * header.
+	 * <p>
+	 * The value of this property may be retrieved by calling the
+	 * <code>BundleContext.getProperty</code> method.
+	 * 
+	 * @since 1.3
+	 */
+	public static final String	SUPPORTS_FRAMEWORK_REQUIREBUNDLE		= "org.osgi.supports.framework.requirebundle";
+
+	/**
+	 * Specifies the type of security manager the framework must use. If not
+	 * specified then the framework will not set the VM security manager.
+	 * 
+	 * @see #FRAMEWORK_SECURITY_OSGI
+	 * @since 1.5
+	 */
+	public final static String	FRAMEWORK_SECURITY						= "org.osgi.framework.security";
+
+	/**
+	 * Specifies that a security manager that supports all security aspects of
+	 * the OSGi core specification including postponed conditions must be
+	 * installed.
+	 * 
+	 * <p>
+	 * If this value is specified and there is a security manager already
+	 * installed, then a <code>SecurityException</code> must be thrown when the
+	 * Framework is initialized.
+	 * 
+	 * @see #FRAMEWORK_SECURITY
+	 * @since 1.5
+	 */
+	public final static String	FRAMEWORK_SECURITY_OSGI					= "osgi";
+
+	/**
+	 * Specified the persistent storage area used by the framework. The value of
+	 * this property must be a valid file path in the file system to a
+	 * directory. If the specified directory does not exist then the framework
+	 * will create the directory. If the specified path exists but is not a
+	 * directory or if the framework fails to create the storage directory, then
+	 * framework initialization must fail. The framework is free to use this
+	 * directory as it sees fit. This area can not be shared with anything else.
+	 * <p>
+	 * If this property is not set, the framework should use a reasonable
+	 * platform default for the persistent storage area.
+	 * 
+	 * @since 1.5
+	 */
+	public final static String	FRAMEWORK_STORAGE						= "org.osgi.framework.storage";
+
+	/**
+	 * Specifies if and when the persistent storage area for the framework
+	 * should be cleaned. If this property is not set, then the framework
+	 * storage area must not be cleaned.
+	 * 
+	 * @see #FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT
+	 * @since 1.5
+	 */
+	public final static String	FRAMEWORK_STORAGE_CLEAN					= "org.osgi.framework.storage.clean";
+
+	/**
+	 * Specifies that the framework storage area must be cleaned before the
+	 * framework is initialized for the first time. Subsequent inits, starts or
+	 * updates of the framework will not result in cleaning the framework
+	 * storage area.
+	 * 
+	 * @since 1.5
+	 */
+	public final static String  FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT			= "onFirstInit";
+
+	/**
+	 * Specifies a comma separated list of additional library file extensions
+	 * that must be used when a bundle's class loader is searching for native
+	 * libraries. If this property is not set, then only the library name
+	 * returned by <code>System.mapLibraryName(String)</code> will be used to
+	 * search. This is needed for certain operating systems which allow more
+	 * than one extension for a library. For example, AIX allows library
+	 * extensions of <code>.a</code> and <code>.so</code>, but
+	 * <code>System.mapLibraryName(String)</code> will only return names with
+	 * the <code>.a</code> extension.
+	 * 
+	 * @since 1.5
+	 */
+	public final static String	FRAMEWORK_LIBRARY_EXTENSIONS			= "org.osgi.framework.library.extensions";
+
+	/**
+	 * Specifies an optional OS specific command to set file permissions on
+	 * extracted native code. On some operating systems, it is required that
+	 * native libraries be set to executable. This optional property allows you
+	 * to specify the command. For example, on a UNIX style OS, this property
+	 * could have the following value.
+	 * 
+	 * <pre>
+	 * chmod +rx ${abspath}
+	 * </pre>
+	 * 
+	 * The <code>${abspath}</code> is used by the framework to substitute the
+	 * actual absolute file path.
+	 * 
+	 * @since 1.5
+	 */
+	public final static String	FRAMEWORK_EXECPERMISSION				= "org.osgi.framework.command.execpermission";
+
+	/**
+	 * Specifies the trust repositories used by the framework. The value is a
+	 * <code>java.io.File.pathSeparator</code> separated list of valid file
+	 * paths to files that contain key stores of type <code>JKS</code>. The
+	 * framework will use the key stores as trust repositories to authenticate
+	 * certificates of trusted signers. The key stores are only used as
+	 * read-only trust repositories to access public keys. No passwords are
+	 * required to access the key stores' public keys.
+	 * <p>
+	 * Note that framework implementations are allowed to use other trust
+	 * repositories in addition to the trust repositories specified by this
+	 * property. How these other trust repositories are configured and populated
+	 * is implementation specific.
+	 * 
+	 * @since 1.5
+	 */
+	public final static String	FRAMEWORK_TRUST_REPOSITORIES			= "org.osgi.framework.trust.repositories";
+
+	/**
+	 * Specifies the current windowing system. The framework should provide a
+	 * reasonable default if this is not set.
+	 * 
+	 * @since 1.5
+	 */
+	public final static String	FRAMEWORK_WINDOWSYSTEM					= "org.osgi.framework.windowsystem";
+
+	/**
+	 * Specifies the beginning start level of the framework.
+	 * 
+	 * @see "Core Specification, section 8.2.3."
+	 * @since 1.5
+	 */
+	public final static String	FRAMEWORK_BEGINNING_STARTLEVEL			= "org.osgi.framework.startlevel.beginning";
+
+	/**
+	 * Specifies the parent class loader type for all bundle class loaders.
+	 * Default value is {@link #FRAMEWORK_BUNDLE_PARENT_BOOT boot}.
+	 * 
+	 * @see #FRAMEWORK_BUNDLE_PARENT_BOOT
+	 * @see #FRAMEWORK_BUNDLE_PARENT_EXT
+	 * @see #FRAMEWORK_BUNDLE_PARENT_APP
+	 * @see #FRAMEWORK_BUNDLE_PARENT_FRAMEWORK
+	 * @since 1.5
+	 */
+	public final static String FRAMEWORK_BUNDLE_PARENT 					= "org.osgi.framework.bundle.parent";
+
+	/**
+	 * Specifies to use of the boot class loader as the parent class loader for
+	 * all bundle class loaders.
+	 * 
+	 * @since 1.5
+	 * @see #FRAMEWORK_BUNDLE_PARENT
+	 */
+	public final static String	FRAMEWORK_BUNDLE_PARENT_BOOT			= "boot";
+
+	/**
+	 * Specifies to use the extension class loader as the parent class loader
+	 * for all bundle class loaders.
+	 * 
+	 * @since 1.5
+	 * @see #FRAMEWORK_BUNDLE_PARENT
+	 */
+	public final static String	FRAMEWORK_BUNDLE_PARENT_EXT				= "ext";
+
+	/**
+	 * Specifies to use the application class loader as the parent class loader
+	 * for all bundle class loaders.  Depending on how the framework is 
+	 * launched, this may refer to the same class loader as 
+	 * {@link #FRAMEWORK_BUNDLE_PARENT_FRAMEWORK}.
+	 * 
+	 * @since 1.5
+	 * @see #FRAMEWORK_BUNDLE_PARENT
+	 */
+	public final static String	FRAMEWORK_BUNDLE_PARENT_APP				= "app";
+
+	/**
+	 * Specifies to use the framework class loader as the parent class loader
+	 * for all bundle class loaders. The framework class loader is the class
+	 * loader used to load the framework implementation.  Depending on how the 
+	 * framework is launched, this may refer to the same class loader as 
+	 * {@link #FRAMEWORK_BUNDLE_PARENT_APP}.
+	 * 
+	 * @since 1.5
+	 * @see #FRAMEWORK_BUNDLE_PARENT
+	 */
+	public final static String	FRAMEWORK_BUNDLE_PARENT_FRAMEWORK		= "framework";
+
+	/*
+	 * Service properties.
+	 */
+	
+	/**
+	 * Service property identifying all of the class names under which a service
+	 * was registered in the Framework. The value of this property must be of
+	 * type <code>String[]</code>.
+	 * 
+	 * <p>
+	 * This property is set by the Framework when a service is registered.
+	 */
+	public static final String	OBJECTCLASS								= "objectClass";
+
+	/**
+	 * Service property identifying a service's registration number. The value
+	 * of this property must be of type <code>Long</code>.
+	 * 
+	 * <p>
+	 * The value of this property is assigned by the Framework when a service is
+	 * registered. The Framework assigns a unique value that is larger than all
+	 * previously assigned values since the Framework was started. These values
+	 * are NOT persistent across restarts of the Framework.
+	 */
+	public static final String	SERVICE_ID								= "service.id";
+
+	/**
+	 * Service property identifying a service's persistent identifier.
+	 * 
+	 * <p>
+	 * This property may be supplied in the <code>properties</code>
+	 * <code>Dictionary</code> object passed to the
+	 * <code>BundleContext.registerService</code> method. The value of this
+	 * property must be of type <code>String</code>, <code>String[]</code>, or
+	 * <code>Collection</code> of <code>String</code>.
+	 * 
+	 * <p>
+	 * A service's persistent identifier uniquely identifies the service and
+	 * persists across multiple Framework invocations.
+	 * 
+	 * <p>
+	 * By convention, every bundle has its own unique namespace, starting with
+	 * the bundle's identifier (see {@link Bundle#getBundleId}) and followed by
+	 * a dot (.). A bundle may use this as the prefix of the persistent
+	 * identifiers for the services it registers.
+	 */
+	public static final String	SERVICE_PID								= "service.pid";
+
+	/**
+	 * Service property identifying a service's ranking number.
+	 * 
+	 * <p>
+	 * This property may be supplied in the <code>properties
+	 * Dictionary</code> object passed to the
+	 * <code>BundleContext.registerService</code> method. The value of this
+	 * property must be of type <code>Integer</code>.
+	 * 
+	 * <p>
+	 * The service ranking is used by the Framework to determine the <i>natural
+	 * order</i> of services, see {@link ServiceReference#compareTo(Object)},
+	 * and the <i>default</i> service to be returned from a call to the
+	 * {@link BundleContext#getServiceReference} method.
+	 * 
+	 * <p>
+	 * The default ranking is zero (0). A service with a ranking of
+	 * <code>Integer.MAX_VALUE</code> is very likely to be returned as the
+	 * default service, whereas a service with a ranking of
+	 * <code>Integer.MIN_VALUE</code> is very unlikely to be returned.
+	 * 
+	 * <p>
+	 * If the supplied property value is not of type <code>Integer</code>, it is
+	 * deemed to have a ranking value of zero.
+	 */
+	public static final String	SERVICE_RANKING							= "service.ranking";
+
+	/**
+	 * Service property identifying a service's vendor.
+	 * 
+	 * <p>
+	 * This property may be supplied in the properties <code>Dictionary</code>
+	 * object passed to the <code>BundleContext.registerService</code> method.
+	 */
+	public static final String	SERVICE_VENDOR							= "service.vendor";
+
+	/**
+	 * Service property identifying a service's description.
+	 * 
+	 * <p>
+	 * This property may be supplied in the properties <code>Dictionary</code>
+	 * object passed to the <code>BundleContext.registerService</code> method.
+	 */
+	public static final String	SERVICE_DESCRIPTION						= "service.description"; 
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/Filter.java b/org.osgi.core/src/main/java/org/osgi/framework/Filter.java
index 41b7cfa..81c3e5b 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/Filter.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/Filter.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/Filter.java,v 1.16 2007/02/21 16:49:05 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -22,12 +20,13 @@
 /**
  * An RFC 1960-based Filter.
  * <p>
- * <code>Filter</code> objects can be created by calling
- * {@link BundleContext#createFilter} with the chosen filter string.
+ * <code>Filter</code>s can be created by calling
+ * {@link BundleContext#createFilter} or {@link FrameworkUtil#createFilter} with
+ * a filter string.
  * <p>
- * A <code>Filter</code> object can be used numerous times to determine if the
- * match argument matches the filter string that was used to create the
- * <code>Filter</code> object.
+ * A <code>Filter</code> can be used numerous times to determine if the match
+ * argument matches the filter string that was used to create the
+ * <code>Filter</code>.
  * <p>
  * Some examples of LDAP filters are:
  * 
@@ -39,86 +38,85 @@
  * </pre>
  * 
  * @since 1.1
- * @see "Core Specification, section 5.5, for a description of the filter string
- *      syntax."
+ * @see "Core Specification, section 5.5, for a description of the filter string syntax."
  * @ThreadSafe
- * @version $Revision: 1.16 $
+ * @version $Revision: 6860 $
  */
 public interface Filter {
 	/**
 	 * Filter using a service's properties.
 	 * <p>
-	 * The filter is executed using the keys and values of the referenced
-	 * service's properties. The keys are case insensitively matched with the
-	 * filter.
+	 * This <code>Filter</code> is executed using the keys and values of the
+	 * referenced service's properties. The keys are case insensitively matched
+	 * with this <code>Filter</code>.
 	 * 
 	 * @param reference The reference to the service whose properties are used
 	 *        in the match.
-	 * 
 	 * @return <code>true</code> if the service's properties match this
-	 *         filter; <code>false</code> otherwise.
+	 *         <code>Filter</code>; <code>false</code> otherwise.
 	 */
 	public boolean match(ServiceReference reference);
 
 	/**
-	 * Filter using a <code>Dictionary</code> object. The Filter is executed
-	 * using the <code>Dictionary</code> object's keys and values. The keys
-	 * are case insensitively matched with the filter.
+	 * Filter using a <code>Dictionary</code>. This <code>Filter</code> is
+	 * executed using the specified <code>Dictionary</code>'s keys and values.
+	 * The keys are case insensitively matched with this <code>Filter</code>.
 	 * 
-	 * @param dictionary The <code>Dictionary</code> object whose keys are
-	 *        used in the match.
-	 * 
-	 * @return <code>true</code> if the <code>Dictionary</code> object's
-	 *         keys and values match this filter; <code>false</code>
-	 *         otherwise.
-	 * 
-	 * @throws IllegalArgumentException If <code>dictionary</code> contains
-	 *         case variants of the same key name.
+	 * @param dictionary The <code>Dictionary</code> whose keys are used in the
+	 *        match.
+	 * @return <code>true</code> if the <code>Dictionary</code>'s keys and
+	 *         values match this filter; <code>false</code> otherwise.
+	 * @throws IllegalArgumentException If <code>dictionary</code> contains case
+	 *         variants of the same key name.
 	 */
 	public boolean match(Dictionary dictionary);
 
 	/**
-	 * Returns this <code>Filter</code> object's filter string.
+	 * Returns this <code>Filter</code>'s filter string.
 	 * <p>
 	 * The filter string is normalized by removing whitespace which does not
 	 * affect the meaning of the filter.
 	 * 
-	 * @return Filter string.
+	 * @return This <code>Filter</code>'s filter string.
 	 */
 	public String toString();
 
 	/**
-	 * Compares this <code>Filter</code> object to another object.
+	 * Compares this <code>Filter</code> to another <code>Filter</code>.
 	 * 
-	 * @param obj The object to compare against this <code>Filter</code>
-	 *        object.
+	 * <p>
+	 * This method returns the result of calling
+	 * <code>this.toString().equals(obj.toString())</code>.
 	 * 
-	 * @return If the other object is a <code>Filter</code> object, then
-	 *         returns <code>this.toString().equals(obj.toString()</code>;<code>false</code>
-	 *         otherwise.
+	 * @param obj The object to compare against this <code>Filter</code>.
+	 * @return If the other object is a <code>Filter</code> object, then returns
+	 *         the result of calling
+	 *         <code>this.toString().equals(obj.toString())</code>;
+	 *         <code>false</code> otherwise.
 	 */
 	public boolean equals(Object obj);
 
 	/**
-	 * Returns the hashCode for this <code>Filter</code> object.
+	 * Returns the hashCode for this <code>Filter</code>.
 	 * 
-	 * @return The hashCode of the filter string; that is,
-	 *         <code>this.toString().hashCode()</code>.
+	 * <p>
+	 * This method returns the result of calling
+	 * <code>this.toString().hashCode()</code>.
+	 * 
+	 * @return The hashCode of this <code>Filter</code>.
 	 */
 	public int hashCode();
 
 	/**
-	 * Filter with case sensitivity using a <code>Dictionary</code> object.
-	 * The Filter is executed using the <code>Dictionary</code> object's keys
-	 * and values. The keys are case sensitively matched with the filter.
+	 * Filter with case sensitivity using a <code>Dictionary</code>. This
+	 * <code>Filter</code> is executed using the specified
+	 * <code>Dictionary</code>'s keys and values. The keys are case sensitively
+	 * matched with this <code>Filter</code>.
 	 * 
-	 * @param dictionary The <code>Dictionary</code> object whose keys are
-	 *        used in the match.
-	 * 
-	 * @return <code>true</code> if the <code>Dictionary</code> object's
-	 *         keys and values match this filter; <code>false</code>
-	 *         otherwise.
-	 * 
+	 * @param dictionary The <code>Dictionary</code> whose keys are used in the
+	 *        match.
+	 * @return <code>true</code> if the <code>Dictionary</code>'s keys and
+	 *         values match this filter; <code>false</code> otherwise.
 	 * @since 1.3
 	 */
 	public boolean matchCase(Dictionary dictionary);
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkEvent.java b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkEvent.java
index c3da54f..747b249 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkEvent.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkEvent.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/FrameworkEvent.java,v 1.15 2007/02/20 00:14:12 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2004, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). 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.
@@ -25,8 +23,8 @@
  * 
  * <p>
  * <code>FrameworkEvent</code> objects are delivered to
- * <code>FrameworkListener</code>s when a general event occurs within the
- * OSGi environment. A type code is used to identify the event type for future
+ * <code>FrameworkListener</code>s when a general event occurs within the OSGi
+ * environment. A type code is used to identify the event type for future
  * extendability.
  * 
  * <p>
@@ -34,11 +32,11 @@
  * 
  * @Immutable
  * @see FrameworkListener
- * @version $Revision: 1.15 $
+ * @version $Revision: 6542 $
  */
 
 public class FrameworkEvent extends EventObject {
-	static final long		serialVersionUID	= 207051004521261705L;
+	static final long		serialVersionUID				= 207051004521261705L;
 	/**
 	 * Bundle related to the event.
 	 */
@@ -60,25 +58,20 @@
 	 * <p>
 	 * This event is fired when the Framework has started after all installed
 	 * bundles that are marked to be started have been started and the Framework
-	 * has reached the intitial start level.
+	 * has reached the initial start level. The source of this event is the
+	 * System Bundle.
 	 * 
-	 * <p>
-	 * The value of <code>STARTED</code> is 0x00000001.
-	 * 
-	 * @see "<code>StartLevel</code>"
+	 * @see "The Start Level Service"
 	 */
-	public final static int	STARTED				= 0x00000001;
+	public final static int	STARTED							= 0x00000001;
 
 	/**
 	 * An error has occurred.
 	 * 
 	 * <p>
 	 * There was an error associated with a bundle.
-	 * 
-	 * <p>
-	 * The value of <code>ERROR</code> is 0x00000002.
 	 */
-	public final static int	ERROR				= 0x00000002;
+	public final static int	ERROR							= 0x00000002;
 
 	/**
 	 * A PackageAdmin.refreshPackage operation has completed.
@@ -86,14 +79,12 @@
 	 * <p>
 	 * This event is fired when the Framework has completed the refresh packages
 	 * operation initiated by a call to the PackageAdmin.refreshPackages method.
-	 * 
-	 * <p>
-	 * The value of <code>PACKAGES_REFRESHED</code> is 0x00000004.
+	 * The source of this event is the System Bundle.
 	 * 
 	 * @since 1.2
 	 * @see "<code>PackageAdmin.refreshPackages</code>"
 	 */
-	public final static int	PACKAGES_REFRESHED	= 0x00000004;
+	public final static int	PACKAGES_REFRESHED				= 0x00000004;
 
 	/**
 	 * A StartLevel.setStartLevel operation has completed.
@@ -101,14 +92,12 @@
 	 * <p>
 	 * This event is fired when the Framework has completed changing the active
 	 * start level initiated by a call to the StartLevel.setStartLevel method.
-	 * 
-	 * <p>
-	 * The value of <code>STARTLEVEL_CHANGED</code> is 0x00000008.
+	 * The source of this event is the System Bundle.
 	 * 
 	 * @since 1.2
-	 * @see "<code>StartLevel</code>"
+	 * @see "The Start Level Service"
 	 */
-	public final static int	STARTLEVEL_CHANGED	= 0x00000008;
+	public final static int	STARTLEVEL_CHANGED				= 0x00000008;
 
 	/**
 	 * A warning has occurred.
@@ -116,12 +105,9 @@
 	 * <p>
 	 * There was a warning associated with a bundle.
 	 * 
-	 * <p>
-	 * The value of <code>WARNING</code> is 0x00000010.
-	 * 
 	 * @since 1.3
 	 */
-	public final static int	WARNING				= 0x00000010;
+	public final static int	WARNING							= 0x00000010;
 
 	/**
 	 * An informational event has occurred.
@@ -129,12 +115,56 @@
 	 * <p>
 	 * There was an informational event associated with a bundle.
 	 * 
-	 * <p>
-	 * The value of <code>INFO</code> is 0x00000020.
-	 * 
 	 * @since 1.3
 	 */
-	public final static int	INFO				= 0x00000020;
+	public final static int	INFO							= 0x00000020;
+
+	/**
+	 * The Framework has stopped.
+	 * 
+	 * <p>
+	 * This event is fired when the Framework has been stopped because of a stop
+	 * operation on the system bundle. The source of this event is the System
+	 * Bundle.
+	 * 
+	 * @since 1.5
+	 */
+	public final static int	STOPPED							= 0x00000040;
+
+	/**
+	 * The Framework has stopped during update.
+	 * 
+	 * <p>
+	 * This event is fired when the Framework has been stopped because of an
+	 * update operation on the system bundle. The Framework will be restarted
+	 * after this event is fired. The source of this event is the System Bundle.
+	 * 
+	 * @since 1.5
+	 */
+	public final static int	STOPPED_UPDATE					= 0x00000080;
+
+	/**
+	 * The Framework has stopped and the boot class path has changed.
+	 * 
+	 * <p>
+	 * This event is fired when the Framework has been stopped because of a stop
+	 * operation on the system bundle and a bootclasspath extension bundle has
+	 * been installed or updated. The source of this event is the System Bundle.
+	 * 
+	 * @since 1.5
+	 */
+	public final static int	STOPPED_BOOTCLASSPATH_MODIFIED	= 0x00000100;
+
+	/**
+	 * The Framework did not stop before the wait timeout expired.
+	 * 
+	 * <p>
+	 * This event is fired when the Framework did not stop before the wait
+	 * timeout expired. The source of this event is the System Bundle.
+	 * 
+	 * @since 1.5
+	 */
+	public final static int	WAIT_TIMEDOUT					= 0x00000200;
 
 	/**
 	 * Creates a Framework event.
@@ -197,6 +227,10 @@
 	 * <li>{@link #INFO}
 	 * <li>{@link #PACKAGES_REFRESHED}
 	 * <li>{@link #STARTLEVEL_CHANGED}
+	 * <li>{@link #STOPPED}
+	 * <li>{@link #STOPPED_BOOTCLASSPATH_MODIFIED}
+	 * <li>{@link #STOPPED_UPDATE}
+	 * <li>{@link #WAIT_TIMEDOUT}
 	 * </ul>
 	 * 
 	 * @return The type of state change.
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkListener.java b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkListener.java
index 29c934d..c96c490 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkListener.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkListener.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/FrameworkListener.java,v 1.12 2007/02/21 16:49:05 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). 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.
@@ -37,7 +35,7 @@
  * 
  * @see FrameworkEvent
  * @NotThreadSafe
- * @version $Revision: 1.12 $
+ * @version $Revision: 5673 $
  */
 
 public interface FrameworkListener extends EventListener {
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkUtil.java b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkUtil.java
index fdefc52..13391ca 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkUtil.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkUtil.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/FrameworkUtil.java,v 1.10 2007/02/21 16:49:05 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2005, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2009). 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.
@@ -18,9 +16,19 @@
 
 package org.osgi.framework;
 
-import java.lang.reflect.*;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
 
 /**
  * Framework Utility class.
@@ -31,117 +39,2117 @@
  * 
  * @since 1.3
  * @ThreadSafe
- * @version $Revision: 1.10 $
+ * @version $Revision: 6888 $
  */
 public class FrameworkUtil {
-	/*
-	 * NOTE: A framework implementor may also choose to replace this class in
-	 * their distribution with a class that directly interfaces with the
-	 * framework implementation.
+	/**
+	 * FrameworkUtil objects may not be constructed.
 	 */
-
-	/*
-	 * This class will load the FrameworkUtil class in the package named by the
-	 * org.osgi.vendor.framework package. For each instance of this class, an
-	 * instance of the vendor FrameworkUtil class will be created and this class
-	 * will delegate method calls to the vendor FrameworkUtil instance.
-	 */
-
-	private static class ImplHolder implements PrivilegedAction {
-		private static final String	packageProperty	= "org.osgi.vendor.framework";
-		
-		/*
-		 * This is the delegate method used by createFilter.
-		 */
-		static final Method	createFilter;
-		
-		static {
-			createFilter = (Method) AccessController.doPrivileged(new ImplHolder());
-		}
-		
-		private ImplHolder() {
-		}
-
-		public Object run() {
-			String packageName = System
-			.getProperty(packageProperty);
-			if (packageName == null) {
-				throw new NoClassDefFoundError(packageProperty
-						+ " property not set");
-			}
-			
-			Class delegateClass;
-			try {
-				delegateClass = Class.forName(packageName
-						+ ".FrameworkUtil");
-			}
-			catch (ClassNotFoundException e) {
-				throw new NoClassDefFoundError(e.toString());
-			}
-			
-			Method result;
-			try {
-				result = delegateClass.getMethod("createFilter",
-						new Class[] {String.class});
-			}
-			catch (NoSuchMethodException e) {
-				throw new NoSuchMethodError(e.toString());
-			}
-			
-			if (!Modifier.isStatic(result.getModifiers())) {
-				throw new NoSuchMethodError(
-				"createFilter method must be static");
-			}
-			
-			return result;
-		}
+	private FrameworkUtil() {
+		// private empty constructor to prevent construction
 	}
 
-	
 	/**
-	 * FrameworkUtil objects may not be constructed. 
-	 */
-	private FrameworkUtil() {}
-	
-	/**
-	 * Creates a <code>Filter</code> object. This <code>Filter</code> object
-	 * may be used to match a <code>ServiceReference</code> object or a
+	 * Creates a <code>Filter</code> object. This <code>Filter</code> object may
+	 * be used to match a <code>ServiceReference</code> object or a
 	 * <code>Dictionary</code> object.
 	 * 
 	 * <p>
 	 * If the filter cannot be parsed, an {@link InvalidSyntaxException} will be
 	 * thrown with a human readable message where the filter became unparsable.
 	 * 
+	 * <p>
+	 * This method returns a Filter implementation which may not perform as well
+	 * as the framework implementation-specific Filter implementation returned
+	 * by {@link BundleContext#createFilter(String)}.
+	 * 
 	 * @param filter The filter string.
 	 * @return A <code>Filter</code> object encapsulating the filter string.
-	 * @throws InvalidSyntaxException If <code>filter</code> contains an
-	 *         invalid filter string that cannot be parsed.
+	 * @throws InvalidSyntaxException If <code>filter</code> contains an invalid
+	 *         filter string that cannot be parsed.
 	 * @throws NullPointerException If <code>filter</code> is null.
 	 * 
 	 * @see Filter
 	 */
 	public static Filter createFilter(String filter)
 			throws InvalidSyntaxException {
-		try {
+		return FilterImpl.newInstance(filter);
+	}
+
+	/**
+	 * Match a Distinguished Name (DN) chain against a pattern. DNs can be
+	 * matched using wildcards. A wildcard ('*' &#92;u002A) replaces all
+	 * possible values. Due to the structure of the DN, the comparison is more
+	 * complicated than string-based wildcard matching.
+	 * <p>
+	 * A wildcard can stand for zero or more DNs in a chain, a number of
+	 * relative distinguished names (RDNs) within a DN, or the value of a single
+	 * RDN. The DNs in the chain and the matching pattern are canonicalized
+	 * before processing. This means, among other things, that spaces must be
+	 * ignored, except in values.
+	 * <p>
+	 * The format of a wildcard match pattern is:
+	 * 
+	 * <pre>
+	 * matchPattern	::= dn-match ( ';' dn-match ) *
+	 * dn-match 	::= ( '*' | rdn-match ) ( ',' rdn-match ) * | '-'
+	 * rdn-match 	::= name '=' value-match
+	 * value-match 	::= '*' | value-star
+	 * value-star 	::= &lt; value, requires escaped '*' and '-' &gt;
+	 * </pre>
+	 * <p>
+	 * The most simple case is a single wildcard; it must match any DN. A
+	 * wildcard can also replace the first list of RDNs of a DN. The first RDNs
+	 * are the least significant. Such lists of matched RDNs can be empty.
+	 * <p>
+	 * For example, a match pattern with a wildcard that matches all all DNs
+	 * that end with RDNs of o=ACME and c=US would look like this:
+	 * 
+	 * <pre>
+	 * *, o=ACME, c=US
+	 * </pre>
+	 * 
+	 * This match pattern would match the following DNs:
+	 * 
+	 * <pre>
+	 * cn = Bugs Bunny, o = ACME, c = US
+	 * ou = Carrots, cn=Daffy Duck, o=ACME, c=US
+	 * street = 9C\, Avenue St. Drézéry, o=ACME, c=US
+	 * dc=www, dc=acme, dc=com, o=ACME, c=US
+	 * o=ACME, c=US
+	 * </pre>
+	 * 
+	 * The following DNs would not match:
+	 * 
+	 * <pre>
+	 * street = 9C\, Avenue St. Drézéry, o=ACME, c=FR
+	 * dc=www, dc=acme, dc=com, c=US
+	 * </pre>
+	 * 
+	 * If a wildcard is used for a value of an RDN, the value must be exactly *.
+	 * The wildcard must match any value, and no substring matching must be
+	 * done. For example:
+	 * 
+	 * <pre>
+	 * cn=*,o=ACME,c=*
+	 * </pre>
+	 * 
+	 * This match pattern with wildcard must match the following DNs:
+	 * 
+	 * <pre>
+	 * cn=Bugs Bunny,o=ACME,c=US
+	 * cn = Daffy Duck , o = ACME , c = US
+	 * cn=Road Runner, o=ACME, c=NL
+	 * </pre>
+	 * 
+	 * But not:
+	 * 
+	 * <pre>
+	 * o=ACME, c=NL
+	 * dc=acme.com, cn=Bugs Bunny, o=ACME, c=US
+	 * </pre>
+	 * 
+	 * <p>
+	 * A match pattern may contain a chain of DN match patterns. The
+	 * semicolon(';' &#92;u003B) must be used to separate DN match patterns in a
+	 * chain. Wildcards can also be used to match against a complete DN within a
+	 * chain.
+	 * <p>
+	 * The following example matches a certificate signed by Tweety Inc. in the
+	 * US.
+	 * </p>
+	 * 
+	 * <pre>
+	 * * ; ou=S &amp; V, o=Tweety Inc., c=US
+	 * </pre>
+	 * <p>
+	 * The wildcard ('*') matches zero or one DN in the chain, however,
+	 * sometimes it is necessary to match a longer chain. The minus sign ('-'
+	 * &#92;u002D) represents zero or more DNs, whereas the asterisk only
+	 * represents a single DN. For example, to match a DN where the Tweety Inc.
+	 * is in the DN chain, use the following expression:
+	 * </p>
+	 * 
+	 * <pre>
+	 * - ; *, o=Tweety Inc., c=US
+	 * </pre>
+	 * 
+	 * @param matchPattern The pattern against which to match the DN chain.
+	 * @param dnChain The DN chain to match against the specified pattern. Each
+	 *        element of the chain must be of type <code>String</code> and use
+	 *        the format defined in RFC 2253.
+	 * @return <code>true</code> If the pattern matches the DN chain; otherwise
+	 *         <code>false</code> is returned.
+	 * @throws IllegalArgumentException If the specified match pattern or DN
+	 *         chain is invalid.
+	 * @since 1.5
+	 */
+	public static boolean matchDistinguishedNameChain(String matchPattern,
+			List /* <String> */dnChain) {
+		return DNChainMatching.match(matchPattern, new ArrayList(dnChain));
+	}
+
+	/**
+	 * Return a <code>Bundle</code> for the specified bundle class. The returned
+	 * <code>Bundle</code> is the bundle associated with the bundle class loader
+	 * which defined the specified class.
+	 * 
+	 * @param classFromBundle A class defined by a bundle class loader.
+	 * @return A <code>Bundle</code> for the specified bundle class or
+	 *         <code>null</code> if the specified class was not defined by a
+	 *         bundle class loader.
+	 * @since 1.5
+	 */
+	public static Bundle getBundle(final Class classFromBundle) {
+		// We use doPriv since the caller may not have permission
+		// to call getClassLoader.
+		Object cl = AccessController.doPrivileged(new PrivilegedAction() {
+			public Object run() {
+				return classFromBundle.getClassLoader();
+			}
+		});
+
+		if (cl instanceof BundleReference) {
+			return ((BundleReference) cl).getBundle();
+		}
+		return null;
+	}
+
+	/**
+	 * RFC 1960-based Filter. Filter objects can be created by calling the
+	 * constructor with the desired filter string. A Filter object can be called
+	 * numerous times to determine if the match argument matches the filter
+	 * string that was used to create the Filter object.
+	 * 
+	 * <p>
+	 * The syntax of a filter string is the string representation of LDAP search
+	 * filters as defined in RFC 1960: <i>A String Representation of LDAP Search
+	 * Filters</i> (available at http://www.ietf.org/rfc/rfc1960.txt). It should
+	 * be noted that RFC 2254: <i>A String Representation of LDAP Search
+	 * Filters</i> (available at http://www.ietf.org/rfc/rfc2254.txt) supersedes
+	 * RFC 1960 but only adds extensible matching and is not applicable for this
+	 * API.
+	 * 
+	 * <p>
+	 * The string representation of an LDAP search filter is defined by the
+	 * following grammar. It uses a prefix format.
+	 * 
+	 * <pre>
+	 *   &lt;filter&gt; ::= '(' &lt;filtercomp&gt; ')'
+	 *   &lt;filtercomp&gt; ::= &lt;and&gt; | &lt;or&gt; | &lt;not&gt; | &lt;item&gt;
+	 *   &lt;and&gt; ::= '&amp;' &lt;filterlist&gt;
+	 *   &lt;or&gt; ::= '|' &lt;filterlist&gt;
+	 *   &lt;not&gt; ::= '!' &lt;filter&gt;
+	 *   &lt;filterlist&gt; ::= &lt;filter&gt; | &lt;filter&gt; &lt;filterlist&gt;
+	 *   &lt;item&gt; ::= &lt;simple&gt; | &lt;present&gt; | &lt;substring&gt;
+	 *   &lt;simple&gt; ::= &lt;attr&gt; &lt;filtertype&gt; &lt;value&gt;
+	 *   &lt;filtertype&gt; ::= &lt;equal&gt; | &lt;approx&gt; | &lt;greater&gt; | &lt;less&gt;
+	 *   &lt;equal&gt; ::= '='
+	 *   &lt;approx&gt; ::= '&tilde;='
+	 *   &lt;greater&gt; ::= '&gt;='
+	 *   &lt;less&gt; ::= '&lt;='
+	 *   &lt;present&gt; ::= &lt;attr&gt; '=*'
+	 *   &lt;substring&gt; ::= &lt;attr&gt; '=' &lt;initial&gt; &lt;any&gt; &lt;final&gt;
+	 *   &lt;initial&gt; ::= NULL | &lt;value&gt;
+	 *   &lt;any&gt; ::= '*' &lt;starval&gt;
+	 *   &lt;starval&gt; ::= NULL | &lt;value&gt; '*' &lt;starval&gt;
+	 *   &lt;final&gt; ::= NULL | &lt;value&gt;
+	 * </pre>
+	 * 
+	 * <code>&lt;attr&gt;</code> is a string representing an attribute, or key,
+	 * in the properties objects of the registered services. Attribute names are
+	 * not case sensitive; that is cn and CN both refer to the same attribute.
+	 * <code>&lt;value&gt;</code> is a string representing the value, or part of
+	 * one, of a key in the properties objects of the registered services. If a
+	 * <code>&lt;value&gt;</code> must contain one of the characters '
+	 * <code>*</code>' or '<code>(</code>' or '<code>)</code>', these characters
+	 * should be escaped by preceding them with the backslash '<code>\</code>'
+	 * character. Note that although both the <code>&lt;substring&gt;</code> and
+	 * <code>&lt;present&gt;</code> productions can produce the <code>'attr=*'</code>
+	 * construct, this construct is used only to denote a presence filter.
+	 * 
+	 * <p>
+	 * Examples of LDAP filters are:
+	 * 
+	 * <pre>
+	 *   &quot;(cn=Babs Jensen)&quot;
+	 *   &quot;(!(cn=Tim Howes))&quot;
+	 *   &quot;(&amp;(&quot; + Constants.OBJECTCLASS + &quot;=Person)(|(sn=Jensen)(cn=Babs J*)))&quot;
+	 *   &quot;(o=univ*of*mich*)&quot;
+	 * </pre>
+	 * 
+	 * <p>
+	 * The approximate match (<code>~=</code>) is implementation specific but
+	 * should at least ignore case and white space differences. Optional are
+	 * codes like soundex or other smart "closeness" comparisons.
+	 * 
+	 * <p>
+	 * Comparison of values is not straightforward. Strings are compared
+	 * differently than numbers and it is possible for a key to have multiple
+	 * values. Note that that keys in the match argument must always be strings.
+	 * The comparison is defined by the object type of the key's value. The
+	 * following rules apply for comparison:
+	 * 
+	 * <blockquote>
+	 * <TABLE BORDER=0>
+	 * <TR>
+	 * <TD><b>Property Value Type </b></TD>
+	 * <TD><b>Comparison Type</b></TD>
+	 * </TR>
+	 * <TR>
+	 * <TD>String</TD>
+	 * <TD>String comparison</TD>
+	 * </TR>
+	 * <TR valign=top>
+	 * <TD>Integer, Long, Float, Double, Byte, Short, BigInteger, BigDecimal</TD>
+	 * <TD>numerical comparison</TD>
+	 * </TR>
+	 * <TR>
+	 * <TD>Character</TD>
+	 * <TD>character comparison</TD>
+	 * </TR>
+	 * <TR>
+	 * <TD>Boolean</TD>
+	 * <TD>equality comparisons only</TD>
+	 * </TR>
+	 * <TR>
+	 * <TD>[] (array)</TD>
+	 * <TD>recursively applied to values</TD>
+	 * </TR>
+	 * <TR>
+	 * <TD>Collection</TD>
+	 * <TD>recursively applied to values</TD>
+	 * </TR>
+	 * </TABLE>
+	 * Note: arrays of primitives are also supported. </blockquote>
+	 * 
+	 * A filter matches a key that has multiple values if it matches at least
+	 * one of those values. For example,
+	 * 
+	 * <pre>
+	 * Dictionary d = new Hashtable();
+	 * d.put(&quot;cn&quot;, new String[] {&quot;a&quot;, &quot;b&quot;, &quot;c&quot;});
+	 * </pre>
+	 * 
+	 * d will match <code>(cn=a)</code> and also <code>(cn=b)</code>
+	 * 
+	 * <p>
+	 * A filter component that references a key having an unrecognizable data
+	 * type will evaluate to <code>false</code> .
+	 */
+	private static class FilterImpl implements Filter {
+		/* filter operators */
+		private static final int			EQUAL		= 1;
+		private static final int			APPROX		= 2;
+		private static final int			GREATER		= 3;
+		private static final int			LESS		= 4;
+		private static final int			PRESENT		= 5;
+		private static final int			SUBSTRING	= 6;
+		private static final int			AND			= 7;
+		private static final int			OR			= 8;
+		private static final int			NOT			= 9;
+
+		/** filter operation */
+		private final int					op;
+		/** filter attribute or null if operation AND, OR or NOT */
+		private final String				attr;
+		/** filter operands */
+		private final Object				value;
+
+		/* normalized filter string for Filter object */
+		private transient volatile String	filterString;
+
+		/**
+		 * Constructs a {@link FilterImpl} object. This filter object may be
+		 * used to match a {@link ServiceReference} or a Dictionary.
+		 * 
+		 * <p>
+		 * If the filter cannot be parsed, an {@link InvalidSyntaxException}
+		 * will be thrown with a human readable message where the filter became
+		 * unparsable.
+		 * 
+		 * @param filterString the filter string.
+		 * @exception InvalidSyntaxException If the filter parameter contains an
+		 *            invalid filter string that cannot be parsed.
+		 */
+		static FilterImpl newInstance(String filterString)
+				throws InvalidSyntaxException {
+			return new Parser(filterString).parse();
+		}
+
+		FilterImpl(int operation, String attr, Object value) {
+			this.op = operation;
+			this.attr = attr;
+			this.value = value;
+		}
+
+		/**
+		 * Filter using a service's properties.
+		 * <p>
+		 * This <code>Filter</code> is executed using the keys and values of the
+		 * referenced service's properties. The keys are case insensitively
+		 * matched with this <code>Filter</code>.
+		 * 
+		 * @param reference The reference to the service whose properties are
+		 *        used in the match.
+		 * @return <code>true</code> if the service's properties match this
+		 *         <code>Filter</code>; <code>false</code> otherwise.
+		 */
+		public boolean match(ServiceReference reference) {
+			return match0(new ServiceReferenceDictionary(reference));
+		}
+
+		/**
+		 * Filter using a <code>Dictionary</code>. This <code>Filter</code> is
+		 * executed using the specified <code>Dictionary</code>'s keys and
+		 * values. The keys are case insensitively matched with this
+		 * <code>Filter</code>.
+		 * 
+		 * @param dictionary The <code>Dictionary</code> whose keys are used in
+		 *        the match.
+		 * @return <code>true</code> if the <code>Dictionary</code>'s keys and
+		 *         values match this filter; <code>false</code> otherwise.
+		 * @throws IllegalArgumentException If <code>dictionary</code> contains
+		 *         case variants of the same key name.
+		 */
+		public boolean match(Dictionary dictionary) {
+			return match0(new CaseInsensitiveDictionary(dictionary));
+		}
+
+		/**
+		 * Filter with case sensitivity using a <code>Dictionary</code>. This
+		 * <code>Filter</code> is executed using the specified
+		 * <code>Dictionary</code>'s keys and values. The keys are case
+		 * sensitively matched with this <code>Filter</code>.
+		 * 
+		 * @param dictionary The <code>Dictionary</code> whose keys are used in
+		 *        the match.
+		 * @return <code>true</code> if the <code>Dictionary</code>'s keys and
+		 *         values match this filter; <code>false</code> otherwise.
+		 * @since 1.3
+		 */
+		public boolean matchCase(Dictionary dictionary) {
+			return match0(dictionary);
+		}
+
+		/**
+		 * Returns this <code>Filter</code>'s filter string.
+		 * <p>
+		 * The filter string is normalized by removing whitespace which does not
+		 * affect the meaning of the filter.
+		 * 
+		 * @return This <code>Filter</code>'s filter string.
+		 */
+		public String toString() {
+			String result = filterString;
+			if (result == null) {
+				filterString = result = normalize();
+			}
+			return result;
+		}
+
+		/**
+		 * Returns this <code>Filter</code>'s normalized filter string.
+		 * <p>
+		 * The filter string is normalized by removing whitespace which does not
+		 * affect the meaning of the filter.
+		 * 
+		 * @return This <code>Filter</code>'s filter string.
+		 */
+		private String normalize() {
+			StringBuffer sb = new StringBuffer();
+			sb.append('(');
+
+			switch (op) {
+				case AND : {
+					sb.append('&');
+
+					FilterImpl[] filters = (FilterImpl[]) value;
+					for (int i = 0, size = filters.length; i < size; i++) {
+						sb.append(filters[i].normalize());
+					}
+
+					break;
+				}
+
+				case OR : {
+					sb.append('|');
+
+					FilterImpl[] filters = (FilterImpl[]) value;
+					for (int i = 0, size = filters.length; i < size; i++) {
+						sb.append(filters[i].normalize());
+					}
+
+					break;
+				}
+
+				case NOT : {
+					sb.append('!');
+					FilterImpl filter = (FilterImpl) value;
+					sb.append(filter.normalize());
+
+					break;
+				}
+
+				case SUBSTRING : {
+					sb.append(attr);
+					sb.append('=');
+
+					String[] substrings = (String[]) value;
+
+					for (int i = 0, size = substrings.length; i < size; i++) {
+						String substr = substrings[i];
+
+						if (substr == null) /* * */{
+							sb.append('*');
+						}
+						else /* xxx */{
+							sb.append(encodeValue(substr));
+						}
+					}
+
+					break;
+				}
+				case EQUAL : {
+					sb.append(attr);
+					sb.append('=');
+					sb.append(encodeValue((String) value));
+
+					break;
+				}
+				case GREATER : {
+					sb.append(attr);
+					sb.append(">=");
+					sb.append(encodeValue((String) value));
+
+					break;
+				}
+				case LESS : {
+					sb.append(attr);
+					sb.append("<=");
+					sb.append(encodeValue((String) value));
+
+					break;
+				}
+				case APPROX : {
+					sb.append(attr);
+					sb.append("~=");
+					sb.append(encodeValue(approxString((String) value)));
+
+					break;
+				}
+
+				case PRESENT : {
+					sb.append(attr);
+					sb.append("=*");
+
+					break;
+				}
+			}
+
+			sb.append(')');
+
+			return sb.toString();
+		}
+
+		/**
+		 * Compares this <code>Filter</code> to another <code>Filter</code>.
+		 * 
+		 * <p>
+		 * This implementation returns the result of calling
+		 * <code>this.toString().equals(obj.toString()</code>.
+		 * 
+		 * @param obj The object to compare against this <code>Filter</code>.
+		 * @return If the other object is a <code>Filter</code> object, then
+		 *         returns the result of calling
+		 *         <code>this.toString().equals(obj.toString()</code>;
+		 *         <code>false</code> otherwise.
+		 */
+		public boolean equals(Object obj) {
+			if (obj == this) {
+				return true;
+			}
+
+			if (!(obj instanceof Filter)) {
+				return false;
+			}
+
+			return this.toString().equals(obj.toString());
+		}
+
+		/**
+		 * Returns the hashCode for this <code>Filter</code>.
+		 * 
+		 * <p>
+		 * This implementation returns the result of calling
+		 * <code>this.toString().hashCode()</code>.
+		 * 
+		 * @return The hashCode of this <code>Filter</code>.
+		 */
+		public int hashCode() {
+			return this.toString().hashCode();
+		}
+
+		/**
+		 * Internal match routine. Dictionary parameter must support
+		 * case-insensitive get.
+		 * 
+		 * @param properties A dictionary whose keys are used in the match.
+		 * @return If the Dictionary's keys match the filter, return
+		 *         <code>true</code>. Otherwise, return <code>false</code>.
+		 */
+		private boolean match0(Dictionary properties) {
+			switch (op) {
+				case AND : {
+					FilterImpl[] filters = (FilterImpl[]) value;
+					for (int i = 0, size = filters.length; i < size; i++) {
+						if (!filters[i].match0(properties)) {
+							return false;
+						}
+					}
+
+					return true;
+				}
+
+				case OR : {
+					FilterImpl[] filters = (FilterImpl[]) value;
+					for (int i = 0, size = filters.length; i < size; i++) {
+						if (filters[i].match0(properties)) {
+							return true;
+						}
+					}
+
+					return false;
+				}
+
+				case NOT : {
+					FilterImpl filter = (FilterImpl) value;
+
+					return !filter.match0(properties);
+				}
+
+				case SUBSTRING :
+				case EQUAL :
+				case GREATER :
+				case LESS :
+				case APPROX : {
+					Object prop = (properties == null) ? null : properties
+							.get(attr);
+
+					return compare(op, prop, value);
+				}
+
+				case PRESENT : {
+					Object prop = (properties == null) ? null : properties
+							.get(attr);
+
+					return prop != null;
+				}
+			}
+
+			return false;
+		}
+
+		/**
+		 * Encode the value string such that '(', '*', ')' and '\' are escaped.
+		 * 
+		 * @param value unencoded value string.
+		 * @return encoded value string.
+		 */
+		private static String encodeValue(String value) {
+			boolean encoded = false;
+			int inlen = value.length();
+			int outlen = inlen << 1; /* inlen 2 */
+
+			char[] output = new char[outlen];
+			value.getChars(0, inlen, output, inlen);
+
+			int cursor = 0;
+			for (int i = inlen; i < outlen; i++) {
+				char c = output[i];
+
+				switch (c) {
+					case '(' :
+					case '*' :
+					case ')' :
+					case '\\' : {
+						output[cursor] = '\\';
+						cursor++;
+						encoded = true;
+
+						break;
+					}
+				}
+
+				output[cursor] = c;
+				cursor++;
+			}
+
+			return encoded ? new String(output, 0, cursor) : value;
+		}
+
+		private boolean compare(int operation, Object value1, Object value2) {
+			if (value1 == null) {
+				return false;
+			}
+			if (value1 instanceof String) {
+				return compare_String(operation, (String) value1, value2);
+			}
+
+			Class clazz = value1.getClass();
+			if (clazz.isArray()) {
+				Class type = clazz.getComponentType();
+				if (type.isPrimitive()) {
+					return compare_PrimitiveArray(operation, type, value1,
+							value2);
+				}
+				return compare_ObjectArray(operation, (Object[]) value1, value2);
+			}
+			if (value1 instanceof Collection) {
+				return compare_Collection(operation, (Collection) value1,
+						value2);
+			}
+			if (value1 instanceof Integer) {
+				return compare_Integer(operation,
+						((Integer) value1).intValue(), value2);
+			}
+			if (value1 instanceof Long) {
+				return compare_Long(operation, ((Long) value1).longValue(),
+						value2);
+			}
+			if (value1 instanceof Byte) {
+				return compare_Byte(operation, ((Byte) value1).byteValue(),
+						value2);
+			}
+			if (value1 instanceof Short) {
+				return compare_Short(operation, ((Short) value1).shortValue(),
+						value2);
+			}
+			if (value1 instanceof Character) {
+				return compare_Character(operation, ((Character) value1)
+						.charValue(), value2);
+			}
+			if (value1 instanceof Float) {
+				return compare_Float(operation, ((Float) value1).floatValue(),
+						value2);
+			}
+			if (value1 instanceof Double) {
+				return compare_Double(operation, ((Double) value1)
+						.doubleValue(), value2);
+			}
+			if (value1 instanceof Boolean) {
+				return compare_Boolean(operation, ((Boolean) value1)
+						.booleanValue(), value2);
+			}
+			if (value1 instanceof Comparable) {
+				return compare_Comparable(operation, (Comparable) value1,
+						value2);
+			}
+			return compare_Unknown(operation, value1, value2); // RFC 59
+		}
+
+		private boolean compare_Collection(int operation,
+				Collection collection, Object value2) {
+			for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
+				if (compare(operation, iterator.next(), value2)) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_ObjectArray(int operation, Object[] array,
+				Object value2) {
+			for (int i = 0, size = array.length; i < size; i++) {
+				if (compare(operation, array[i], value2)) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_PrimitiveArray(int operation, Class type,
+				Object primarray, Object value2) {
+			if (Integer.TYPE.isAssignableFrom(type)) {
+				int[] array = (int[]) primarray;
+				for (int i = 0, size = array.length; i < size; i++) {
+					if (compare_Integer(operation, array[i], value2)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Long.TYPE.isAssignableFrom(type)) {
+				long[] array = (long[]) primarray;
+				for (int i = 0, size = array.length; i < size; i++) {
+					if (compare_Long(operation, array[i], value2)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Byte.TYPE.isAssignableFrom(type)) {
+				byte[] array = (byte[]) primarray;
+				for (int i = 0, size = array.length; i < size; i++) {
+					if (compare_Byte(operation, array[i], value2)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Short.TYPE.isAssignableFrom(type)) {
+				short[] array = (short[]) primarray;
+				for (int i = 0, size = array.length; i < size; i++) {
+					if (compare_Short(operation, array[i], value2)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Character.TYPE.isAssignableFrom(type)) {
+				char[] array = (char[]) primarray;
+				for (int i = 0, size = array.length; i < size; i++) {
+					if (compare_Character(operation, array[i], value2)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Float.TYPE.isAssignableFrom(type)) {
+				float[] array = (float[]) primarray;
+				for (int i = 0, size = array.length; i < size; i++) {
+					if (compare_Float(operation, array[i], value2)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Double.TYPE.isAssignableFrom(type)) {
+				double[] array = (double[]) primarray;
+				for (int i = 0, size = array.length; i < size; i++) {
+					if (compare_Double(operation, array[i], value2)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Boolean.TYPE.isAssignableFrom(type)) {
+				boolean[] array = (boolean[]) primarray;
+				for (int i = 0, size = array.length; i < size; i++) {
+					if (compare_Boolean(operation, array[i], value2)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			return false;
+		}
+
+		private boolean compare_String(int operation, String string,
+				Object value2) {
+			switch (operation) {
+				case SUBSTRING : {
+					String[] substrings = (String[]) value2;
+					int pos = 0;
+					for (int i = 0, size = substrings.length; i < size; i++) {
+						String substr = substrings[i];
+
+						if (i + 1 < size) /* if this is not that last substr */{
+							if (substr == null) /* * */{
+								String substr2 = substrings[i + 1];
+
+								if (substr2 == null) /* ** */
+									continue; /* ignore first star */
+								/* xxx */
+								int index = string.indexOf(substr2, pos);
+								if (index == -1) {
+									return false;
+								}
+
+								pos = index + substr2.length();
+								if (i + 2 < size) // if there are more
+									// substrings, increment
+									// over the string we just
+									// matched; otherwise need
+									// to do the last substr
+									// check
+									i++;
+							}
+							else /* xxx */{
+								int len = substr.length();
+								if (string.regionMatches(pos, substr, 0, len)) {
+									pos += len;
+								}
+								else {
+									return false;
+								}
+							}
+						}
+						else /* last substr */{
+							if (substr == null) /* * */{
+								return true;
+							}
+							/* xxx */
+							return string.endsWith(substr);
+						}
+					}
+
+					return true;
+				}
+				case EQUAL : {
+					return string.equals(value2);
+				}
+				case APPROX : {
+					string = approxString(string);
+					String string2 = approxString((String) value2);
+
+					return string.equalsIgnoreCase(string2);
+				}
+				case GREATER : {
+					return string.compareTo((String) value2) >= 0;
+				}
+				case LESS : {
+					return string.compareTo((String) value2) <= 0;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_Integer(int operation, int intval, Object value2) {
+			if (operation == SUBSTRING) {
+				return false;
+			}
+			int intval2 = Integer.parseInt(((String) value2).trim());
+			switch (operation) {
+				case APPROX :
+				case EQUAL : {
+					return intval == intval2;
+				}
+				case GREATER : {
+					return intval >= intval2;
+				}
+				case LESS : {
+					return intval <= intval2;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_Long(int operation, long longval, Object value2) {
+			if (operation == SUBSTRING) {
+				return false;
+			}
+			long longval2 = Long.parseLong(((String) value2).trim());
+			switch (operation) {
+				case APPROX :
+				case EQUAL : {
+					return longval == longval2;
+				}
+				case GREATER : {
+					return longval >= longval2;
+				}
+				case LESS : {
+					return longval <= longval2;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_Byte(int operation, byte byteval, Object value2) {
+			if (operation == SUBSTRING) {
+				return false;
+			}
+			byte byteval2 = Byte.parseByte(((String) value2).trim());
+			switch (operation) {
+				case APPROX :
+				case EQUAL : {
+					return byteval == byteval2;
+				}
+				case GREATER : {
+					return byteval >= byteval2;
+				}
+				case LESS : {
+					return byteval <= byteval2;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_Short(int operation, short shortval,
+				Object value2) {
+			if (operation == SUBSTRING) {
+				return false;
+			}
+			short shortval2 = Short.parseShort(((String) value2).trim());
+			switch (operation) {
+				case APPROX :
+				case EQUAL : {
+					return shortval == shortval2;
+				}
+				case GREATER : {
+					return shortval >= shortval2;
+				}
+				case LESS : {
+					return shortval <= shortval2;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_Character(int operation, char charval,
+				Object value2) {
+			if (operation == SUBSTRING) {
+				return false;
+			}
+			char charval2 = (((String) value2).trim()).charAt(0);
+			switch (operation) {
+				case EQUAL : {
+					return charval == charval2;
+				}
+				case APPROX : {
+					return (charval == charval2)
+							|| (Character.toUpperCase(charval) == Character
+									.toUpperCase(charval2))
+							|| (Character.toLowerCase(charval) == Character
+									.toLowerCase(charval2));
+				}
+				case GREATER : {
+					return charval >= charval2;
+				}
+				case LESS : {
+					return charval <= charval2;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_Boolean(int operation, boolean boolval,
+				Object value2) {
+			if (operation == SUBSTRING) {
+				return false;
+			}
+			boolean boolval2 = Boolean.valueOf(((String) value2).trim())
+					.booleanValue();
+			switch (operation) {
+				case APPROX :
+				case EQUAL :
+				case GREATER :
+				case LESS : {
+					return boolval == boolval2;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_Float(int operation, float floatval,
+				Object value2) {
+			if (operation == SUBSTRING) {
+				return false;
+			}
+			float floatval2 = Float.parseFloat(((String) value2).trim());
+			switch (operation) {
+				case APPROX :
+				case EQUAL : {
+					return Float.compare(floatval, floatval2) == 0;
+				}
+				case GREATER : {
+					return Float.compare(floatval, floatval2) >= 0;
+				}
+				case LESS : {
+					return Float.compare(floatval, floatval2) <= 0;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_Double(int operation, double doubleval,
+				Object value2) {
+			if (operation == SUBSTRING) {
+				return false;
+			}
+			double doubleval2 = Double.parseDouble(((String) value2).trim());
+			switch (operation) {
+				case APPROX :
+				case EQUAL : {
+					return Double.compare(doubleval, doubleval2) == 0;
+				}
+				case GREATER : {
+					return Double.compare(doubleval, doubleval2) >= 0;
+				}
+				case LESS : {
+					return Double.compare(doubleval, doubleval2) <= 0;
+				}
+			}
+			return false;
+		}
+
+		private static final Class[]	constructorType	= new Class[] {String.class};
+
+		private boolean compare_Comparable(int operation, Comparable value1,
+				Object value2) {
+			if (operation == SUBSTRING) {
+				return false;
+			}
+			Constructor constructor;
 			try {
-				return (Filter) ImplHolder.createFilter
-						.invoke(null, new Object[] {filter});
+				constructor = value1.getClass().getConstructor(constructorType);
+			}
+			catch (NoSuchMethodException e) {
+				return false;
+			}
+			try {
+				if (!constructor.isAccessible())
+					AccessController.doPrivileged(new SetAccessibleAction(
+							constructor));
+				value2 = constructor
+						.newInstance(new Object[] {((String) value2).trim()});
+			}
+			catch (IllegalAccessException e) {
+				return false;
 			}
 			catch (InvocationTargetException e) {
-				throw e.getTargetException();
+				return false;
+			}
+			catch (InstantiationException e) {
+				return false;
+			}
+
+			switch (operation) {
+				case APPROX :
+				case EQUAL : {
+					return value1.compareTo(value2) == 0;
+				}
+				case GREATER : {
+					return value1.compareTo(value2) >= 0;
+				}
+				case LESS : {
+					return value1.compareTo(value2) <= 0;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_Unknown(int operation, Object value1,
+				Object value2) {
+			if (operation == SUBSTRING) {
+				return false;
+			}
+			Constructor constructor;
+			try {
+				constructor = value1.getClass().getConstructor(constructorType);
+			}
+			catch (NoSuchMethodException e) {
+				return false;
+			}
+			try {
+				if (!constructor.isAccessible())
+					AccessController.doPrivileged(new SetAccessibleAction(
+							constructor));
+				value2 = constructor
+						.newInstance(new Object[] {((String) value2).trim()});
+			}
+			catch (IllegalAccessException e) {
+				return false;
+			}
+			catch (InvocationTargetException e) {
+				return false;
+			}
+			catch (InstantiationException e) {
+				return false;
+			}
+
+			switch (operation) {
+				case APPROX :
+				case EQUAL :
+				case GREATER :
+				case LESS : {
+					return value1.equals(value2);
+				}
+			}
+			return false;
+		}
+
+		/**
+		 * Map a string for an APPROX (~=) comparison.
+		 * 
+		 * This implementation removes white spaces. This is the minimum
+		 * implementation allowed by the OSGi spec.
+		 * 
+		 * @param input Input string.
+		 * @return String ready for APPROX comparison.
+		 */
+		private static String approxString(String input) {
+			boolean changed = false;
+			char[] output = input.toCharArray();
+			int cursor = 0;
+			for (int i = 0, length = output.length; i < length; i++) {
+				char c = output[i];
+
+				if (Character.isWhitespace(c)) {
+					changed = true;
+					continue;
+				}
+
+				output[cursor] = c;
+				cursor++;
+			}
+
+			return changed ? new String(output, 0, cursor) : input;
+		}
+
+		/**
+		 * Parser class for OSGi filter strings. This class parses the complete
+		 * filter string and builds a tree of Filter objects rooted at the
+		 * parent.
+		 */
+		private static class Parser {
+			private final String	filterstring;
+			private final char[]	filterChars;
+			private int				pos;
+
+			Parser(String filterstring) {
+				this.filterstring = filterstring;
+				filterChars = filterstring.toCharArray();
+				pos = 0;
+			}
+
+			FilterImpl parse() throws InvalidSyntaxException {
+				FilterImpl filter;
+				try {
+					filter = parse_filter();
+				}
+				catch (ArrayIndexOutOfBoundsException e) {
+					throw new InvalidSyntaxException("Filter ended abruptly",
+							filterstring);
+				}
+
+				if (pos != filterChars.length) {
+					throw new InvalidSyntaxException(
+							"Extraneous trailing characters: "
+									+ filterstring.substring(pos), filterstring);
+				}
+				return filter;
+			}
+
+			private FilterImpl parse_filter() throws InvalidSyntaxException {
+				FilterImpl filter;
+				skipWhiteSpace();
+
+				if (filterChars[pos] != '(') {
+					throw new InvalidSyntaxException("Missing '(': "
+							+ filterstring.substring(pos), filterstring);
+				}
+
+				pos++;
+
+				filter = parse_filtercomp();
+
+				skipWhiteSpace();
+
+				if (filterChars[pos] != ')') {
+					throw new InvalidSyntaxException("Missing ')': "
+							+ filterstring.substring(pos), filterstring);
+				}
+
+				pos++;
+
+				skipWhiteSpace();
+
+				return filter;
+			}
+
+			private FilterImpl parse_filtercomp() throws InvalidSyntaxException {
+				skipWhiteSpace();
+
+				char c = filterChars[pos];
+
+				switch (c) {
+					case '&' : {
+						pos++;
+						return parse_and();
+					}
+					case '|' : {
+						pos++;
+						return parse_or();
+					}
+					case '!' : {
+						pos++;
+						return parse_not();
+					}
+				}
+				return parse_item();
+			}
+
+			private FilterImpl parse_and() throws InvalidSyntaxException {
+				skipWhiteSpace();
+
+				if (filterChars[pos] != '(') {
+					throw new InvalidSyntaxException("Missing '(': "
+							+ filterstring.substring(pos), filterstring);
+				}
+
+				List operands = new ArrayList(10);
+
+				while (filterChars[pos] == '(') {
+					FilterImpl child = parse_filter();
+					operands.add(child);
+				}
+
+				return new FilterImpl(FilterImpl.AND, null, operands
+						.toArray(new FilterImpl[operands.size()]));
+			}
+
+			private FilterImpl parse_or() throws InvalidSyntaxException {
+				skipWhiteSpace();
+
+				if (filterChars[pos] != '(') {
+					throw new InvalidSyntaxException("Missing '(': "
+							+ filterstring.substring(pos), filterstring);
+				}
+
+				List operands = new ArrayList(10);
+
+				while (filterChars[pos] == '(') {
+					FilterImpl child = parse_filter();
+					operands.add(child);
+				}
+
+				return new FilterImpl(FilterImpl.OR, null, operands
+						.toArray(new FilterImpl[operands.size()]));
+			}
+
+			private FilterImpl parse_not() throws InvalidSyntaxException {
+				skipWhiteSpace();
+
+				if (filterChars[pos] != '(') {
+					throw new InvalidSyntaxException("Missing '(': "
+							+ filterstring.substring(pos), filterstring);
+				}
+
+				FilterImpl child = parse_filter();
+
+				return new FilterImpl(FilterImpl.NOT, null, child);
+			}
+
+			private FilterImpl parse_item() throws InvalidSyntaxException {
+				String attr = parse_attr();
+
+				skipWhiteSpace();
+
+				switch (filterChars[pos]) {
+					case '~' : {
+						if (filterChars[pos + 1] == '=') {
+							pos += 2;
+							return new FilterImpl(FilterImpl.APPROX, attr,
+									parse_value());
+						}
+						break;
+					}
+					case '>' : {
+						if (filterChars[pos + 1] == '=') {
+							pos += 2;
+							return new FilterImpl(FilterImpl.GREATER, attr,
+									parse_value());
+						}
+						break;
+					}
+					case '<' : {
+						if (filterChars[pos + 1] == '=') {
+							pos += 2;
+							return new FilterImpl(FilterImpl.LESS, attr,
+									parse_value());
+						}
+						break;
+					}
+					case '=' : {
+						if (filterChars[pos + 1] == '*') {
+							int oldpos = pos;
+							pos += 2;
+							skipWhiteSpace();
+							if (filterChars[pos] == ')') {
+								return new FilterImpl(FilterImpl.PRESENT, attr,
+										null);
+							}
+							pos = oldpos;
+						}
+
+						pos++;
+						Object string = parse_substring();
+
+						if (string instanceof String) {
+							return new FilterImpl(FilterImpl.EQUAL, attr,
+									string);
+						}
+						return new FilterImpl(FilterImpl.SUBSTRING, attr,
+								string);
+					}
+				}
+
+				throw new InvalidSyntaxException("Invalid operator: "
+						+ filterstring.substring(pos), filterstring);
+			}
+
+			private String parse_attr() throws InvalidSyntaxException {
+				skipWhiteSpace();
+
+				int begin = pos;
+				int end = pos;
+
+				char c = filterChars[pos];
+
+				while (c != '~' && c != '<' && c != '>' && c != '=' && c != '('
+						&& c != ')') {
+					pos++;
+
+					if (!Character.isWhitespace(c)) {
+						end = pos;
+					}
+
+					c = filterChars[pos];
+				}
+
+				int length = end - begin;
+
+				if (length == 0) {
+					throw new InvalidSyntaxException("Missing attr: "
+							+ filterstring.substring(pos), filterstring);
+				}
+
+				return new String(filterChars, begin, length);
+			}
+
+			private String parse_value() throws InvalidSyntaxException {
+				StringBuffer sb = new StringBuffer(filterChars.length - pos);
+
+				parseloop: while (true) {
+					char c = filterChars[pos];
+
+					switch (c) {
+						case ')' : {
+							break parseloop;
+						}
+
+						case '(' : {
+							throw new InvalidSyntaxException("Invalid value: "
+									+ filterstring.substring(pos), filterstring);
+						}
+
+						case '\\' : {
+							pos++;
+							c = filterChars[pos];
+							/* fall through into default */
+						}
+
+						default : {
+							sb.append(c);
+							pos++;
+							break;
+						}
+					}
+				}
+
+				if (sb.length() == 0) {
+					throw new InvalidSyntaxException("Missing value: "
+							+ filterstring.substring(pos), filterstring);
+				}
+
+				return sb.toString();
+			}
+
+			private Object parse_substring() throws InvalidSyntaxException {
+				StringBuffer sb = new StringBuffer(filterChars.length - pos);
+
+				List operands = new ArrayList(10);
+
+				parseloop: while (true) {
+					char c = filterChars[pos];
+
+					switch (c) {
+						case ')' : {
+							if (sb.length() > 0) {
+								operands.add(sb.toString());
+							}
+
+							break parseloop;
+						}
+
+						case '(' : {
+							throw new InvalidSyntaxException("Invalid value: "
+									+ filterstring.substring(pos), filterstring);
+						}
+
+						case '*' : {
+							if (sb.length() > 0) {
+								operands.add(sb.toString());
+							}
+
+							sb.setLength(0);
+
+							operands.add(null);
+							pos++;
+
+							break;
+						}
+
+						case '\\' : {
+							pos++;
+							c = filterChars[pos];
+							/* fall through into default */
+						}
+
+						default : {
+							sb.append(c);
+							pos++;
+							break;
+						}
+					}
+				}
+
+				int size = operands.size();
+
+				if (size == 0) {
+					throw new InvalidSyntaxException("Missing value: "
+							+ filterstring.substring(pos), filterstring);
+				}
+
+				if (size == 1) {
+					Object single = operands.get(0);
+
+					if (single != null) {
+						return single;
+					}
+				}
+
+				return operands.toArray(new String[size]);
+			}
+
+			private void skipWhiteSpace() {
+				for (int length = filterChars.length; (pos < length)
+						&& Character.isWhitespace(filterChars[pos]);) {
+					pos++;
+				}
 			}
 		}
-		catch (InvalidSyntaxException e) {
-			throw e;
+	}
+
+	/**
+	 * This Dictionary is used for case-insensitive key lookup during filter
+	 * evaluation. This Dictionary implementation only supports the get
+	 * operation using a String key as no other operations are used by the
+	 * Filter implementation.
+	 */
+	private static class CaseInsensitiveDictionary extends Dictionary {
+		private final Dictionary	dictionary;
+		private final String[]		keys;
+
+		/**
+		 * Create a case insensitive dictionary from the specified dictionary.
+		 * 
+		 * @param dictionary
+		 * @throws IllegalArgumentException If <code>dictionary</code> contains
+		 *         case variants of the same key name.
+		 */
+		CaseInsensitiveDictionary(Dictionary dictionary) {
+			if (dictionary == null) {
+				this.dictionary = null;
+				this.keys = new String[0];
+				return;
+			}
+			this.dictionary = dictionary;
+			List keyList = new ArrayList(dictionary.size());
+			for (Enumeration e = dictionary.keys(); e.hasMoreElements();) {
+				Object k = e.nextElement();
+				if (k instanceof String) {
+					String key = (String) k;
+					for (Iterator i = keyList.iterator(); i.hasNext();) {
+						if (key.equalsIgnoreCase((String) i.next())) {
+							throw new IllegalArgumentException();
+						}
+					}
+					keyList.add(key);
+				}
+			}
+			this.keys = (String[]) keyList.toArray(new String[keyList.size()]);
 		}
-		catch (Error e) {
-			throw e;
+
+		public Object get(Object o) {
+			String k = (String) o;
+			for (int i = 0, length = keys.length; i < length; i++) {
+				String key = keys[i];
+				if (key.equalsIgnoreCase(k)) {
+					return dictionary.get(key);
+				}
+			}
+			return null;
 		}
-		catch (RuntimeException e) {
-			throw e;
+
+		public boolean isEmpty() {
+			throw new UnsupportedOperationException();
 		}
-		catch (Throwable e) {
-			throw new RuntimeException(e.toString());
+
+		public Enumeration keys() {
+			throw new UnsupportedOperationException();
+		}
+
+		public Enumeration elements() {
+			throw new UnsupportedOperationException();
+		}
+
+		public Object put(Object key, Object value) {
+			throw new UnsupportedOperationException();
+		}
+
+		public Object remove(Object key) {
+			throw new UnsupportedOperationException();
+		}
+
+		public int size() {
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	/**
+	 * This Dictionary is used for key lookup from a ServiceReference during
+	 * filter evaluation. This Dictionary implementation only supports the get
+	 * operation using a String key as no other operations are used by the
+	 * Filter implementation.
+	 */
+	private static class ServiceReferenceDictionary extends Dictionary {
+		private final ServiceReference	reference;
+
+		ServiceReferenceDictionary(ServiceReference reference) {
+			this.reference = reference;
+		}
+
+		public Object get(Object key) {
+			if (reference == null) {
+				return null;
+			}
+			return reference.getProperty((String) key);
+		}
+
+		public boolean isEmpty() {
+			throw new UnsupportedOperationException();
+		}
+
+		public Enumeration keys() {
+			throw new UnsupportedOperationException();
+		}
+
+		public Enumeration elements() {
+			throw new UnsupportedOperationException();
+		}
+
+		public Object put(Object key, Object value) {
+			throw new UnsupportedOperationException();
+		}
+
+		public Object remove(Object key) {
+			throw new UnsupportedOperationException();
+		}
+
+		public int size() {
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	private static class SetAccessibleAction implements PrivilegedAction {
+		private final AccessibleObject	accessible;
+
+		SetAccessibleAction(AccessibleObject accessible) {
+			this.accessible = accessible;
+		}
+
+		public Object run() {
+			accessible.setAccessible(true);
+			return null;
+		}
+	}
+
+	/**
+	 * This class contains a method to match a distinguished name (DN) chain
+	 * against and DN chain pattern.
+	 * <p>
+	 * The format of DNs are given in RFC 2253. We represent a signature chain
+	 * for an X.509 certificate as a semicolon separated list of DNs. This is
+	 * what we refer to as the DN chain. Each DN is made up of relative
+	 * distinguished names (RDN) which in turn are made up of key value pairs.
+	 * For example:
+	 * 
+	 * <pre>
+	 *   cn=ben+ou=research,o=ACME,c=us;ou=Super CA,c=CA
+	 * </pre>
+	 * 
+	 * is made up of two DNs: "<code>cn=ben+ou=research,o=ACME,c=us</code>
+	 * " and " <code>ou=Super CA,c=CA</code>
+	 * ". The first DN is made of of three RDNs: "
+	 * <code>cn=ben+ou=research</code>" and "<code>o=ACME</code>" and "
+	 * <code>c=us</code>". The first RDN has two name value pairs: "
+	 * <code>cn=ben</code>" and "<code>ou=research</code>".
+	 * <p>
+	 * A chain pattern makes use of wildcards ('*' or '-') to match against DNs,
+	 * and wildcards ('*') to match againts DN prefixes, and value. If a DN in a
+	 * match pattern chain is made up of a wildcard ("*"), that wildcard will
+	 * match zero or one DNs in the chain. If a DN in a match pattern chain is
+	 * made up of a wildcard ("-"), that wildcard will match zero or more DNs in
+	 * the chain. If the first RDN of a DN is the wildcard ("*"), that DN will
+	 * match any other DN with the same suffix (the DN with the wildcard RDN
+	 * removed). If a value of a name/value pair is a wildcard ("*"), the value
+	 * will match any value for that name.
+	 */
+	private static class DNChainMatching {
+		private static final String	MINUS_WILDCARD	= "-";
+		private static final String	STAR_WILDCARD	= "*";
+
+		/**
+		 * Check the name/value pairs of the rdn against the pattern.
+		 * 
+		 * @param rdn ArrayList of name value pairs for a given RDN.
+		 * @param rdnPattern ArrayList of name value pattern pairs.
+		 * @return true if the list of name value pairs match the pattern.
+		 */
+		private static boolean rdnmatch(ArrayList rdn, ArrayList rdnPattern) {
+			if (rdn.size() != rdnPattern.size()) {
+				return false;
+			}
+			for (int i = 0; i < rdn.size(); i++) {
+				String rdnNameValue = (String) rdn.get(i);
+				String patNameValue = (String) rdnPattern.get(i);
+				int rdnNameEnd = rdnNameValue.indexOf('=');
+				int patNameEnd = patNameValue.indexOf('=');
+				if (rdnNameEnd != patNameEnd
+						|| !rdnNameValue.regionMatches(0, patNameValue, 0,
+								rdnNameEnd)) {
+					return false;
+				}
+				String patValue = patNameValue.substring(patNameEnd);
+				String rdnValue = rdnNameValue.substring(rdnNameEnd);
+				if (!rdnValue.equals(patValue) && !patValue.equals("=*")
+						&& !patValue.equals("=#16012a")) {
+					return false;
+				}
+			}
+			return true;
+		}
+
+		private static boolean dnmatch(ArrayList dn, ArrayList dnPattern) {
+			int dnStart = 0;
+			int patStart = 0;
+			int patLen = dnPattern.size();
+			if (patLen == 0) {
+				return false;
+			}
+			if (dnPattern.get(0).equals(STAR_WILDCARD)) {
+				patStart = 1;
+				patLen--;
+			}
+			if (dn.size() < patLen) {
+				return false;
+			}
+			else {
+				if (dn.size() > patLen) {
+					if (!dnPattern.get(0).equals(STAR_WILDCARD)) {
+						// If the number of rdns do not match we must have a
+						// prefix
+						// map
+						return false;
+					}
+					// The rdnPattern and rdn must have the same number of
+					// elements
+					dnStart = dn.size() - patLen;
+				}
+			}
+			for (int i = 0; i < patLen; i++) {
+				if (!rdnmatch((ArrayList) dn.get(i + dnStart),
+						(ArrayList) dnPattern.get(i + patStart))) {
+					return false;
+				}
+			}
+			return true;
+		}
+
+		/**
+		 * Parses a distinguished name chain pattern and returns an ArrayList
+		 * where each element represents a distinguished name (DN) in the chain
+		 * of DNs. Each element will be either a String, if the element
+		 * represents a wildcard ("*" or "-"), or an ArrayList representing an
+		 * RDN. Each element in the RDN ArrayList will be a String, if the
+		 * element represents a wildcard ("*"), or an ArrayList of Strings, each
+		 * String representing a name/value pair in the RDN.
+		 * 
+		 * @param dnChain
+		 * @return a list of DNs.
+		 * @throws IllegalArgumentException
+		 */
+		private static ArrayList parseDNchainPattern(String dnChain) {
+			if (dnChain == null) {
+				throw new IllegalArgumentException(
+						"The DN chain must not be null.");
+			}
+			ArrayList parsed = new ArrayList();
+			int startIndex = 0;
+			startIndex = skipSpaces(dnChain, startIndex);
+			while (startIndex < dnChain.length()) {
+				int endIndex = startIndex;
+				boolean inQuote = false;
+				out: while (endIndex < dnChain.length()) {
+					char c = dnChain.charAt(endIndex);
+					switch (c) {
+						case '"' :
+							inQuote = !inQuote;
+							break;
+						case '\\' :
+							endIndex++; // skip the escaped char
+							break;
+						case ';' :
+							if (!inQuote)
+								break out;
+					}
+					endIndex++;
+				}
+				if (endIndex > dnChain.length()) {
+					throw new IllegalArgumentException("unterminated escape");
+				}
+				parsed.add(dnChain.substring(startIndex, endIndex));
+				startIndex = endIndex + 1;
+				startIndex = skipSpaces(dnChain, startIndex);
+			}
+			parseDNchain(parsed);
+			return parsed;
+		}
+
+		private static List parseDNchain(List chain) {
+			if (chain == null) {
+				throw new IllegalArgumentException("DN chain must not be null.");
+			}
+			// Now we parse is a list of strings, lets make ArrayList of rdn out
+			// of
+			// them
+			for (int i = 0; i < chain.size(); i++) {
+				String dn = (String) chain.get(i);
+				if (dn.equals(STAR_WILDCARD) || dn.equals(MINUS_WILDCARD)) {
+					continue;
+				}
+				ArrayList rdns = new ArrayList();
+				if (dn.charAt(0) == '*') {
+					if (dn.charAt(1) != ',') {
+						throw new IllegalArgumentException(
+								"invalid wildcard prefix");
+					}
+					rdns.add(STAR_WILDCARD);
+					dn = new X500Principal(dn.substring(2))
+							.getName(X500Principal.CANONICAL);
+				}
+				else {
+					dn = new X500Principal(dn).getName(X500Principal.CANONICAL);
+				}
+				// Now dn is a nice CANONICAL DN
+				parseDN(dn, rdns);
+				chain.set(i, rdns);
+			}
+			if (chain.size() == 0) {
+				throw new IllegalArgumentException("empty DN chain");
+			}
+			return chain;
+		}
+
+		/**
+		 * Increment startIndex until the end of dnChain is hit or until it is
+		 * the index of a non-space character.
+		 */
+		private static int skipSpaces(String dnChain, int startIndex) {
+			while (startIndex < dnChain.length()
+					&& dnChain.charAt(startIndex) == ' ') {
+				startIndex++;
+			}
+			return startIndex;
+		}
+
+		/**
+		 * Takes a distinguished name in canonical form and fills in the
+		 * rdnArray with the extracted RDNs.
+		 * 
+		 * @param dn the distinguished name in canonical form.
+		 * @param rdnArray the array to fill in with RDNs extracted from the dn
+		 * @throws IllegalArgumentException if a formatting error is found.
+		 */
+		private static void parseDN(String dn, ArrayList rdnArray) {
+			int startIndex = 0;
+			char c = '\0';
+			ArrayList nameValues = new ArrayList();
+			while (startIndex < dn.length()) {
+				int endIndex;
+				for (endIndex = startIndex; endIndex < dn.length(); endIndex++) {
+					c = dn.charAt(endIndex);
+					if (c == ',' || c == '+') {
+						break;
+					}
+					if (c == '\\') {
+						endIndex++; // skip the escaped char
+					}
+				}
+				if (endIndex > dn.length()) {
+					throw new IllegalArgumentException("unterminated escape "
+							+ dn);
+				}
+				nameValues.add(dn.substring(startIndex, endIndex));
+				if (c != '+') {
+					rdnArray.add(nameValues);
+					if (endIndex != dn.length()) {
+						nameValues = new ArrayList();
+					}
+					else {
+						nameValues = null;
+					}
+				}
+				startIndex = endIndex + 1;
+			}
+			if (nameValues != null) {
+				throw new IllegalArgumentException("improperly terminated DN "
+						+ dn);
+			}
+		}
+
+		/**
+		 * This method will return an 'index' which points to a non-wildcard DN
+		 * or the end-of-arraylist.
+		 */
+		private static int skipWildCards(List dnChainPattern,
+				int dnChainPatternIndex) {
+			int i;
+			for (i = dnChainPatternIndex; i < dnChainPattern.size(); i++) {
+				Object dnPattern = dnChainPattern.get(i);
+				if (dnPattern instanceof String) {
+					if (!dnPattern.equals(STAR_WILDCARD)
+							&& !dnPattern.equals(MINUS_WILDCARD)) {
+						throw new IllegalArgumentException(
+								"expected wildcard in DN pattern");
+					}
+					// otherwise continue skipping over wild cards
+				}
+				else {
+					if (dnPattern instanceof ArrayList) {
+						// if its an arraylist then we have our 'non-wildcard'
+						// DN
+						break;
+					}
+					else {
+						// unknown member of the DNChainPattern
+						throw new IllegalArgumentException(
+								"expected String or Arraylist in DN Pattern");
+					}
+				}
+			}
+			// i either points to end-of-arraylist, or to the first
+			// non-wildcard
+			// pattern
+			// after dnChainPatternIndex
+			return i;
+		}
+
+		/**
+		 * recursively attempt to match the DNChain, and the DNChainPattern
+		 * where DNChain is of the format: "DN;DN;DN;" and DNChainPattern is of
+		 * the format: "DNPattern;*;DNPattern" (or combinations of this)
+		 */
+		private static boolean dnChainMatch(List dnChain, int dnChainIndex,
+				List dnChainPattern, int dnChainPatternIndex)
+				throws IllegalArgumentException {
+			if (dnChainIndex >= dnChain.size()) {
+				return false;
+			}
+			if (dnChainPatternIndex >= dnChainPattern.size()) {
+				return false;
+			}
+			// check to see what the pattern starts with
+			Object dnPattern = dnChainPattern.get(dnChainPatternIndex);
+			if (dnPattern instanceof String) {
+				if (!dnPattern.equals(STAR_WILDCARD)
+						&& !dnPattern.equals(MINUS_WILDCARD)) {
+					throw new IllegalArgumentException(
+							"expected wildcard in DN pattern");
+				}
+				// here we are processing a wild card as the first DN
+				// skip all wildcard DN's
+				if (dnPattern.equals(MINUS_WILDCARD)) {
+					dnChainPatternIndex = skipWildCards(dnChainPattern,
+							dnChainPatternIndex);
+				}
+				else {
+					dnChainPatternIndex++; // only skip the '*' wildcard
+				}
+				if (dnChainPatternIndex >= dnChainPattern.size()) {
+					// return true iff the wild card is '-' or if we are at the
+					// end of the chain
+					return dnPattern.equals(MINUS_WILDCARD) ? true : dnChain
+							.size() - 1 == dnChainIndex;
+				}
+				//
+				// we will now recursively call to see if the rest of the
+				// DNChainPattern
+				// matches increasingly smaller portions of the rest of the
+				// DNChain
+				//
+				if (dnPattern.equals(STAR_WILDCARD)) {
+					// '*' option: only wildcard on 0 or 1
+					return dnChainMatch(dnChain, dnChainIndex, dnChainPattern,
+							dnChainPatternIndex)
+							|| dnChainMatch(dnChain, dnChainIndex + 1,
+									dnChainPattern, dnChainPatternIndex);
+				}
+				for (int i = dnChainIndex; i < dnChain.size(); i++) {
+					// '-' option: wildcard 0 or more
+					if (dnChainMatch(dnChain, i, dnChainPattern,
+							dnChainPatternIndex)) {
+						return true;
+					}
+				}
+				// if we are here, then we didn't find a match.. fall through to
+				// failure
+			}
+			else {
+				if (dnPattern instanceof ArrayList) {
+					// here we have to do a deeper check for each DN in the
+					// pattern
+					// until we hit a wild card
+					do {
+						if (!dnmatch((ArrayList) dnChain.get(dnChainIndex),
+								(ArrayList) dnPattern)) {
+							return false;
+						}
+						// go to the next set of DN's in both chains
+						dnChainIndex++;
+						dnChainPatternIndex++;
+						// if we finished the pattern then it all matched
+						if ((dnChainIndex >= dnChain.size())
+								&& (dnChainPatternIndex >= dnChainPattern
+										.size())) {
+							return true;
+						}
+						// if the DN Chain is finished, but the pattern isn't
+						// finished
+						// then if the rest of the pattern is not wildcard then
+						// we
+						// are
+						// done
+						if (dnChainIndex >= dnChain.size()) {
+							dnChainPatternIndex = skipWildCards(dnChainPattern,
+									dnChainPatternIndex);
+							// return TRUE iff the pattern index moved past the
+							// array-size
+							// (implying that the rest of the pattern is all
+							// wildcards)
+							return dnChainPatternIndex >= dnChainPattern.size();
+						}
+						// if the pattern finished, but the chain continues then
+						// we
+						// have
+						// a mis-match
+						if (dnChainPatternIndex >= dnChainPattern.size()) {
+							return false;
+						}
+						// get the next DN Pattern
+						dnPattern = dnChainPattern.get(dnChainPatternIndex);
+						if (dnPattern instanceof String) {
+							if (!dnPattern.equals(STAR_WILDCARD)
+									&& !dnPattern.equals(MINUS_WILDCARD)) {
+								throw new IllegalArgumentException(
+										"expected wildcard in DN pattern");
+							}
+							// if the next DN is a 'wildcard', then we will
+							// recurse
+							return dnChainMatch(dnChain, dnChainIndex,
+									dnChainPattern, dnChainPatternIndex);
+						}
+						else {
+							if (!(dnPattern instanceof ArrayList)) {
+								throw new IllegalArgumentException(
+										"expected String or Arraylist in DN Pattern");
+							}
+						}
+						// if we are here, then we will just continue to the
+						// match
+						// the
+						// next set of DN's from the DNChain, and the
+						// DNChainPattern
+						// since both are array-lists
+					} while (true);
+					// should never reach here?
+				}
+				else {
+					throw new IllegalArgumentException(
+							"expected String or Arraylist in DN Pattern");
+				}
+			}
+			// if we get here, the the default return is 'mis-match'
+			return false;
+		}
+
+		/**
+		 * Matches a distinguished name chain against a pattern of a
+		 * distinguished name chain.
+		 * 
+		 * @param dnChain
+		 * @param pattern the pattern of distinguished name (DN) chains to match
+		 *        against the dnChain. Wildcards ("*" or "-") can be used in
+		 *        three cases:
+		 *        <ol>
+		 *        <li>As a DN. In this case, the DN will consist of just the "*"
+		 *        or "-". When "*" is used it will match zero or one DNs. When
+		 *        "-" is used it will match zero or more DNs. For example,
+		 *        "cn=me,c=US;*;cn=you" will match
+		 *        "cn=me,c=US";cn=you" and "cn=me,c=US;cn=her;cn=you". The
+		 *        pattern "cn=me,c=US;-;cn=you" will match "cn=me,c=US";cn=you"
+		 *        and "cn=me,c=US;cn=her;cn=him;cn=you".
+		 *        <li>As a DN prefix. In this case, the DN must start with "*,".
+		 *        The wild card will match zero or more RDNs at the start of a
+		 *        DN. For example, "*,cn=me,c=US;cn=you" will match
+		 *        "cn=me,c=US";cn=you" and
+		 *        "ou=my org unit,o=my org,cn=me,c=US;cn=you"</li>
+		 *        <li>As a value. In this case the value of a name value pair in
+		 *        an RDN will be a "*". The wildcard will match any value for
+		 *        the given name. For example, "cn=*,c=US;cn=you" will match
+		 *        "cn=me,c=US";cn=you" and "cn=her,c=US;cn=you", but it will not
+		 *        match "ou=my org unit,c=US;cn=you". If the wildcard does not
+		 *        occur by itself in the value, it will not be used as a
+		 *        wildcard. In other words, "cn=m*,c=US;cn=you" represents the
+		 *        common name of "m*" not any common name starting with "m".</li>
+		 *        </ol>
+		 * @return true if dnChain matches the pattern.
+		 * @throws IllegalArgumentException
+		 */
+		static boolean match(String pattern, List/* <String> */dnChain) {
+			List parsedDNChain;
+			List parsedDNPattern;
+			try {
+				parsedDNChain = parseDNchain(dnChain);
+			}
+			catch (IllegalArgumentException e) {
+				throw (IllegalArgumentException) new IllegalArgumentException(
+						"Invalid DN chain: " + toString(dnChain)).initCause(e);
+			}
+			try {
+				parsedDNPattern = parseDNchainPattern(pattern);
+			}
+			catch (IllegalArgumentException e) {
+				throw (IllegalArgumentException) new IllegalArgumentException(
+						"Invalid match pattern: " + pattern).initCause(e);
+			}
+			return dnChainMatch(parsedDNChain, 0, parsedDNPattern, 0);
+		}
+
+		private static String toString(List dnChain) {
+			if (dnChain == null) {
+				return null;
+			}
+			StringBuffer sb = new StringBuffer();
+			for (Iterator iChain = dnChain.iterator(); iChain.hasNext();) {
+				sb.append(iChain.next());
+				if (iChain.hasNext()) {
+					sb.append("; ");
+				}
+			}
+			return sb.toString();
 		}
 	}
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/InvalidSyntaxException.java b/org.osgi.core/src/main/java/org/osgi/framework/InvalidSyntaxException.java
index b69c120..f67fd43 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/InvalidSyntaxException.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/InvalidSyntaxException.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/InvalidSyntaxException.java,v 1.16 2007/02/20 00:15:00 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). 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.
@@ -28,10 +26,9 @@
  * {@link Filter} for a description of the filter string syntax.
  * 
  * <p>
- * This exception is updated to conform to the general purpose exception
- * chaining mechanism.
+ * This exception conforms to the general purpose exception chaining mechanism.
  * 
- * @version $Revision: 1.16 $
+ * @version $Revision: 6083 $
  */
 
 public class InvalidSyntaxException extends Exception {
@@ -40,10 +37,6 @@
 	 * The invalid filter string.
 	 */
 	private final String	filter;
-	/**
-	 * Nested exception.
-	 */
-	private final Throwable	cause;
 
 	/**
 	 * Creates an exception of type <code>InvalidSyntaxException</code>.
@@ -59,7 +52,6 @@
 	public InvalidSyntaxException(String msg, String filter) {
 		super(msg);
 		this.filter = filter;
-		this.cause = null;
 	}
 
 	/**
@@ -76,9 +68,8 @@
 	 * @since 1.3
 	 */
 	public InvalidSyntaxException(String msg, String filter, Throwable cause) {
-		super(msg);
+		super(msg, cause);
 		this.filter = filter;
-		this.cause = cause;
 	}
 
 	/**
@@ -94,28 +85,29 @@
 	}
 
 	/**
-	 * Returns the cause of this exception or <code>null</code> if no cause
-	 * was specified when this exception was created.
+	 * Returns the cause of this exception or <code>null</code> if no cause was
+	 * set.
 	 * 
-	 * @return The cause of this exception or <code>null</code> if no cause
-	 *         was specified.
+	 * @return The cause of this exception or <code>null</code> if no cause was
+	 *         set.
 	 * @since 1.3
 	 */
 	public Throwable getCause() {
-		return cause;
+		return super.getCause();
 	}
 
 	/**
-	 * The cause of this exception can only be set when constructed.
+	 * Initializes the cause of this exception to the specified value.
 	 * 
-	 * @param cause Cause of the exception.
-	 * @return This object.
-	 * @throws java.lang.IllegalStateException This method will always throw an
-	 *         <code>IllegalStateException</code> since the cause of this
-	 *         exception can only be set when constructed.
+	 * @param cause The cause of this exception.
+	 * @return This exception.
+	 * @throws IllegalArgumentException If the specified cause is this
+	 *         exception.
+	 * @throws IllegalStateException If the cause of this exception has already
+	 *         been set.
 	 * @since 1.3
 	 */
 	public Throwable initCause(Throwable cause) {
-		throw new IllegalStateException();
+		return super.initCause(cause);
 	}
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/PackagePermission.java b/org.osgi.core/src/main/java/org/osgi/framework/PackagePermission.java
index 762bce1..fc319e8 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/PackagePermission.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/PackagePermission.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/PackagePermission.java,v 1.14 2006/06/16 16:31:18 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -19,9 +17,25 @@
 package org.osgi.framework;
 
 import java.io.IOException;
-import java.security.*;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.security.AccessController;
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 /**
  * A bundle's authority to import or export a package.
@@ -33,54 +47,90 @@
  * For example:
  * 
  * <pre>
- * <code>
  * org.osgi.service.http
- * </code>
  * </pre>
  * 
  * <p>
- * <code>PackagePermission</code> has two actions: <code>EXPORT</code> and
- * <code>IMPORT</code>. The <code>EXPORT</code> action implies the
- * <code>IMPORT</code> action.
+ * <code>PackagePermission</code> has three actions: <code>exportonly</code>,
+ * <code>import</code> and <code>export</code>. The <code>export</code> action,
+ * which is deprecated, implies the <code>import</code> action.
  * 
- * @version $Revision: 1.14 $
+ * @ThreadSafe
+ * @version $Revision: 6530 $
  */
 
 public final class PackagePermission extends BasicPermission {
-	static final long			serialVersionUID	= -5107705877071099135L;
+	static final long						serialVersionUID	= -5107705877071099135L;
+
 	/**
-	 * The action string <code>export</code>.
+	 * The action string <code>export</code>. The <code>export</code> action
+	 * implies the <code>import</code> action.
+	 * 
+	 * @deprecated Since 1.5. Use <code>exportonly</code> instead.
 	 */
-	public final static String	EXPORT				= "export";
+	public final static String				EXPORT				= "export";
+
+	/**
+	 * The action string <code>exportonly</code>. The <code>exportonly</code>
+	 * action does not imply the <code>import</code> action.
+	 * 
+	 * @since 1.5
+	 */
+	public final static String				EXPORTONLY			= "exportonly";
 
 	/**
 	 * The action string <code>import</code>.
 	 */
-	public final static String	IMPORT				= "import";
+	public final static String				IMPORT				= "import";
 
-	private final static int	ACTION_EXPORT		= 0x00000001;
-	private final static int	ACTION_IMPORT		= 0x00000002;
-	private final static int	ACTION_ALL			= ACTION_EXPORT
-															| ACTION_IMPORT;
-	private final static int	ACTION_NONE			= 0;
+	private final static int				ACTION_EXPORT		= 0x00000001;
+	private final static int				ACTION_IMPORT		= 0x00000002;
+	private final static int				ACTION_ALL			= ACTION_EXPORT
+																		| ACTION_IMPORT;
+	final static int						ACTION_NONE			= 0;
+
 	/**
 	 * The actions mask.
 	 */
-	private transient int		action_mask			= ACTION_NONE;
+	transient int							action_mask;
 
 	/**
 	 * The actions in canonical form.
 	 * 
 	 * @serial
 	 */
-	private String				actions				= null;
+	private volatile String					actions				= null;
 
 	/**
-	 * Defines the authority to import and/or export a package within the OSGi
-	 * environment.
+	 * The bundle used by this PackagePermission.
+	 */
+	transient final Bundle					bundle;
+
+	/**
+	 * If this PackagePermission was constructed with a filter, this holds a
+	 * Filter matching object used to evaluate the filter in implies.
+	 */
+	transient Filter						filter;
+
+	/**
+	 * This dictionary holds the properties of the permission, used to match a
+	 * filter in implies. This is not initialized until necessary, and then
+	 * cached in this object.
+	 */
+	private transient volatile Dictionary	properties;
+
+	/**
+	 * Creates a new <code>PackagePermission</code> object.
+	 * 
 	 * <p>
 	 * The name is specified as a normal Java package name: a dot-separated
-	 * string. Wildcards may be used. For example:
+	 * string. Wildcards may be used.
+	 * 
+	 * <pre>
+	 * name ::= &lt;package name&gt; | &lt;package name ending in &quot;.*&quot;&gt; | *
+	 * </pre>
+	 * 
+	 * Examples:
 	 * 
 	 * <pre>
 	 * org.osgi.service.http
@@ -88,34 +138,85 @@
 	 * *
 	 * </pre>
 	 * 
+	 * For the <code>import</code> action, the name can also be a filter
+	 * expression. The filter gives access to the following attributes:
+	 * <ul>
+	 * <li>signer - A Distinguished Name chain used to sign the exporting
+	 * bundle. Wildcards in a DN are not matched according to the filter string
+	 * rules, but according to the rules defined for a DN chain.</li>
+	 * <li>location - The location of the exporting bundle.</li>
+	 * <li>id - The bundle ID of the exporting bundle.</li>
+	 * <li>name - The symbolic name of the exporting bundle.</li>
+	 * <li>package.name - The name of the requested package.</li>
+	 * </ul>
+	 * Filter attribute names are processed in a case sensitive manner.
+	 * 
 	 * <p>
 	 * Package Permissions are granted over all possible versions of a package.
 	 * 
 	 * A bundle that needs to export a package must have the appropriate
-	 * <code>PackagePermission</code> for that package; similarly, a bundle
-	 * that needs to import a package must have the appropriate
+	 * <code>PackagePermission</code> for that package; similarly, a bundle that
+	 * needs to import a package must have the appropriate
 	 * <code>PackagePermssion</code> for that package.
 	 * <p>
 	 * Permission is granted for both classes and resources.
 	 * 
-	 * @param name Package name.
-	 * @param actions <code>EXPORT</code>,<code>IMPORT</code> (canonical
+	 * @param name Package name or filter expression. A filter expression can
+	 *        only be specified if the specified action is <code>import</code>.
+	 * @param actions <code>exportonly</code>,<code>import</code> (canonical
 	 *        order).
+	 * @throw IllegalArgumentException If the specified name is a filter
+	 *        expression and either the specified action is not
+	 *        <code>import</code> or the filter has an invalid syntax.
 	 */
-
 	public PackagePermission(String name, String actions) {
-		this(name, getMask(actions));
+		this(name, parseActions(actions));
+		if ((filter != null)
+				&& ((action_mask & ACTION_ALL) != ACTION_IMPORT)) {
+			throw new IllegalArgumentException(
+					"invalid action string for filter expression");
+		}
+	}
+
+	/**
+	 * Creates a new requested <code>PackagePermission</code> object to be used
+	 * by code that must perform <code>checkPermission</code> for the
+	 * <code>import</code> action. <code>PackagePermission</code> objects
+	 * created with this constructor cannot be added to a
+	 * <code>PackagePermission</code> permission collection.
+	 * 
+	 * @param name The name of the requested package to import.
+	 * @param exportingBundle The bundle exporting the requested package.
+	 * @param actions The action <code>import</code>.
+	 * @throw IllegalArgumentException If the specified action is not
+	 *        <code>import</code> or the name is a filter expression.
+	 * @since 1.5
+	 */
+	public PackagePermission(String name, Bundle exportingBundle, String actions) {
+		super(name);
+		setTransients(name, parseActions(actions));
+		this.bundle = exportingBundle;
+		if (exportingBundle == null) {
+			throw new IllegalArgumentException("bundle must not be null");
+		}
+		if (filter != null) {
+			throw new IllegalArgumentException("invalid name");
+		}
+		if ((action_mask & ACTION_ALL) != ACTION_IMPORT) {
+			throw new IllegalArgumentException("invalid action string");
+		}
 	}
 
 	/**
 	 * Package private constructor used by PackagePermissionCollection.
 	 * 
-	 * @param name class name
+	 * @param name package name
 	 * @param mask action mask
 	 */
 	PackagePermission(String name, int mask) {
 		super(name);
-		init(mask);
+		setTransients(name, mask);
+		this.bundle = null;
 	}
 
 	/**
@@ -123,12 +224,12 @@
 	 * 
 	 * @param mask action mask
 	 */
-	private void init(int mask) {
+	private void setTransients(String name, int mask) {
 		if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
 			throw new IllegalArgumentException("invalid action string");
 		}
-
 		action_mask = mask;
+		filter = parseFilter(name);
 	}
 
 	/**
@@ -137,20 +238,20 @@
 	 * @param actions Action string.
 	 * @return action mask.
 	 */
-	private static int getMask(String actions) {
+	private static int parseActions(String actions) {
 		boolean seencomma = false;
 
 		int mask = ACTION_NONE;
 
 		if (actions == null) {
-			return (mask);
+			return mask;
 		}
 
 		char[] a = actions.toCharArray();
 
 		int i = a.length - 1;
 		if (i < 0)
-			return (mask);
+			return mask;
 
 		while (i != -1) {
 			char c;
@@ -186,9 +287,25 @@
 
 				}
 				else {
-					// parse error
-					throw new IllegalArgumentException("invalid permission: "
-							+ actions);
+					if (i >= 9 && (a[i - 9] == 'e' || a[i - 9] == 'E')
+							&& (a[i - 8] == 'x' || a[i - 8] == 'X')
+							&& (a[i - 7] == 'p' || a[i - 7] == 'P')
+							&& (a[i - 6] == 'o' || a[i - 6] == 'O')
+							&& (a[i - 5] == 'r' || a[i - 5] == 'R')
+							&& (a[i - 4] == 't' || a[i - 4] == 'T')
+							&& (a[i - 3] == 'o' || a[i - 3] == 'O')
+							&& (a[i - 2] == 'n' || a[i - 2] == 'N')
+							&& (a[i - 1] == 'l' || a[i - 1] == 'L')
+							&& (a[i] == 'y' || a[i] == 'Y')) {
+						matchlen = 10;
+						mask |= ACTION_EXPORT;
+
+					}
+					else {
+						// parse error
+						throw new IllegalArgumentException(
+								"invalid permission: " + actions);
+					}
 				}
 
 			// make sure we didn't just match the tail of a word
@@ -198,7 +315,7 @@
 				switch (a[i - matchlen]) {
 					case ',' :
 						seencomma = true;
-					/* FALLTHROUGH */
+						/* FALLTHROUGH */
 					case ' ' :
 					case '\r' :
 					case '\n' :
@@ -220,7 +337,32 @@
 			throw new IllegalArgumentException("invalid permission: " + actions);
 		}
 
-		return (mask);
+		return mask;
+	}
+
+	/**
+	 * Parse filter string into a Filter object.
+	 * 
+	 * @param filterString The filter string to parse.
+	 * @return a Filter for this bundle. If the specified filterString is not a
+	 *         filter expression, then <code>null</code> is returned.
+	 * @throws IllegalArgumentException If the filter syntax is invalid.
+	 */
+	private static Filter parseFilter(String filterString) {
+		filterString = filterString.trim();
+		if (filterString.charAt(0) != '(') {
+			return null;
+		}
+
+		try {
+			return FrameworkUtil.createFilter(filterString);
+		}
+		catch (InvalidSyntaxException e) {
+			IllegalArgumentException iae = new IllegalArgumentException(
+					"invalid filter");
+			iae.initCause(e);
+			throw iae;
+		}
 	}
 
 	/**
@@ -242,21 +384,49 @@
 	 * x.y,&quot;export&quot; -&gt; x.y.z, &quot;export&quot;  is false
 	 * </pre>
 	 * 
-	 * @param p The target permission to interrogate.
-	 * @return <code>true</code> if the specified
-	 *         <code>PackagePermission</code> action is implied by this
+	 * @param p The requested permission.
+	 * @return <code>true</code> if the specified permission is implied by this
 	 *         object; <code>false</code> otherwise.
 	 */
-
 	public boolean implies(Permission p) {
-		if (p instanceof PackagePermission) {
-			PackagePermission target = (PackagePermission) p;
-
-			return (((action_mask & target.action_mask) == target.action_mask) && super
-					.implies(p));
+		if (!(p instanceof PackagePermission)) {
+			return false;
 		}
+		PackagePermission requested = (PackagePermission) p;
+		if (bundle != null) {
+			return false;
+		}
+		// if requested permission has a filter, then it is an invalid argument
+		if (requested.filter != null) {
+			return false;
+		}
+		return implies0(requested, ACTION_NONE);
+	}
 
-		return (false);
+	/**
+	 * Internal implies method. Used by the implies and the permission
+	 * collection implies methods.
+	 * 
+	 * @param requested The requested PackagePermission which has already be
+	 *        validated as a proper argument. The requested PackagePermission
+	 *        must not have a filter expression.
+	 * @param effective The effective actions with which to start.
+	 * @return <code>true</code> if the specified permission is implied by this
+	 *         object; <code>false</code> otherwise.
+	 */
+	boolean implies0(PackagePermission requested, int effective) {
+		/* check actions first - much faster */
+		effective |= action_mask;
+		final int desired = requested.action_mask;
+		if ((effective & desired) != desired) {
+			return false;
+		}
+		/* Get filter if any */
+		Filter f = filter;
+		if (f == null) {
+			return super.implies(requested);
+		}
+		return f.matchCase(requested.getProperties());
 	}
 
 	/**
@@ -265,32 +435,32 @@
 	 * 
 	 * <p>
 	 * Always returns present <code>PackagePermission</code> actions in the
-	 * following order: <code>EXPORT</code>,<code>IMPORT</code>.
+	 * following order: <code>EXPORTONLY</code>,<code>IMPORT</code>.
 	 * 
 	 * @return Canonical string representation of the
 	 *         <code>PackagePermission</code> actions.
 	 */
-
 	public String getActions() {
-		if (actions == null) {
+		String result = actions;
+		if (result == null) {
 			StringBuffer sb = new StringBuffer();
 			boolean comma = false;
 
-			if ((action_mask & ACTION_EXPORT) == ACTION_EXPORT) {
-				sb.append(EXPORT);
+			int mask = action_mask;
+			if ((mask & ACTION_EXPORT) == ACTION_EXPORT) {
+				sb.append(EXPORTONLY);
 				comma = true;
 			}
 
-			if ((action_mask & ACTION_IMPORT) == ACTION_IMPORT) {
+			if ((mask & ACTION_IMPORT) == ACTION_IMPORT) {
 				if (comma)
 					sb.append(',');
 				sb.append(IMPORT);
 			}
 
-			actions = sb.toString();
+			actions = result = sb.toString();
 		}
-
-		return (actions);
+		return result;
 	}
 
 	/**
@@ -300,7 +470,7 @@
 	 * @return A new <code>PermissionCollection</code> object.
 	 */
 	public PermissionCollection newPermissionCollection() {
-		return (new PackagePermissionCollection());
+		return new PackagePermissionCollection();
 	}
 
 	/**
@@ -313,22 +483,25 @@
 	 * @param obj The object to test for equality with this
 	 *        <code>PackagePermission</code> object.
 	 * @return <code>true</code> if <code>obj</code> is a
-	 *         <code>PackagePermission</code>, and has the same package name
-	 *         and actions as this <code>PackagePermission</code> object;
+	 *         <code>PackagePermission</code>, and has the same package name and
+	 *         actions as this <code>PackagePermission</code> object;
 	 *         <code>false</code> otherwise.
 	 */
 	public boolean equals(Object obj) {
 		if (obj == this) {
-			return (true);
+			return true;
 		}
 
 		if (!(obj instanceof PackagePermission)) {
-			return (false);
+			return false;
 		}
 
-		PackagePermission p = (PackagePermission) obj;
+		PackagePermission pp = (PackagePermission) obj;
 
-		return ((action_mask == p.action_mask) && getName().equals(p.getName()));
+		return (action_mask == pp.action_mask)
+				&& getName().equals(pp.getName())
+				&& ((bundle == pp.bundle) || ((bundle != null) && bundle
+						.equals(pp.bundle)));
 	}
 
 	/**
@@ -336,20 +509,13 @@
 	 * 
 	 * @return A hash code value for this object.
 	 */
-
 	public int hashCode() {
-		return (getName().hashCode() ^ getActions().hashCode());
-	}
-
-	/**
-	 * Returns the current action mask.
-	 * <p>
-	 * Used by the PackagePermissionCollection class.
-	 * 
-	 * @return Current action mask.
-	 */
-	int getMask() {
-		return (action_mask);
+		int h = 31 * 17 + getName().hashCode();
+		h = 31 * h + getActions().hashCode();
+		if (bundle != null) {
+			h = 31 * h + bundle.hashCode();
+		}
+		return h;
 	}
 
 	/**
@@ -357,9 +523,11 @@
 	 * stream. The actions are serialized, and the superclass takes care of the
 	 * name.
 	 */
-
 	private synchronized void writeObject(java.io.ObjectOutputStream s)
 			throws IOException {
+		if (bundle != null) {
+			throw new NotSerializableException("cannot serialize");
+		}
 		// Write out the actions. The superclass takes care of the name
 		// call getActions to make sure actions field is initialized
 		if (actions == null)
@@ -375,7 +543,41 @@
 			throws IOException, ClassNotFoundException {
 		// Read in the action, then initialize the rest
 		s.defaultReadObject();
-		init(getMask(actions));
+		setTransients(getName(), parseActions(actions));
+	}
+
+	/**
+	 * Called by <code><@link PackagePermission#implies(Permission)></code>.
+	 * 
+	 * @return a dictionary of properties for this permission.
+	 */
+	private Dictionary getProperties() {
+		Dictionary result = properties;
+		if (result != null) {
+			return result;
+		}
+		final Dictionary dict = new Hashtable(5);
+		if (filter == null) {
+			dict.put("package.name", getName());
+		}
+		if (bundle != null) {
+			AccessController.doPrivileged(new PrivilegedAction() {
+				public Object run() {
+					dict.put("id", new Long(bundle.getBundleId()));
+					dict.put("location", bundle.getLocation());
+					String name = bundle.getSymbolicName();
+					if (name != null) {
+						dict.put("name", name);
+					}
+					SignerProperty signer = new SignerProperty(bundle);
+					if (signer.isBundleSigned()) {
+						dict.put("signer", signer);
+					}
+					return null;
+				}
+			});
+		}
+		return properties = dict;
 	}
 }
 
@@ -388,73 +590,100 @@
  */
 
 final class PackagePermissionCollection extends PermissionCollection {
-	static final long	serialVersionUID	= -3350758995234427603L;
+	static final long		serialVersionUID	= -3350758995234427603L;
 	/**
-	 * Table of permissions.
+	 * Table of permissions with names.
 	 * 
-	 * @serial
+	 * @GuardedBy this
 	 */
-	private Hashtable	permissions;
+	private transient Map	permissions;
 
 	/**
 	 * Boolean saying if "*" is in the collection.
 	 * 
 	 * @serial
+	 * @GuardedBy this
 	 */
-	private boolean		all_allowed;
+	private boolean			all_allowed;
+
+	/**
+	 * Table of permissions with filter expressions.
+	 * 
+	 * @serial
+	 * @GuardedBy this
+	 */
+	private Map				filterPermissions;
 
 	/**
 	 * Create an empty PackagePermissions object.
 	 */
-
 	public PackagePermissionCollection() {
-		permissions = new Hashtable();
+		permissions = new HashMap();
 		all_allowed = false;
 	}
 
 	/**
-	 * Adds a permission to the <code>PackagePermission</code> objects. The
-	 * key for the hash is the name.
+	 * Adds a permission to this permission collection.
 	 * 
 	 * @param permission The <code>PackagePermission</code> object to add.
-	 * 
-	 * @throws IllegalArgumentException If the permission is not a
-	 *         <code>PackagePermission</code> instance.
-	 * 
+	 * @throws IllegalArgumentException If the specified permission is not a
+	 *         <code>PackagePermission</code> instance or was constructed with a
+	 *         Bundle object.
 	 * @throws SecurityException If this
 	 *         <code>PackagePermissionCollection</code> object has been marked
 	 *         read-only.
 	 */
-
-	public void add(Permission permission) {
-		if (!(permission instanceof PackagePermission))
+	public void add(final Permission permission) {
+		if (!(permission instanceof PackagePermission)) {
 			throw new IllegalArgumentException("invalid permission: "
 					+ permission);
-		if (isReadOnly())
+		}
+		if (isReadOnly()) {
 			throw new SecurityException("attempt to add a Permission to a "
 					+ "readonly PermissionCollection");
+		}
 
-		PackagePermission pp = (PackagePermission) permission;
-		String name = pp.getName();
+		final PackagePermission pp = (PackagePermission) permission;
+		if (pp.bundle != null) {
+			throw new IllegalArgumentException("cannot add to collection: "
+					+ pp);
+		}
 
-		PackagePermission existing = (PackagePermission) permissions.get(name);
-
-		if (existing != null) {
-			int oldMask = existing.getMask();
-			int newMask = pp.getMask();
-			if (oldMask != newMask) {
-				permissions.put(name, new PackagePermission(name, oldMask
-						| newMask));
-
+		final String name = pp.getName();
+		final Filter f = pp.filter;
+		synchronized (this) {
+			/* select the bucket for the permission */
+			Map pc;
+			if (f != null) {
+				pc = filterPermissions;
+				if (pc == null) {
+					filterPermissions = pc = new HashMap();
+				}
 			}
-		}
-		else {
-			permissions.put(name, permission);
-		}
+			else {
+				pc = permissions;
+			}
+			
+			final PackagePermission existing = (PackagePermission) pc.get(name);
+			if (existing != null) {
+				final int oldMask = existing.action_mask;
+				final int newMask = pp.action_mask;
+				if (oldMask != newMask) {
+					pc
+							.put(name, new PackagePermission(name, oldMask
+									| newMask));
 
-		if (!all_allowed) {
-			if (name.equals("*"))
-				all_allowed = true;
+				}
+			}
+			else {
+				pc.put(name, pp);
+			}
+
+			if (!all_allowed) {
+				if (name.equals("*")) {
+					all_allowed = true;
+				}
+			}
 		}
 	}
 
@@ -464,68 +693,80 @@
 	 * 
 	 * @param permission The Permission object to compare with this
 	 *        <code>PackagePermission</code> object.
-	 * 
-	 * @return <code>true</code> if <code>permission</code> is a proper
-	 *         subset of a permission in the set; <code>false</code>
-	 *         otherwise.
+	 * @return <code>true</code> if <code>permission</code> is a proper subset
+	 *         of a permission in the set; <code>false</code> otherwise.
 	 */
+	public boolean implies(final Permission permission) {
+		if (!(permission instanceof PackagePermission)) {
+			return false;
+		}
+		final PackagePermission requested = (PackagePermission) permission;
+		/* if requested permission has a filter, then it is an invalid argument */
+		if (requested.filter != null) {
+			return false;
+		}
+		String requestedName = requested.getName();
+		final int desired = requested.action_mask;
+		int effective = PackagePermission.ACTION_NONE;
 
-	public boolean implies(Permission permission) {
-		if (!(permission instanceof PackagePermission))
-			return (false);
-
-		PackagePermission pp = (PackagePermission) permission;
-		PackagePermission x;
-
-		int desired = pp.getMask();
-		int effective = 0;
-
-		// short circuit if the "*" Permission was added
-		if (all_allowed) {
-			x = (PackagePermission) permissions.get("*");
-			if (x != null) {
-				effective |= x.getMask();
-				if ((effective & desired) == desired)
-					return (true);
+		Collection perms;
+		synchronized (this) {
+			Map pc = permissions;
+			PackagePermission pp;
+			/* short circuit if the "*" Permission was added */
+			if (all_allowed) {
+				pp = (PackagePermission) pc.get("*");
+				if (pp != null) {
+					effective |= pp.action_mask;
+					if ((effective & desired) == desired) {
+						return true;
+					}
+				}
+			}
+			/*
+			 * strategy: Check for full match first. Then work our way up the
+			 * name looking for matches on a.b.*
+			 */
+			pp = (PackagePermission) pc.get(requestedName);
+			if (pp != null) {
+				/* we have a direct hit! */
+				effective |= pp.action_mask;
+				if ((effective & desired) == desired) {
+					return true;
+				}
+			}
+			/* work our way up the tree... */
+			int last;
+			int offset = requestedName.length() - 1;
+			while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+				requestedName = requestedName.substring(0, last + 1) + "*";
+				pp = (PackagePermission) pc.get(requestedName);
+				if (pp != null) {
+					effective |= pp.action_mask;
+					if ((effective & desired) == desired) {
+						return true;
+					}
+				}
+				offset = last - 1;
+			}
+			/*
+			 * we don't have to check for "*" as it was already checked before
+			 * we were called.
+			 */
+			pc = filterPermissions;
+			if (pc == null) {
+				return false;
+			}
+			perms = pc.values();
+		}
+		/* iterate one by one over filteredPermissions */
+		for (Iterator iter = perms.iterator(); iter.hasNext();) {
+			if (((PackagePermission) iter.next())
+					.implies0(requested, effective)) {
+				return true;
 			}
 		}
-
-		// strategy:
-		// Check for full match first. Then work our way up the
-		// name looking for matches on a.b.*
-
-		String name = pp.getName();
-
-		x = (PackagePermission) permissions.get(name);
-
-		if (x != null) {
-			// we have a direct hit!
-			effective |= x.getMask();
-			if ((effective & desired) == desired)
-				return (true);
-		}
-
-		// work our way up the tree...
-		int last, offset;
-
-		offset = name.length() - 1;
-
-		while ((last = name.lastIndexOf(".", offset)) != -1) {
-
-			name = name.substring(0, last + 1) + "*";
-			x = (PackagePermission) permissions.get(name);
-
-			if (x != null) {
-				effective |= x.getMask();
-				if ((effective & desired) == desired)
-					return (true);
-			}
-			offset = last - 1;
-		}
-
-		// we don't have to check for "*" as it was already checked
-		// at the top (all_allowed), so we just return false
-		return (false);
+		return false;
 	}
 
 	/**
@@ -534,8 +775,37 @@
 	 * 
 	 * @return Enumeration of all <code>PackagePermission</code> objects.
 	 */
+	public synchronized Enumeration elements() {
+		List all = new ArrayList(permissions.values());
+		Map pc = filterPermissions;
+		if (pc != null) {
+			all.addAll(pc.values());
+		}
+		return Collections.enumeration(all);
+	}
 
-	public Enumeration elements() {
-		return (permissions.elements());
+	/* serialization logic */
+	private static final ObjectStreamField[]	serialPersistentFields	= {
+			new ObjectStreamField("permissions", Hashtable.class),
+			new ObjectStreamField("all_allowed", Boolean.TYPE),
+			new ObjectStreamField("filterPermissions", HashMap.class)	};
+
+	private synchronized void writeObject(ObjectOutputStream out)
+			throws IOException {
+		Hashtable hashtable = new Hashtable(permissions);
+		ObjectOutputStream.PutField pfields = out.putFields();
+		pfields.put("permissions", hashtable);
+		pfields.put("all_allowed", all_allowed);
+		pfields.put("filterPermissions", filterPermissions);
+		out.writeFields();
+	}
+
+	private synchronized void readObject(java.io.ObjectInputStream in)
+			throws IOException, ClassNotFoundException {
+		ObjectInputStream.GetField gfields = in.readFields();
+		Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+		permissions = new HashMap(hashtable);
+		all_allowed = gfields.get("all_allowed", false);
+		filterPermissions = (HashMap) gfields.get("filterPermissions", null);
 	}
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceEvent.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceEvent.java
index 6f76863..b7c9928 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServiceEvent.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceEvent.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServiceEvent.java,v 1.15 2007/02/20 00:14:12 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -18,14 +16,15 @@
 
 package org.osgi.framework;
 
+import java.util.Dictionary;
 import java.util.EventObject;
 
 /**
  * An event from the Framework describing a service lifecycle change.
  * <p>
  * <code>ServiceEvent</code> objects are delivered to
- * <code>ServiceListener</code>s and <code>AllServiceListener</code>s when
- * a change occurs in this service's lifecycle. A type code is used to identify
+ * <code>ServiceListener</code>s and <code>AllServiceListener</code>s when a
+ * change occurs in this service's lifecycle. A type code is used to identify
  * the event type for future extendability.
  * 
  * <p>
@@ -34,7 +33,7 @@
  * @Immutable
  * @see ServiceListener
  * @see AllServiceListener
- * @version $Revision: 1.15 $
+ * @version $Revision: 6542 $
  */
 
 public class ServiceEvent extends EventObject {
@@ -55,10 +54,7 @@
 	 * This event is synchronously delivered <strong>after</strong> the service
 	 * has been registered with the Framework.
 	 * 
-	 * <p>
-	 * The value of <code>REGISTERED</code> is 0x00000001.
-	 * 
-	 * @see BundleContext#registerService(String[],Object,java.util.Dictionary)
+	 * @see BundleContext#registerService(String[],Object,Dictionary)
 	 */
 	public final static int			REGISTERED			= 0x00000001;
 
@@ -68,9 +64,6 @@
 	 * This event is synchronously delivered <strong>after</strong> the service
 	 * properties have been modified.
 	 * 
-	 * <p>
-	 * The value of <code>MODIFIED</code> is 0x00000002.
-	 * 
 	 * @see ServiceRegistration#setProperties
 	 */
 	public final static int			MODIFIED			= 0x00000002;
@@ -78,8 +71,8 @@
 	/**
 	 * This service is in the process of being unregistered.
 	 * <p>
-	 * This event is synchronously delivered <strong>before</strong> the
-	 * service has completed unregistering.
+	 * This event is synchronously delivered <strong>before</strong> the service
+	 * has completed unregistering.
 	 * 
 	 * <p>
 	 * If a bundle is using a service that is <code>UNREGISTERING</code>, the
@@ -88,20 +81,32 @@
 	 * this event, the Framework will automatically release the bundle's use of
 	 * the service while completing the service unregistration operation.
 	 * 
-	 * <p>
-	 * The value of UNREGISTERING is 0x00000004.
-	 * 
 	 * @see ServiceRegistration#unregister
 	 * @see BundleContext#ungetService
 	 */
 	public final static int			UNREGISTERING		= 0x00000004;
 
 	/**
+	 * The properties of a registered service have been modified and the new
+	 * properties no longer match the listener's filter.
+	 * <p>
+	 * This event is synchronously delivered <strong>after</strong> the service
+	 * properties have been modified. This event is only delivered to listeners
+	 * which were added with a non-<code>null</code> filter where the filter
+	 * matched the service properties prior to the modification but the filter
+	 * does not match the modified service properties.
+	 * 
+	 * @see ServiceRegistration#setProperties
+	 * @since 1.5
+	 */
+	public final static int			MODIFIED_ENDMATCH	= 0x00000008;
+
+	/**
 	 * Creates a new service event object.
 	 * 
 	 * @param type The event type.
 	 * @param reference A <code>ServiceReference</code> object to the service
-	 *        that had a lifecycle change.
+	 * 	that had a lifecycle change.
 	 */
 	public ServiceEvent(int type, ServiceReference reference) {
 		super(reference);
@@ -124,9 +129,10 @@
 	/**
 	 * Returns the type of event. The event type values are:
 	 * <ul>
-	 * <li>{@link #REGISTERED}
-	 * <li>{@link #MODIFIED}
-	 * <li>{@link #UNREGISTERING}
+	 * <li>{@link #REGISTERED} </li> 
+	 * <li>{@link #MODIFIED} </li> 
+	 * <li>{@link #MODIFIED_ENDMATCH} </li> 
+	 * <li>{@link #UNREGISTERING} </li>
 	 * </ul>
 	 * 
 	 * @return Type of service lifecycle change.
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceException.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceException.java
new file mode 100644
index 0000000..4cf04a0
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceException.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) OSGi Alliance (2007, 2009). 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.framework;
+
+/**
+ * A service exception used to indicate that a service problem occurred.
+ * 
+ * <p>
+ * A <code>ServiceException</code> object is created by the Framework or
+ * service implementation to denote an exception condition in the service. A
+ * type code is used to identify the exception type for future extendability.
+ * Service implementations may also create subclasses of
+ * <code>ServiceException</code>. When subclassing, the subclass should set
+ * the type to {@link #SUBCLASSED} to indicate that
+ * <code>ServiceException</code> has been subclassed.
+ * 
+ * <p>
+ * This exception conforms to the general purpose exception chaining mechanism.
+ * 
+ * @version $Revision: 6518 $
+ * @since 1.5
+ */
+
+public class ServiceException extends RuntimeException {
+	static final long		serialVersionUID	= 3038963223712959631L;
+
+	/**
+	 * Type of service exception.
+	 */
+	private final int		type;
+
+	/**
+	 * No exception type is unspecified.
+	 */
+	public static final int	UNSPECIFIED			= 0;
+	/**
+	 * The service has been unregistered.
+	 */
+	public static final int	UNREGISTERED		= 1;
+	/**
+	 * The service factory produced an invalid service object.
+	 */
+	public static final int	FACTORY_ERROR		= 2;
+	/**
+	 * The service factory threw an exception.
+	 */
+	public static final int	FACTORY_EXCEPTION	= 3;
+	/**
+	 * The exception is a subclass of ServiceException. The subclass should be
+	 * examined for the type of the exception.
+	 */
+	public static final int	SUBCLASSED			= 4;
+	/**
+	 * An error occurred invoking a remote service.
+	 */
+	public static final int REMOTE 				= 5;
+
+	/**
+	 * Creates a <code>ServiceException</code> with the specified message and
+	 * exception cause.
+	 * 
+	 * @param msg The associated message.
+	 * @param cause The cause of this exception.
+	 */
+	public ServiceException(String msg, Throwable cause) {
+		this(msg, UNSPECIFIED, cause);
+	}
+
+	/**
+	 * Creates a <code>ServiceException</code> with the specified message.
+	 * 
+	 * @param msg The message.
+	 */
+	public ServiceException(String msg) {
+		this(msg, UNSPECIFIED);
+	}
+
+	/**
+	 * Creates a <code>ServiceException</code> with the specified message,
+	 * type and exception cause.
+	 * 
+	 * @param msg The associated message.
+	 * @param type The type for this exception.
+	 * @param cause The cause of this exception.
+	 */
+	public ServiceException(String msg, int type, Throwable cause) {
+		super(msg, cause);
+		this.type = type;
+	}
+
+	/**
+	 * Creates a <code>ServiceException</code> with the specified message and
+	 * type.
+	 * 
+	 * @param msg The message.
+	 * @param type The type for this exception.
+	 */
+	public ServiceException(String msg, int type) {
+		super(msg);
+		this.type = type;
+	}
+
+	/**
+	 * Returns the type for this exception or <code>UNSPECIFIED</code> if the
+	 * type was unspecified or unknown.
+	 * 
+	 * @return The type of this exception.
+	 */
+	public int getType() {
+		return type;
+	}
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceFactory.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceFactory.java
index 1a3b3d2..c8f6bf3 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServiceFactory.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceFactory.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServiceFactory.java,v 1.10 2007/02/20 00:16:30 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). 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.
@@ -48,7 +46,7 @@
  * 
  * @see BundleContext#getService
  * @ThreadSafe
- * @version $Revision: 1.10 $
+ * @version $Revision: 5967 $
  */
 
 public interface ServiceFactory {
@@ -65,7 +63,9 @@
 	 * <p>
 	 * The Framework caches the value returned (unless it is <code>null</code>),
 	 * and will return the same service object on any future call to
-	 * <code>BundleContext.getService</code> from the same bundle.
+	 * <code>BundleContext.getService</code> for the same bundle. This means the
+	 * Framework must not allow this method to be concurrently called for the
+	 * same bundle.
 	 * 
 	 * <p>
 	 * The Framework will check if the returned service object is an instance of
@@ -75,8 +75,8 @@
 	 * @param bundle The bundle using the service.
 	 * @param registration The <code>ServiceRegistration</code> object for the
 	 *        service.
-	 * @return A service object that <strong>must </strong> be an instance of
-	 *         all the classes named when the service was registered.
+	 * @return A service object that <strong>must</strong> be an instance of all
+	 *         the classes named when the service was registered.
 	 * @see BundleContext#getService
 	 */
 	public Object getService(Bundle bundle, ServiceRegistration registration);
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceListener.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceListener.java
index 8d9464e..ec08560 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServiceListener.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceListener.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServiceListener.java,v 1.15 2007/02/20 00:16:30 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). 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.
@@ -53,7 +51,7 @@
  * @see ServiceEvent
  * @see ServicePermission
  * @ThreadSafe
- * @version $Revision: 1.15 $
+ * @version $Revision: 5673 $
  */
 
 public interface ServiceListener extends EventListener {
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServicePermission.java b/org.osgi.core/src/main/java/org/osgi/framework/ServicePermission.java
index 4f10f09..d1fb70f 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServicePermission.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServicePermission.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServicePermission.java,v 1.15 2007/02/20 00:06:02 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -19,34 +17,51 @@
 package org.osgi.framework;
 
 import java.io.IOException;
-import java.security.*;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.security.AccessController;
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 /**
  * A bundle's authority to register or get a service.
  * <ul>
- * <li>The <code>ServicePermission.REGISTER</code> action allows a bundle to
- * register a service on the specified names.
- * <li>The <code>ServicePermission.GET</code> action allows a bundle to
- * detect a service and get it.
+ * <li>The <code>register</code> action allows a bundle to register a service on
+ * the specified names.
+ * <li>The <code>get</code> action allows a bundle to detect a service and get
+ * it.
  * </ul>
  * Permission to get a service is required in order to detect events regarding
  * the service. Untrusted bundles should not be able to detect the presence of
  * certain services unless they have the appropriate
  * <code>ServicePermission</code> to get the specific service.
  * 
- * @version $Revision: 1.15 $
+ * @ThreadSafe
+ * @version $Revision: 6530 $
  */
 
-final public class ServicePermission extends BasicPermission {
+public final class ServicePermission extends BasicPermission {
 	static final long			serialVersionUID	= -7662148639076511574L;
 	/**
-	 * The action string <code>get</code> (Value is "get").
+	 * The action string <code>get</code>.
 	 */
 	public final static String	GET					= "get";
 	/**
-	 * The action string <code>register</code> (Value is "register").
+	 * The action string <code>register</code>.
 	 */
 	public final static String	REGISTER			= "register";
 
@@ -54,27 +69,65 @@
 	private final static int	ACTION_REGISTER		= 0x00000002;
 	private final static int	ACTION_ALL			= ACTION_GET
 															| ACTION_REGISTER;
-	private final static int	ACTION_NONE			= 0;
+	final static int						ACTION_NONE			= 0;
+
 	/**
 	 * The actions mask.
 	 */
-	private transient int		action_mask			= ACTION_NONE;
+	transient int							action_mask;
 
 	/**
 	 * The actions in canonical form.
 	 * 
 	 * @serial
 	 */
-	private String				actions				= null;
+	private volatile String		actions				= null;
+
+	/**
+	 * The service used by this ServicePermission. Must be null if not
+	 * constructed with a service.
+	 */
+	transient final ServiceReference		service;
+
+	/**
+	 * The object classes for this ServicePermission. Must be null if not
+	 * constructed with a service.
+	 */
+	transient final String[]				objectClass;
+
+	/**
+	 * If this ServicePermission was constructed with a filter, this holds a
+	 * Filter matching object used to evaluate the filter in implies.
+	 */
+	transient Filter						filter;
+
+	/**
+	 * This dictionary holds the properties of the permission, used to match a
+	 * filter in implies. This is not initialized until necessary, and then
+	 * cached in this object.
+	 */
+	private transient volatile Dictionary	properties;
+
+	/**
+	 * True if constructed with a name and the name is "*" or ends with ".*".
+	 */
+	private transient boolean				wildcard;
+
+	/**
+	 * If constructed with a name and the name ends with ".*", this contains the
+	 * name without the final "*".
+	 */
+	private transient String				prefix;
 
 	/**
 	 * Create a new ServicePermission.
 	 * 
 	 * <p>
 	 * The name of the service is specified as a fully qualified class name.
+	 * Wildcards may be used.
 	 * 
 	 * <pre>
-	 * ClassName ::= &lt;class name&gt; | &lt;class name ending in &quot;.*&quot;&gt;
+	 * name ::= &lt;class name&gt; | &lt;class name ending in &quot;.*&quot;&gt; | *
 	 * </pre>
 	 * 
 	 * Examples:
@@ -82,23 +135,88 @@
 	 * <pre>
 	 * org.osgi.service.http.HttpService
 	 * org.osgi.service.http.*
-	 * org.osgi.service.snmp.*
+	 * *
 	 * </pre>
 	 * 
+	 * For the <code>get</code> action, the name can also be a filter
+	 * expression. The filter gives access to the service properties as well as
+	 * the following attributes:
+	 * <ul>
+	 * <li>signer - A Distinguished Name chain used to sign the bundle
+	 * publishing the service. Wildcards in a DN are not matched according to
+	 * the filter string rules, but according to the rules defined for a DN
+	 * chain.</li>
+	 * <li>location - The location of the bundle publishing the service.</li>
+	 * <li>id - The bundle ID of the bundle publishing the service.</li>
+	 * <li>name - The symbolic name of the bundle publishing the service.</li>
+	 * </ul>
+	 * Since the above attribute names may conflict with service property names
+	 * used by a service, you can prefix an attribute name with '@' in the
+	 * filter expression to match against the service property and not one of
+	 * the above attributes. Filter attribute names are processed in a case
+	 * sensitive manner unless the attribute references a service property.
+	 * Service properties names are case insensitive.
+	 * 
 	 * <p>
 	 * There are two possible actions: <code>get</code> and
-	 * <code>register</code>. The <code>get</code> permission allows the
-	 * owner of this permission to obtain a service with this name. The
-	 * <code>register</code> permission allows the bundle to register a
-	 * service under that name.
+	 * <code>register</code>. The <code>get</code> permission allows the owner
+	 * of this permission to obtain a service with this name. The
+	 * <code>register</code> permission allows the bundle to register a service
+	 * under that name.
 	 * 
-	 * @param name class name
-	 * @param actions <code>get</code>,<code>register</code> (canonical
-	 *        order)
+	 * @param name The service class name
+	 * @param actions <code>get</code>,<code>register</code> (canonical order)
+	 * @throw IllegalArgumentException If the specified name is a filter
+	 *        expression and either the specified action is not <code>get</code>
+	 *        or the filter has an invalid syntax.
 	 */
-
 	public ServicePermission(String name, String actions) {
-		this(name, getMask(actions));
+		this(name, parseActions(actions));
+		if ((filter != null)
+				&& ((action_mask & ACTION_ALL) != ACTION_GET)) {
+			throw new IllegalArgumentException(
+					"invalid action string for filter expression");
+		}
+	}
+
+	/**
+	 * Creates a new requested <code>ServicePermission</code> object to be used
+	 * by code that must perform <code>checkPermission</code> for the
+	 * <code>get</code> action. <code>ServicePermission</code> objects created
+	 * with this constructor cannot be added to a <code>ServicePermission</code>
+	 * permission collection.
+	 * 
+	 * @param reference The requested service.
+	 * @param actions The action <code>get</code>.
+	 * @throw IllegalArgumentException If the specified action is not
+	 *        <code>get</code> or reference is <code>null</code>.
+	 * @since 1.5
+	 */
+	public ServicePermission(ServiceReference reference, String actions) {
+		super(createName(reference));
+		setTransients(null, parseActions(actions));
+		this.service = reference;
+		this.objectClass = (String[]) reference
+				.getProperty(Constants.OBJECTCLASS);
+		if ((action_mask & ACTION_ALL) != ACTION_GET) {
+			throw new IllegalArgumentException("invalid action string");
+		}
+	}
+
+	/**
+	 * Create a permission name from a ServiceReference
+	 * 
+	 * @param reference ServiceReference to use to create permission name.
+	 * @return permission name.
+	 */
+	private static String createName(ServiceReference reference) {
+		if (reference == null) {
+			throw new IllegalArgumentException("reference must not be null");
+		}
+		StringBuffer sb = new StringBuffer("(service.id=");
+		sb.append(reference.getProperty(Constants.SERVICE_ID));
+		sb.append(")");
+		return sb.toString();
 	}
 
 	/**
@@ -109,8 +227,9 @@
 	 */
 	ServicePermission(String name, int mask) {
 		super(name);
-
-		init(mask);
+		setTransients(parseFilter(name), mask);
+		this.service = null;
+		this.objectClass = null;
 	}
 
 	/**
@@ -118,12 +237,22 @@
 	 * 
 	 * @param mask action mask
 	 */
-	private void init(int mask) {
+	private void setTransients(Filter f, int mask) {
 		if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
 			throw new IllegalArgumentException("invalid action string");
 		}
-
 		action_mask = mask;
+		filter = f;
+		if (f == null) {
+			String name = getName();
+			int l = name.length();
+			/* if "*" or endsWith ".*" */
+			wildcard = ((name.charAt(l - 1) == '*') && ((l == 1) || (name
+					.charAt(l - 2) == '.')));
+			if (wildcard && (l > 1)) {
+				prefix = name.substring(0, l - 1);
+			}
+		}
 	}
 
 	/**
@@ -132,7 +261,7 @@
 	 * @param actions Action string.
 	 * @return action mask.
 	 */
-	private static int getMask(String actions) {
+	private static int parseActions(String actions) {
 		boolean seencomma = false;
 
 		int mask = ACTION_NONE;
@@ -218,23 +347,105 @@
 	}
 
 	/**
+	 * Parse filter string into a Filter object.
+	 * 
+	 * @param filterString The filter string to parse.
+	 * @return a Filter for this bundle. If the specified filterString is not a
+	 *         filter expression, then <code>null</code> is returned.
+	 * @throws IllegalArgumentException If the filter syntax is invalid.
+	 */
+	private static Filter parseFilter(String filterString) {
+		filterString = filterString.trim();
+		if (filterString.charAt(0) != '(') {
+			return null;
+		}
+
+		try {
+			return FrameworkUtil.createFilter(filterString);
+		}
+		catch (InvalidSyntaxException e) {
+			IllegalArgumentException iae = new IllegalArgumentException(
+					"invalid filter");
+			iae.initCause(e);
+			throw iae;
+		}
+	}
+
+	/**
 	 * Determines if a <code>ServicePermission</code> object "implies" the
 	 * specified permission.
 	 * 
 	 * @param p The target permission to check.
-	 * @return <code>true</code> if the specified permission is implied by
-	 *         this object; <code>false</code> otherwise.
+	 * @return <code>true</code> if the specified permission is implied by this
+	 *         object; <code>false</code> otherwise.
 	 */
-
 	public boolean implies(Permission p) {
-		if (p instanceof ServicePermission) {
-			ServicePermission target = (ServicePermission) p;
-
-			return (((action_mask & target.action_mask) == target.action_mask) && super
-					.implies(p));
+		if (!(p instanceof ServicePermission)) {
+			return false;
 		}
+		ServicePermission requested = (ServicePermission) p;
+		if (service != null) {
+			return false;
+		}
+		// if requested permission has a filter, then it is an invalid argument
+		if (requested.filter != null) {
+			return false;
+		}
+		return implies0(requested, ACTION_NONE);
+	}
 
-		return (false);
+	/**
+	 * Internal implies method. Used by the implies and the permission
+	 * collection implies methods.
+	 * 
+	 * @param requested The requested ServicePermission which has already be
+	 *        validated as a proper argument. The requested ServicePermission
+	 *        must not have a filter expression.
+	 * @param effective The effective actions with which to start.
+	 * @return <code>true</code> if the specified permission is implied by this
+	 *         object; <code>false</code> otherwise.
+	 */
+	boolean implies0(ServicePermission requested, int effective) {
+		/* check actions first - much faster */
+		effective |= action_mask;
+		final int desired = requested.action_mask;
+		if ((effective & desired) != desired) {
+			return false;
+		}
+		/* we have name of "*" */
+		if (wildcard && (prefix == null)) {
+			return true;
+		}
+		/* if we have a filter */
+		Filter f = filter;
+		if (f != null) {
+			return f.matchCase(requested.getProperties());
+		}
+		/* if requested permission not created with ServiceReference */
+		String[] requestedNames = requested.objectClass;
+		if (requestedNames == null) {
+			return super.implies(requested);
+		}
+		/* requested permission created with ServiceReference */
+		if (wildcard) {
+			int pl = prefix.length();
+			for (int i = 0, l = requestedNames.length; i < l; i++) {
+				String requestedName = requestedNames[i];
+				if ((requestedName.length() > pl)
+						&& requestedName.startsWith(prefix)) {
+					return true;
+				}
+			}
+		}
+		else {
+			String name = getName();
+			for (int i = 0, l = requestedNames.length; i < l; i++) {
+				if (requestedNames[i].equals(name)) {
+					return true;
+				}
+			}
+		}
+		return false;
 	}
 
 	/**
@@ -245,25 +456,27 @@
 	 * @return The canonical string representation of the actions.
 	 */
 	public String getActions() {
-		if (actions == null) {
+		String result = actions;
+		if (result == null) {
 			StringBuffer sb = new StringBuffer();
 			boolean comma = false;
 
-			if ((action_mask & ACTION_GET) == ACTION_GET) {
+			int mask = action_mask;
+			if ((mask & ACTION_GET) == ACTION_GET) {
 				sb.append(GET);
 				comma = true;
 			}
 
-			if ((action_mask & ACTION_REGISTER) == ACTION_REGISTER) {
+			if ((mask & ACTION_REGISTER) == ACTION_REGISTER) {
 				if (comma)
 					sb.append(',');
 				sb.append(REGISTER);
 			}
 
-			actions = sb.toString();
+			actions = result = sb.toString();
 		}
 
-		return (actions);
+		return result;
 	}
 
 	/**
@@ -274,33 +487,35 @@
 	 * <code>ServicePermission</code> objects.
 	 */
 	public PermissionCollection newPermissionCollection() {
-		return (new ServicePermissionCollection());
+		return new ServicePermissionCollection();
 	}
 
 	/**
-	 * Determines the equalty of two ServicePermission objects.
+	 * Determines the equality of two ServicePermission objects.
 	 * 
 	 * Checks that specified object has the same class name and action as this
 	 * <code>ServicePermission</code>.
 	 * 
 	 * @param obj The object to test for equality.
-	 * @return true if obj is a <code>ServicePermission</code>, and has the
-	 *         same class name and actions as this
-	 *         <code>ServicePermission</code> object; <code>false</code>
-	 *         otherwise.
+	 * @return true if obj is a <code>ServicePermission</code>, and has the same
+	 *         class name and actions as this <code>ServicePermission</code>
+	 *         object; <code>false</code> otherwise.
 	 */
 	public boolean equals(Object obj) {
 		if (obj == this) {
-			return (true);
+			return true;
 		}
 
 		if (!(obj instanceof ServicePermission)) {
-			return (false);
+			return false;
 		}
 
-		ServicePermission p = (ServicePermission) obj;
+		ServicePermission sp = (ServicePermission) obj;
 
-		return ((action_mask == p.action_mask) && getName().equals(p.getName()));
+		return (action_mask == sp.action_mask)
+				&& getName().equals(sp.getName())
+				&& ((service == sp.service) || ((service != null) && (service
+						.compareTo(sp.service) == 0)));
 	}
 
 	/**
@@ -308,28 +523,24 @@
 	 * 
 	 * @return Hash code value for this object.
 	 */
-
 	public int hashCode() {
-		return (getName().hashCode() ^ getActions().hashCode());
-	}
-
-	/**
-	 * Returns the current action mask. Used by the ServicePermissionCollection
-	 * object.
-	 * 
-	 * @return The actions mask.
-	 */
-	int getMask() {
-		return (action_mask);
+		int h = 31 * 17 + getName().hashCode();
+		h = 31 * h + getActions().hashCode();
+		if (service != null) {
+			h = 31 * h + service.hashCode();
+		}
+		return h;
 	}
 
 	/**
 	 * WriteObject is called to save the state of this permission to a stream.
 	 * The actions are serialized, and the superclass takes care of the name.
 	 */
-
 	private synchronized void writeObject(java.io.ObjectOutputStream s)
 			throws IOException {
+		if (service != null) {
+			throw new NotSerializableException("cannot serialize");
+		}
 		// Write out the actions. The superclass takes care of the name
 		// call getActions to make sure actions field is initialized
 		if (actions == null)
@@ -345,7 +556,123 @@
 			throws IOException, ClassNotFoundException {
 		// Read in the action, then initialize the rest
 		s.defaultReadObject();
-		init(getMask(actions));
+		setTransients(parseFilter(getName()), parseActions(actions));
+	}
+	/**
+	 * Called by <code><@link ServicePermission#implies(Permission)></code>.
+	 * 
+	 * @return a dictionary of properties for this permission.
+	 */
+	private Dictionary getProperties() {
+		Dictionary result = properties;
+		if (result != null) {
+			return result;
+		}
+		if (service == null) {
+			result = new Hashtable(1);
+			if (filter == null) {
+				result.put(Constants.OBJECTCLASS, new String[] {getName()});
+			}
+			return properties = result;
+		}
+		final Map props = new HashMap(4);
+		final Bundle bundle = service.getBundle();
+		if (bundle != null) {
+			AccessController.doPrivileged(new PrivilegedAction() {
+				public Object run() {
+					props.put("id", new Long(bundle.getBundleId()));
+					props.put("location", bundle.getLocation());
+					String name = bundle.getSymbolicName();
+					if (name != null) {
+						props.put("name", name);
+					}
+					SignerProperty signer = new SignerProperty(bundle);
+					if (signer.isBundleSigned()) {
+						props.put("signer", signer);
+					}
+					return null;
+				}
+			});
+		}
+		return properties = new Properties(props, service);
+	}
+	
+	private static class Properties extends Dictionary {
+		private final Map				properties;
+		private final ServiceReference	service;
+
+		Properties(Map properties, ServiceReference service) {
+			this.properties = properties;
+			this.service = service;
+		}
+
+		public Object get(Object k) {
+			if (!(k instanceof String)) {
+				return null;
+			}
+			String key = (String) k;
+			if (key.charAt(0) == '@') {
+				return service.getProperty(key.substring(1));
+			}
+			Object value = properties.get(key);
+			if (value != null) { // fall back to service properties
+				return value;
+			}
+			return service.getProperty(key);
+		}
+
+		public int size() {
+			return properties.size() + service.getPropertyKeys().length;
+		}
+
+		public boolean isEmpty() {
+			// we can return false because this must never be empty
+			return false;
+		}
+
+		public Enumeration keys() {
+			Collection pk = properties.keySet();
+			String spk[] = service.getPropertyKeys();
+			List all = new ArrayList(pk.size() + spk.length);
+			all.addAll(pk);
+			add:
+			for (int i = 0, length = spk.length; i < length; i++) {
+				String key = spk[i];
+				for (Iterator iter = pk.iterator(); iter.hasNext();) {
+					if (key.equalsIgnoreCase((String) iter.next())) {
+						continue add;
+					}
+				}
+				all.add(key);
+			}
+			return Collections.enumeration(all);
+		}
+
+		public Enumeration elements() {
+			Collection pk = properties.keySet();
+			String spk[] = service.getPropertyKeys();
+			List all = new ArrayList(pk.size() + spk.length);
+			all.addAll(properties.values());
+			add:
+			for (int i = 0, length = spk.length; i < length; i++) {
+				String key = spk[i];
+				for (Iterator iter = pk.iterator(); iter.hasNext();) {
+					if (key.equalsIgnoreCase((String) iter.next())) {
+						continue add;
+					}
+				}
+				all.add(service.getProperty(key));
+			}
+			return Collections.enumeration(all);
+		}
+
+		public Object put(Object key, Object value) {
+			throw new UnsupportedOperationException();
+		}
+
+		public Object remove(Object key) {
+			throw new UnsupportedOperationException();
+		}
 	}
 }
 
@@ -356,73 +683,99 @@
  * @see java.security.Permissions
  * @see java.security.PermissionCollection
  */
-
 final class ServicePermissionCollection extends PermissionCollection {
 	static final long	serialVersionUID	= 662615640374640621L;
 	/**
 	 * Table of permissions.
 	 * 
-	 * @serial
+	 * @GuardedBy this
 	 */
-	private Hashtable	permissions;
+	private transient Map	permissions;
 
 	/**
 	 * Boolean saying if "*" is in the collection.
 	 * 
 	 * @serial
+	 * @GuardedBy this
 	 */
 	private boolean		all_allowed;
 
 	/**
+	 * Table of permissions with filter expressions.
+	 * 
+	 * @serial
+	 * @GuardedBy this
+	 */
+	private Map				filterPermissions;
+
+	/**
 	 * Creates an empty ServicePermissions object.
 	 */
-
 	public ServicePermissionCollection() {
-		permissions = new Hashtable();
+		permissions = new HashMap();
 		all_allowed = false;
 	}
 
 	/**
-	 * Adds a permission to the <code>ServicePermission</code> objects using
-	 * the key for the hash as the name.
+	 * Adds a permission to this permission collection.
 	 * 
 	 * @param permission The Permission object to add.
-	 * 
-	 * @throws IllegalArgumentException If the permission is not a
+	 * @throws IllegalArgumentException If the specified permission is not a
 	 *         ServicePermission object.
 	 * @throws SecurityException If this
 	 *         <code>ServicePermissionCollection</code> object has been marked
 	 *         read-only.
 	 */
-
-	public void add(Permission permission) {
-		if (!(permission instanceof ServicePermission))
+	public void add(final Permission permission) {
+		if (!(permission instanceof ServicePermission)) {
 			throw new IllegalArgumentException("invalid permission: "
 					+ permission);
-		if (isReadOnly())
+		}
+		if (isReadOnly()) {
 			throw new SecurityException("attempt to add a Permission to a "
 					+ "readonly PermissionCollection");
+		}
 
-		ServicePermission sp = (ServicePermission) permission;
-		String name = sp.getName();
-
-		ServicePermission existing = (ServicePermission) permissions.get(name);
-
-		if (existing != null) {
-			int oldMask = existing.getMask();
-			int newMask = sp.getMask();
-			if (oldMask != newMask) {
-				permissions.put(name, new ServicePermission(name, oldMask
-						| newMask));
+		final ServicePermission sp = (ServicePermission) permission;
+		if (sp.service != null) {
+			throw new IllegalArgumentException("cannot add to collection: "
+					+ sp);
+		}
+		
+		final String name = sp.getName();
+		final Filter f = sp.filter;
+		synchronized (this) {
+			/* select the bucket for the permission */
+			Map pc;
+			if (f != null) {
+				pc = filterPermissions;
+				if (pc == null) {
+					filterPermissions = pc = new HashMap();
+				}
 			}
-		}
-		else {
-			permissions.put(name, permission);
-		}
-
-		if (!all_allowed) {
-			if (name.equals("*"))
-				all_allowed = true;
+			else {
+				pc = permissions;
+			}
+			final ServicePermission existing = (ServicePermission) pc.get(name);
+			
+			if (existing != null) {
+				final int oldMask = existing.action_mask;
+				final int newMask = sp.action_mask;
+				if (oldMask != newMask) {
+					pc
+							.put(name, new ServicePermission(name, oldMask
+							| newMask));
+				}
+			}
+			else {
+				pc.put(name, sp);
+			}
+			
+			if (!all_allowed) {
+				if (name.equals("*")) {
+					all_allowed = true;
+				}
+			}
 		}
 	}
 
@@ -431,78 +784,149 @@
 	 * <code>permission</code>.
 	 * 
 	 * @param permission The Permission object to compare.
-	 * 
 	 * @return <code>true</code> if <code>permission</code> is a proper
 	 *         subset of a permission in the set; <code>false</code>
 	 *         otherwise.
 	 */
-
-	public boolean implies(Permission permission) {
-		if (!(permission instanceof ServicePermission))
-			return (false);
-
-		ServicePermission sp = (ServicePermission) permission;
-		ServicePermission x;
-
-		int desired = sp.getMask();
-		int effective = 0;
-
-		// short circuit if the "*" Permission was added
-		if (all_allowed) {
-			x = (ServicePermission) permissions.get("*");
-			if (x != null) {
-				effective |= x.getMask();
-				if ((effective & desired) == desired)
-					return (true);
-			}
+	public boolean implies(final Permission permission) {
+		if (!(permission instanceof ServicePermission)) {
+			return false;
+		}
+		final ServicePermission requested = (ServicePermission) permission;
+		/* if requested permission has a filter, then it is an invalid argument */
+		if (requested.filter != null) {
+			return false;
 		}
 
+		int effective = ServicePermission.ACTION_NONE;
+		Collection perms;
+		synchronized (this) {
+			final int desired = requested.action_mask;
+			/* short circuit if the "*" Permission was added */
+			if (all_allowed) {
+				ServicePermission sp = (ServicePermission) permissions.get("*");
+				if (sp != null) {
+					effective |= sp.action_mask;
+					if ((effective & desired) == desired) {
+						return true;
+					}
+				}
+			}
+			
+			String[] requestedNames = requested.objectClass;
+			/* if requested permission not created with ServiceReference */
+			if (requestedNames == null) {
+				effective |= effective(requested.getName(), desired, effective);
+				if ((effective & desired) == desired) {
+					return true;
+				}
+			}
+			/* requested permission created with ServiceReference */
+			else {
+				for (int i = 0, l = requestedNames.length; i < l; i++) {
+					if ((effective(requestedNames[i], desired, effective) & desired) == desired) {
+						return true;
+					}
+				}
+			}
+			Map pc = filterPermissions;
+			if (pc == null) {
+				return false;
+			}
+			perms = pc.values();
+		}
+		
+		/* iterate one by one over filteredPermissions */
+		for (Iterator iter = perms.iterator(); iter.hasNext();) {
+			if (((ServicePermission) iter.next())
+					.implies0(requested, effective)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Consult permissions map to compute the effective permission for the
+	 * requested permission name.
+	 * 
+	 * @param requestedName The requested service name.
+	 * @param desired The desired actions.
+	 * @param effective The effective actions.
+	 * @return The new effective actions.
+	 */
+	private int effective(String requestedName, final int desired,
+			int effective) {
+		final Map pc = permissions;
+		ServicePermission sp = (ServicePermission) pc.get(requestedName);
 		// strategy:
 		// Check for full match first. Then work our way up the
 		// name looking for matches on a.b.*
-
-		String name = sp.getName();
-
-		x = (ServicePermission) permissions.get(name);
-
-		if (x != null) {
+		if (sp != null) {
 			// we have a direct hit!
-			effective |= x.getMask();
-			if ((effective & desired) == desired)
-				return (true);
+			effective |= sp.action_mask;
+			if ((effective & desired) == desired) {
+				return effective;
+			}
 		}
-
 		// work our way up the tree...
-		int last, offset;
-
-		offset = name.length() - 1;
-
-		while ((last = name.lastIndexOf(".", offset)) != -1) {
-
-			name = name.substring(0, last + 1) + "*";
-			x = (ServicePermission) permissions.get(name);
-
-			if (x != null) {
-				effective |= x.getMask();
-				if ((effective & desired) == desired)
-					return (true);
+		int last;
+		int offset = requestedName.length() - 1;
+		while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+			requestedName = requestedName.substring(0, last + 1) + "*";
+			sp = (ServicePermission) pc.get(requestedName);
+			if (sp != null) {
+				effective |= sp.action_mask;
+				if ((effective & desired) == desired) {
+					return effective;
+				}
 			}
 			offset = last - 1;
 		}
-
-		// we don't have to check for "*" as it was already checked
-		// at the top (all_allowed), so we just return false
-		return (false);
+		/*
+		 * we don't have to check for "*" as it was already checked before we
+		 * were called.
+		 */
+		return effective;
 	}
-
+	
 	/**
 	 * Returns an enumeration of all the <code>ServicePermission</code>
 	 * objects in the container.
 	 * 
 	 * @return Enumeration of all the ServicePermission objects.
 	 */
+	public synchronized Enumeration elements() {
+		List all = new ArrayList(permissions.values());
+		Map pc = filterPermissions;
+		if (pc != null) {
+			all.addAll(pc.values());
+		}
+		return Collections.enumeration(all);
+	}
+	
+	/* serialization logic */
+	private static final ObjectStreamField[]	serialPersistentFields	= {
+			new ObjectStreamField("permissions", Hashtable.class),
+			new ObjectStreamField("all_allowed", Boolean.TYPE),
+			new ObjectStreamField("filterPermissions", HashMap.class)	};
 
-	public Enumeration elements() {
-		return (permissions.elements());
+	private synchronized void writeObject(ObjectOutputStream out)
+			throws IOException {
+		Hashtable hashtable = new Hashtable(permissions);
+		ObjectOutputStream.PutField pfields = out.putFields();
+		pfields.put("permissions", hashtable);
+		pfields.put("all_allowed", all_allowed);
+		pfields.put("filterPermissions", filterPermissions);
+		out.writeFields();
+	}
+
+	private synchronized void readObject(java.io.ObjectInputStream in)
+			throws IOException, ClassNotFoundException {
+		ObjectInputStream.GetField gfields = in.readFields();
+		Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+		permissions = new HashMap(hashtable);
+		all_allowed = gfields.get("all_allowed", false);
+		filterPermissions = (HashMap) gfields.get("filterPermissions", null);
 	}
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceReference.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceReference.java
index a24461c..a6dd9bd 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServiceReference.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceReference.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServiceReference.java,v 1.20 2007/02/21 16:49:05 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -18,6 +16,8 @@
 
 package org.osgi.framework;
 
+import java.util.Dictionary;
+
 /**
  * A reference to a service.
  * 
@@ -46,7 +46,7 @@
  * @see BundleContext#getServiceReferences
  * @see BundleContext#getService
  * @ThreadSafe
- * @version $Revision: 1.20 $
+ * @version $Revision: 6374 $
  */
 
 public interface ServiceReference extends Comparable {
@@ -85,8 +85,8 @@
 	 * This method is <i>case-preserving </i>; this means that every key in the
 	 * returned array must have the same case as the corresponding key in the
 	 * properties <code>Dictionary</code> that was passed to the
-	 * {@link BundleContext#registerService(String[],Object,java.util.Dictionary)}
-	 * or {@link ServiceRegistration#setProperties} methods.
+	 * {@link BundleContext#registerService(String[],Object,Dictionary)} or
+	 * {@link ServiceRegistration#setProperties} methods.
 	 * 
 	 * @return An array of property keys.
 	 */
@@ -102,9 +102,9 @@
 	 * unregistered.
 	 * 
 	 * @return The bundle that registered the service referenced by this
-	 *         <code>ServiceReference</code> object; <code>null</code> if
-	 *         that service has already been unregistered.
-	 * @see BundleContext#registerService(String[],Object,java.util.Dictionary)
+	 *         <code>ServiceReference</code> object; <code>null</code> if that
+	 *         service has already been unregistered.
+	 * @see BundleContext#registerService(String[],Object,Dictionary)
 	 */
 	public Bundle getBundle();
 
@@ -146,7 +146,9 @@
 	 *         referenced by this <code>ServiceReference</code> and the
 	 *         specified bundle use the same source for the package of the
 	 *         specified class name. Otherwise <code>false</code> is returned.
-	 * 
+	 * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+	 *         not created by the same framework instance as this
+	 *         <code>ServiceReference</code>.
 	 * @since 1.3
 	 */
 	public boolean isAssignableTo(Bundle bundle, String className);
@@ -157,10 +159,9 @@
 	 * 
 	 * <p>
 	 * If this <code>ServiceReference</code> and the specified
-	 * <code>ServiceReference</code> have the same
-	 * {@link Constants#SERVICE_ID service id} they are equal. This
-	 * <code>ServiceReference</code> is less than the specified
-	 * <code>ServiceReference</code> if it has a lower
+	 * <code>ServiceReference</code> have the same {@link Constants#SERVICE_ID
+	 * service id} they are equal. This <code>ServiceReference</code> is less
+	 * than the specified <code>ServiceReference</code> if it has a lower
 	 * {@link Constants#SERVICE_RANKING service ranking} and greater if it has a
 	 * higher service ranking. Otherwise, if this <code>ServiceReference</code>
 	 * and the specified <code>ServiceReference</code> have the same
@@ -172,8 +173,11 @@
 	 * 
 	 * @param reference The <code>ServiceReference</code> to be compared.
 	 * @return Returns a negative integer, zero, or a positive integer if this
-	 *         <code>ServiceReference</code> is less than, equal to, or
-	 *         greater than the specified <code>ServiceReference</code>.
+	 *         <code>ServiceReference</code> is less than, equal to, or greater
+	 *         than the specified <code>ServiceReference</code>.
+	 * @throws IllegalArgumentException If the specified
+	 *         <code>ServiceReference</code> was not created by the same
+	 *         framework instance as this <code>ServiceReference</code>.
 	 * @since 1.4
 	 */
 	public int compareTo(Object reference);
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceRegistration.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceRegistration.java
index 3239364..9186cf7 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServiceRegistration.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceRegistration.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServiceRegistration.java,v 1.14 2007/02/21 16:49:05 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
@@ -34,7 +32,7 @@
  * 
  * @see BundleContext#registerService(String[],Object,Dictionary)
  * @ThreadSafe
- * @version $Revision: 1.14 $
+ * @version $Revision: 6361 $
  */
 
 public interface ServiceRegistration {
@@ -45,7 +43,7 @@
 	 * The <code>ServiceReference</code> object may be shared with other
 	 * bundles.
 	 * 
-	 * @throws java.lang.IllegalStateException If this
+	 * @throws IllegalStateException If this
 	 *         <code>ServiceRegistration</code> object has already been
 	 *         unregistered.
 	 * @return <code>ServiceReference</code> object.
@@ -64,8 +62,7 @@
 	 * The following steps are required to modify service properties:
 	 * <ol>
 	 * <li>The service's properties are replaced with the provided properties.
-	 * <li>A service event of type {@link ServiceEvent#MODIFIED} is
-	 * fired.
+	 * <li>A service event of type {@link ServiceEvent#MODIFIED} is fired.
 	 * </ol>
 	 * 
 	 * @param properties The properties for this service. See {@link Constants}
@@ -84,17 +81,19 @@
 	 * Unregisters a service. Remove a <code>ServiceRegistration</code> object
 	 * from the Framework service registry. All <code>ServiceReference</code>
 	 * objects associated with this <code>ServiceRegistration</code> object
-	 * can no longer be used to interact with the service.
+	 * can no longer be used to interact with the service once unregistration is
+	 * complete.
 	 * 
 	 * <p>
 	 * The following steps are required to unregister a service:
 	 * <ol>
 	 * <li>The service is removed from the Framework service registry so that
-	 * it can no longer be used. <code>ServiceReference</code> objects for the
-	 * service may no longer be used to get a service object for the service.
-	 * <li>A service event of type {@link ServiceEvent#UNREGISTERING} is
-	 * fired so that bundles using this service can release their
-	 * use of it.
+	 * it can no longer be obtained.
+	 * <li>A service event of type {@link ServiceEvent#UNREGISTERING} is fired
+	 * so that bundles using this service can release their use of the service.
+	 * Once delivery of the service event is complete, the
+	 * <code>ServiceReference</code> objects for the service may no longer be
+	 * used to get a service object for the service.
 	 * <li>For each bundle whose use count for this service is greater than
 	 * zero: <br>
 	 * The bundle's use count for this service is set to zero. <br>
@@ -103,7 +102,7 @@
 	 * the service object for the bundle.
 	 * </ol>
 	 * 
-	 * @throws java.lang.IllegalStateException If this
+	 * @throws IllegalStateException If this
 	 *         <code>ServiceRegistration</code> object has already been
 	 *         unregistered.
 	 * @see BundleContext#ungetService
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/SignerProperty.java b/org.osgi.core/src/main/java/org/osgi/framework/SignerProperty.java
new file mode 100644
index 0000000..2ba0389
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/SignerProperty.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). 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.framework;
+
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Package private class used by permissions for filter matching on signer key
+ * during filter expression evaluation in the permission implies method.
+ * 
+ * @Immutable
+ * @version $Revision: 6479 $
+ */
+class SignerProperty {
+	private final Bundle	bundle;
+	private final String	pattern;
+
+	/**
+	 * String constructor used by the filter matching algorithm to construct a
+	 * SignerProperty from the attribute value in a filter expression.
+	 * 
+	 * @param pattern Attribute value in the filter expression.
+	 */
+	public SignerProperty(String pattern) {
+		this.pattern = pattern;
+		this.bundle = null;
+	}
+
+	/**
+	 * Used by the permission implies method to build the properties for a
+	 * filter match.
+	 * 
+	 * @param bundle The bundle whose signers are to be matched.
+	 */
+	SignerProperty(Bundle bundle) {
+		this.bundle = bundle;
+		this.pattern = null;
+	}
+
+	/**
+	 * Used by the filter matching algorithm. This methods does NOT satisfy the
+	 * normal equals contract. Since the class is only used in filter expression
+	 * evaluations, it only needs to support comparing an instance created with
+	 * a Bundle to an instance created with a pattern string from the filter
+	 * expression.
+	 * 
+	 * @param o SignerProperty to compare against.
+	 * @return true if the DN name chain matches the pattern.
+	 */
+	public boolean equals(Object o) {
+		if (!(o instanceof SignerProperty))
+			return false;
+		SignerProperty other = (SignerProperty) o;
+		Bundle matchBundle = bundle != null ? bundle : other.bundle;
+		String matchPattern = bundle != null ? other.pattern : pattern;
+		Map/* <X509Certificate, List<X509Certificate>> */signers = matchBundle
+				.getSignerCertificates(Bundle.SIGNERS_TRUSTED);
+		for (Iterator iSigners = signers.values().iterator(); iSigners
+				.hasNext();) {
+			List/* <X509Certificate> */signerCerts = (List) iSigners.next();
+			List/* <String> */dnChain = new ArrayList(signerCerts.size());
+			for (Iterator iCerts = signerCerts.iterator(); iCerts.hasNext();) {
+				dnChain.add(((X509Certificate) iCerts.next()).getSubjectDN()
+						.getName());
+			}
+			if (FrameworkUtil
+					.matchDistinguishedNameChain(matchPattern, dnChain)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Since the equals method does not obey the general equals contract, this
+	 * method cannot generate hash codes which obey the equals contract.
+	 */
+	public int hashCode() {
+		return 31;
+	}
+
+	/**
+	 * Check if the bundle is signed.
+	 * 
+	 * @return true if constructed with a bundle that is signed.
+	 */
+	boolean isBundleSigned() {
+		if (bundle == null) {
+			return false;
+		}
+		Map/* <X509Certificate, List<X509Certificate>> */signers = bundle
+				.getSignerCertificates(Bundle.SIGNERS_TRUSTED);
+		return !signers.isEmpty();
+	}
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/SynchronousBundleListener.java b/org.osgi.core/src/main/java/org/osgi/framework/SynchronousBundleListener.java
index e1ec5d5..9104f04 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/SynchronousBundleListener.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/SynchronousBundleListener.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/SynchronousBundleListener.java,v 1.15 2007/02/20 00:16:30 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2001, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2001, 2008). 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.
@@ -47,7 +45,7 @@
  * @since 1.1
  * @see BundleEvent
  * @ThreadSafe
- * @version $Revision: 1.15 $
+ * @version $Revision: 5673 $
  */
 
 public interface SynchronousBundleListener extends BundleListener {
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/Version.java b/org.osgi.core/src/main/java/org/osgi/framework/Version.java
index 55c8268..7317495 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/Version.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/Version.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/Version.java,v 1.17 2007/02/20 00:07:22 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2004, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). 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.
@@ -39,7 +37,7 @@
  * 
  * @since 1.3
  * @Immutable
- * @version $Revision: 1.17 $
+ * @version $Revision: 6860 $
  */
 
 public class Version implements Comparable {
@@ -50,8 +48,7 @@
 	private static final String	SEPARATOR		= ".";					//$NON-NLS-1$
 
 	/**
-	 * The empty version "0.0.0". Equivalent to calling
-	 * <code>new Version(0,0,0)</code>.
+	 * The empty version "0.0.0".
 	 */
 	public static final Version	emptyVersion	= new Version(0, 0, 0);
 
@@ -72,14 +69,14 @@
 	}
 
 	/**
-	 * Creates a version identifier from the specifed components.
+	 * Creates a version identifier from the specified components.
 	 * 
 	 * @param major Major component of the version identifier.
 	 * @param minor Minor component of the version identifier.
 	 * @param micro Micro component of the version identifier.
 	 * @param qualifier Qualifier component of the version identifier. If
-	 *        <code>null</code> is specified, then the qualifier will be set
-	 *        to the empty string.
+	 *        <code>null</code> is specified, then the qualifier will be set to
+	 *        the empty string.
 	 * @throws IllegalArgumentException If the numerical components are negative
 	 *         or the qualifier string is invalid.
 	 */
@@ -118,26 +115,26 @@
 	 *         formatted.
 	 */
 	public Version(String version) {
-		int major = 0;
-		int minor = 0;
-		int micro = 0;
-		String qualifier = ""; //$NON-NLS-1$
+		int maj = 0;
+		int min = 0;
+		int mic = 0;
+		String qual = ""; //$NON-NLS-1$
 
 		try {
 			StringTokenizer st = new StringTokenizer(version, SEPARATOR, true);
-			major = Integer.parseInt(st.nextToken());
+			maj = Integer.parseInt(st.nextToken());
 
 			if (st.hasMoreTokens()) {
 				st.nextToken(); // consume delimiter
-				minor = Integer.parseInt(st.nextToken());
+				min = Integer.parseInt(st.nextToken());
 
 				if (st.hasMoreTokens()) {
 					st.nextToken(); // consume delimiter
-					micro = Integer.parseInt(st.nextToken());
+					mic = Integer.parseInt(st.nextToken());
 
 					if (st.hasMoreTokens()) {
 						st.nextToken(); // consume delimiter
-						qualifier = st.nextToken();
+						qual = st.nextToken();
 
 						if (st.hasMoreTokens()) {
 							throw new IllegalArgumentException("invalid format"); //$NON-NLS-1$
@@ -150,10 +147,10 @@
 			throw new IllegalArgumentException("invalid format"); //$NON-NLS-1$
 		}
 
-		this.major = major;
-		this.minor = minor;
-		this.micro = micro;
-		this.qualifier = qualifier;
+		major = maj;
+		minor = min;
+		micro = mic;
+		qualifier = qual;
 		validate();
 	}
 
@@ -173,11 +170,23 @@
 		if (micro < 0) {
 			throw new IllegalArgumentException("negative micro"); //$NON-NLS-1$
 		}
-		int length = qualifier.length();
-		for (int i = 0; i < length; i++) {
-			if ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-".indexOf(qualifier.charAt(i)) == -1) { //$NON-NLS-1$
-				throw new IllegalArgumentException("invalid qualifier"); //$NON-NLS-1$
+		char[] chars = qualifier.toCharArray();
+		for (int i = 0, length = chars.length; i < length; i++) {
+	        char ch = chars[i];
+			if (('A' <= ch) && (ch <= 'Z')) {
+				continue;
 			}
+			if (('a' <= ch) && (ch <= 'z')) {
+				continue;
+			}
+			if (('0' <= ch) && (ch <= '9')) {
+				continue;
+			}
+			if ((ch == '_') || (ch == '-')) {
+				continue;
+			}
+			throw new IllegalArgumentException(
+					"invalid qualifier: " + qualifier); //$NON-NLS-1$
 		}
 	}
 
@@ -256,13 +265,18 @@
 	 * @return The string representation of this version identifier.
 	 */
 	public String toString() {
-		String base = major + SEPARATOR + minor + SEPARATOR + micro;
-		if (qualifier.length() == 0) { //$NON-NLS-1$
-			return base;
+		int q = qualifier.length();
+		StringBuffer result = new StringBuffer(20 + q);
+		result.append(major);
+		result.append(SEPARATOR);
+		result.append(minor);
+		result.append(SEPARATOR);
+		result.append(micro);
+		if (q > 0) {
+			result.append(SEPARATOR);
+			result.append(qualifier);
 		}
-		else {
-			return base + SEPARATOR + qualifier;
-		}
+		return result.toString();
 	}
 
 	/**
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/EventHook.java b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/EventHook.java
new file mode 100644
index 0000000..fe21fba
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/EventHook.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). 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.framework.hooks.service;
+
+import java.util.Collection;
+
+import org.osgi.framework.ServiceEvent;
+
+/**
+ * OSGi Framework Service Event Hook Service.
+ * 
+ * <p>
+ * Bundles registering this service will be called during framework service
+ * (register, modify, and unregister service) operations.
+ * 
+ * @ThreadSafe
+ * @version $Revision: 6860 $
+ */
+
+public interface EventHook {
+	/**
+	 * Event hook method. This method is called prior to service event delivery
+	 * when a publishing bundle registers, modifies or unregisters a service.
+	 * This method can filter the bundles which receive the event.
+	 * 
+	 * @param event The service event to be delivered.
+	 * @param contexts A <code>Collection</code> of Bundle Contexts for bundles
+	 *        which have listeners to which the specified event will be
+	 *        delivered. The implementation of this method may remove bundle
+	 *        contexts from the collection to prevent the event from being
+	 *        delivered to the associated bundles. The collection supports all
+	 *        the optional <code>Collection</code> operations except
+	 *        <code>add</code> and <code>addAll</code>. Attempting to add to the
+	 *        collection will result in an
+	 *        <code>UnsupportedOperationException</code>. The collection is not
+	 *        synchronized.
+	 */
+	void event(ServiceEvent event,
+			Collection/* <? extends BundleContext> */contexts);
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/FindHook.java b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/FindHook.java
new file mode 100644
index 0000000..02044f3
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/FindHook.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). 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.framework.hooks.service;
+
+import java.util.Collection;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * OSGi Framework Service Find Hook Service.
+ * 
+ * <p>
+ * Bundles registering this service will be called during framework service find
+ * (get service references) operations.
+ * 
+ * @ThreadSafe
+ * @version $Revision: 6860 $
+ */
+
+public interface FindHook {
+	/**
+	 * Find hook method. This method is called during the service find operation
+	 * (for example, {@link BundleContext#getServiceReferences(String, String)}
+	 * ). This method can filter the result of the find operation.
+	 * 
+	 * @param context The bundle context of the bundle performing the find
+	 *        operation.
+	 * @param name The class name of the services to find or <code>null</code>
+	 *        to find all services.
+	 * @param filter The filter criteria of the services to find or
+	 *        <code>null</code> for no filter criteria.
+	 * @param allServices <code>true</code> if the find operation is the result
+	 *        of a call to
+	 *        {@link BundleContext#getAllServiceReferences(String, String)}
+	 * @param references A <code>Collection</code> of Service References to be
+	 *        returned as a result of the find operation. The implementation of
+	 *        this method may remove service references from the collection to
+	 *        prevent the references from being returned to the bundle
+	 *        performing the find operation. The collection supports all the
+	 *        optional <code>Collection</code> operations except
+	 *        <code>add</code> and <code>addAll</code>. Attempting to add to the
+	 *        collection will result in an
+	 *        <code>UnsupportedOperationException</code>. The collection is not
+	 *        synchronized.
+	 */
+	void find(BundleContext context, String name, String filter,
+			boolean allServices,
+			Collection/* <? extends ServiceReference> */references);
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/ListenerHook.java b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/ListenerHook.java
new file mode 100644
index 0000000..7ee855b
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/ListenerHook.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). 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.framework.hooks.service;
+
+import java.util.Collection;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * OSGi Framework Service Listener Hook Service.
+ * 
+ * <p>
+ * Bundles registering this service will be called during service listener
+ * addition and removal.
+ * 
+ * @ThreadSafe
+ * @version $Revision: 6906 $
+ */
+
+public interface ListenerHook {
+	/**
+	 * Added listeners hook method. This method is called to provide the hook
+	 * implementation with information on newly added service listeners. This
+	 * method will be called as service listeners are added while this hook is
+	 * registered. Also, immediately after registration of this hook, this
+	 * method will be called to provide the current collection of service
+	 * listeners which had been added prior to the hook being registered.
+	 * 
+	 * @param listeners A <code>Collection</code> of {@link ListenerInfo}s for
+	 *        newly added service listeners which are now listening to service
+	 *        events. Attempting to add to or remove from the collection will
+	 *        result in an <code>UnsupportedOperationException</code>. The
+	 *        collection is not synchronized.
+	 */
+	void added(Collection/* <? extends ListenerInfo> */listeners);
+
+	/**
+	 * Removed listeners hook method. This method is called to provide the hook
+	 * implementation with information on newly removed service listeners. This
+	 * method will be called as service listeners are removed while this hook is
+	 * registered.
+	 * 
+	 * @param listeners A <code>Collection</code> of {@link ListenerInfo}s for
+	 *        newly removed service listeners which are no longer listening to
+	 *        service events. Attempting to add to or remove from the collection
+	 *        will result in an <code>UnsupportedOperationException</code>. The
+	 *        collection is not synchronized.
+	 */
+	void removed(Collection/* <? extends ListenerInfo> */listeners);
+
+	/**
+	 * Information about a Service Listener. This interface describes the bundle
+	 * which added the Service Listener and the filter with which it was added.
+	 * 
+	 * @ThreadSafe
+	 */
+	public interface ListenerInfo {
+		/**
+		 * Return the context of the bundle which added the listener.
+		 * 
+		 * @return The context of the bundle which added the listener.
+		 */
+		BundleContext getBundleContext();
+
+		/**
+		 * Return the filter string with which the listener was added.
+		 * 
+		 * @return The filter string with which the listener was added. This may
+		 *         be <code>null</code> if the listener was added without a
+		 *         filter.
+		 */
+		String getFilter();
+
+		/**
+		 * Return the state of the listener for this addition and removal life
+		 * cycle. Initially this method will return <code>false</code>
+		 * indicating the listener has been added but has not been removed.
+		 * After the listener has been removed, this method must always return
+		 * <code>true</code>.
+		 * 
+		 * <p>
+		 * There is an extremely rare case in which removed notification to
+		 * {@link ListenerHook}s can be made before added notification if two
+		 * threads are racing to add and remove the same service listener.
+		 * Because {@link ListenerHook}s are called synchronously during service
+		 * listener addition and removal, the Framework cannot guarantee
+		 * in-order delivery of added and removed notification for a given
+		 * service listener. This method can be used to detect this rare
+		 * occurrence.
+		 * 
+		 * @return <code>false</code> if the listener has not been been removed,
+		 *         <code>true</code> otherwise.
+		 */
+		boolean isRemoved();
+
+		/**
+		 * Compares this <code>ListenerInfo</code> to another
+		 * <code>ListenerInfo</code>. Two <code>ListenerInfo</code>s are equals
+		 * if they refer to the same listener for a given addition and removal
+		 * life cycle. If the same listener is added again, it must have a
+		 * different <code>ListenerInfo</code> which is not equal to this
+		 * <code>ListenerInfo</code>.
+		 * 
+		 * @param obj The object to compare against this
+		 *        <code>ListenerInfo</code>.
+		 * @return <code>true</code> if the other object is a
+		 *         <code>ListenerInfo</code> object and both objects refer to
+		 *         the same listener for a given addition and removal life
+		 *         cycle.
+		 */
+		boolean equals(Object obj);
+
+		/**
+		 * Returns the hash code for this <code>ListenerInfo</code>.
+		 * 
+		 * @return The hash code of this <code>ListenerInfo</code>.
+		 */
+		int hashCode();
+	}
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/package.html b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/package.html
new file mode 100644
index 0000000..46d18ac
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6211 $ -->
+<BODY>
+<p>Framework Service Hooks Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework.hooks.service;version=&quot;[1.0,2.0)&quot;
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/packageinfo b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/launch/Framework.java b/org.osgi.core/src/main/java/org/osgi/framework/launch/Framework.java
new file mode 100644
index 0000000..f7618aa
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/launch/Framework.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). 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.framework.launch;
+
+import java.io.InputStream;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+
+/**
+ * A Framework instance. A Framework is also known as a System Bundle.
+ * 
+ * <p>
+ * Framework instances are created using a {@link FrameworkFactory}. The methods
+ * of this interface can be used to manage and control the created framework
+ * instance.
+ * 
+ * @ThreadSafe
+ * @version $Revision: 6542 $
+ */
+public interface Framework extends Bundle {
+
+	/**
+	 * Initialize this Framework. After calling this method, this Framework
+	 * must:
+	 * <ul>
+	 * <li>Be in the {@link #STARTING} state.</li>
+	 * <li>Have a valid Bundle Context.</li>
+	 * <li>Be at start level 0.</li>
+	 * <li>Have event handling enabled.</li>
+	 * <li>Have reified Bundle objects for all installed bundles.</li>
+	 * <li>Have registered any framework services. For example,
+	 * <code>PackageAdmin</code>, <code>ConditionalPermissionAdmin</code>,
+	 * <code>StartLevel</code>.</li>
+	 * </ul>
+	 * 
+	 * <p>
+	 * This Framework will not actually be started until {@link #start() start}
+	 * is called.
+	 * 
+	 * <p>
+	 * This method does nothing if called when this Framework is in the
+	 * {@link #STARTING}, {@link #ACTIVE} or {@link #STOPPING} states.
+	 * 
+	 * @throws BundleException If this Framework could not be initialized.
+	 * @throws SecurityException If the Java Runtime Environment supports
+	 *         permissions and the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code> or if there is a
+	 *         security manager already installed and the
+	 *         {@link Constants#FRAMEWORK_SECURITY} configuration property is
+	 *         set.
+	 * 
+	 */
+	void init() throws BundleException;
+
+	/**
+	 * Wait until this Framework has completely stopped. The <code>stop</code>
+	 * and <code>update</code> methods on a Framework performs an asynchronous
+	 * stop of the Framework. This method can be used to wait until the
+	 * asynchronous stop of this Framework has completed. This method will only
+	 * wait if called when this Framework is in the {@link #STARTING},
+	 * {@link #ACTIVE}, or {@link #STOPPING} states. Otherwise it will return
+	 * immediately.
+	 * <p>
+	 * A Framework Event is returned to indicate why this Framework has stopped.
+	 * 
+	 * @param timeout Maximum number of milliseconds to wait until this
+	 *        Framework has completely stopped. A value of zero will wait
+	 *        indefinitely.
+	 * @return A Framework Event indicating the reason this method returned. The
+	 *         following <code>FrameworkEvent</code> types may be returned by
+	 *         this method.
+	 *         <ul>
+	 *         <li>{@link FrameworkEvent#STOPPED STOPPED} - This Framework has
+	 *         been stopped. </li>
+	 * 
+	 *         <li>{@link FrameworkEvent#STOPPED_UPDATE STOPPED_UPDATE} - This
+	 *         Framework has been updated which has shutdown and will now
+	 *         restart.</li>
+	 * 
+	 *         <li> {@link FrameworkEvent#STOPPED_BOOTCLASSPATH_MODIFIED
+	 *         STOPPED_BOOTCLASSPATH_MODIFIED} - This Framework has been stopped
+	 *         and a bootclasspath extension bundle has been installed or
+	 *         updated. The VM must be restarted in order for the changed boot
+	 *         class path to take affect. </li>
+	 * 
+	 *         <li>{@link FrameworkEvent#ERROR ERROR} - The Framework
+	 *         encountered an error while shutting down or an error has occurred
+	 *         which forced the framework to shutdown. </li>
+	 * 
+	 *         <li> {@link FrameworkEvent#WAIT_TIMEDOUT WAIT_TIMEDOUT} - This
+	 *         method has timed out and returned before this Framework has
+	 *         stopped.</li>
+	 *         </ul>
+	 * @throws InterruptedException If another thread interrupted the current
+	 *         thread before or while the current thread was waiting for this
+	 *         Framework to completely stop. The <i>interrupted status</i> of
+	 *         the current thread is cleared when this exception is thrown.
+	 * @throws IllegalArgumentException If the value of timeout is negative.
+	 */
+	FrameworkEvent waitForStop(long timeout) throws InterruptedException;
+
+	/**
+	 * Start this Framework.
+	 * 
+	 * <p>
+	 * The following steps are taken to start this Framework:
+	 * <ol>
+	 * <li>If this Framework is not in the {@link #STARTING} state,
+	 * {@link #init() initialize} this Framework.</li>
+	 * <li>All installed bundles must be started in accordance with each
+	 * bundle's persistent <i>autostart setting</i>. This means some bundles
+	 * will not be started, some will be started with <i>eager activation</i>
+	 * and some will be started with their <i>declared activation</i> policy. If
+	 * this Framework implements the optional <i>Start Level Service
+	 * Specification</i>, then the start level of this Framework is moved to the
+	 * start level specified by the
+	 * {@link Constants#FRAMEWORK_BEGINNING_STARTLEVEL beginning start level}
+	 * framework property, as described in the <i>Start Level Service
+	 * Specification</i>. If this framework property is not specified, then the
+	 * start level of this Framework is moved to start level one (1). Any
+	 * exceptions that occur during bundle starting must be wrapped in a
+	 * {@link BundleException} and then published as a framework event of type
+	 * {@link FrameworkEvent#ERROR}</li>
+	 * <li>This Framework's state is set to {@link #ACTIVE}.</li>
+	 * <li>A framework event of type {@link FrameworkEvent#STARTED} is fired</li>
+	 * </ol>
+	 * 
+	 * @throws BundleException If this Framework could not be started.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
+	 * @see "Start Level Service Specification"
+	 */
+	void start() throws BundleException;
+
+	/**
+	 * Start this Framework.
+	 * 
+	 * <p>
+	 * Calling this method is the same as calling {@link #start()}. There are no
+	 * start options for the Framework.
+	 * 
+	 * @param options Ignored. There are no start options for the Framework.
+	 * @throws BundleException If this Framework could not be started.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
+	 * @see #start()
+	 */
+	void start(int options) throws BundleException;
+
+	/**
+	 * Stop this Framework.
+	 * 
+	 * <p>
+	 * The method returns immediately to the caller after initiating the
+	 * following steps to be taken on another thread.
+	 * <ol>
+	 * <li>This Framework's state is set to {@link #STOPPING}.</li>
+	 * <li>All installed bundles must be stopped without changing each bundle's
+	 * persistent <i>autostart setting</i>. If this Framework implements the
+	 * optional <i>Start Level Service Specification</i>, then the start level
+	 * of this Framework is moved to start level zero (0), as described in the
+	 * <i>Start Level Service Specification</i>. Any exceptions that occur
+	 * during bundle stopping must be wrapped in a {@link BundleException} and
+	 * then published as a framework event of type {@link FrameworkEvent#ERROR}</li>
+	 * <li>Unregister all services registered by this Framework.</li>
+	 * <li>Event handling is disabled.</li>
+	 * <li>This Framework's state is set to {@link #RESOLVED}.</li>
+	 * <li>All resources held by this Framework are released. This includes
+	 * threads, bundle class loaders, open files, etc.</li>
+	 * <li>Notify all threads that are waiting at {@link #waitForStop(long)
+	 * waitForStop} that the stop operation has completed.</li>
+	 * </ol>
+	 * <p>
+	 * After being stopped, this Framework may be discarded, initialized or
+	 * started.
+	 * 
+	 * @throws BundleException If stopping this Framework could not be
+	 *         initiated.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
+	 * @see "Start Level Service Specification"
+	 */
+	void stop() throws BundleException;
+
+	/**
+	 * Stop this Framework.
+	 * 
+	 * <p>
+	 * Calling this method is the same as calling {@link #stop()}. There are no
+	 * stop options for the Framework.
+	 * 
+	 * @param options Ignored. There are no stop options for the Framework.
+	 * @throws BundleException If stopping this Framework could not be
+	 *         initiated.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
+	 * @see #stop()
+	 */
+	void stop(int options) throws BundleException;
+
+	/**
+	 * The Framework cannot be uninstalled.
+	 * 
+	 * <p>
+	 * This method always throws a BundleException.
+	 * 
+	 * @throws BundleException This Framework cannot be uninstalled.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+	 *         Runtime Environment supports permissions.
+	 */
+	void uninstall() throws BundleException;
+
+	/**
+	 * Stop and restart this Framework.
+	 * 
+	 * <p>
+	 * The method returns immediately to the caller after initiating the
+	 * following steps to be taken on another thread.
+	 * <ol>
+	 * <li>Perform the steps in the {@link #stop()} method to stop this
+	 * Framework.</li>
+	 * <li>Perform the steps in the {@link #start()} method to start this
+	 * Framework.</li>
+	 * </ol>
+	 * 
+	 * @throws BundleException If stopping and restarting this Framework could
+	 *         not be initiated.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+	 *         Runtime Environment supports permissions.
+	 */
+	void update() throws BundleException;
+
+	/**
+	 * Stop and restart this Framework.
+	 * 
+	 * <p>
+	 * Calling this method is the same as calling {@link #update()} except that
+	 * any provided InputStream is immediately closed.
+	 * 
+	 * @param in Any provided InputStream is immediately closed before returning
+	 *        from this method and otherwise ignored.
+	 * @throws BundleException If stopping and restarting this Framework could
+	 *         not be initiated.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+	 *         Runtime Environment supports permissions.
+	 */
+	void update(InputStream in) throws BundleException;
+
+	/**
+	 * Returns the Framework unique identifier. This Framework is assigned the
+	 * unique identifier zero (0) since this Framework is also a System Bundle.
+	 * 
+	 * @return 0.
+	 * @see Bundle#getBundleId()
+	 */
+	long getBundleId();
+
+	/**
+	 * Returns the Framework location identifier. This Framework is assigned the
+	 * unique location &quot;<code>System Bundle</code>&quot; since this
+	 * Framework is also a System Bundle.
+	 * 
+	 * @return The string &quot;<code>System Bundle</code>&quot;.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,METADATA]</code>, and the Java Runtime
+	 *         Environment supports permissions.
+	 * @see Bundle#getLocation()
+	 * @see Constants#SYSTEM_BUNDLE_LOCATION
+	 */
+	String getLocation();
+
+	/**
+	 * Returns the symbolic name of this Framework. The symbolic name is unique
+	 * for the implementation of the framework. However, the symbolic name
+	 * &quot;<code>system.bundle</code>&quot; must be recognized as an alias to
+	 * the implementation-defined symbolic name since this Framework is also a
+	 * System Bundle.
+	 * 
+	 * @return The symbolic name of this Framework.
+	 * @see Bundle#getSymbolicName()
+	 * @see Constants#SYSTEM_BUNDLE_SYMBOLICNAME
+	 */
+	String getSymbolicName();
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/launch/FrameworkFactory.java b/org.osgi.core/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
new file mode 100644
index 0000000..bcb6da3
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). 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.framework.launch;
+
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * A factory for creating {@link Framework} instances.
+ * 
+ * <p>
+ * A framework implementation jar must contain the following resource:
+ * 
+ * <pre>
+ * /META-INF/services/org.osgi.framework.launch.FrameworkFactory
+ * </pre>
+ * 
+ * This UTF-8 encoded resource must contain the name of the framework
+ * implementation's FrameworkFactory implementation class. Space and tab
+ * characters, including blank lines, in the resource must be ignored. The
+ * number sign ('#' &#92;u0023) and all characters following it on each line are
+ * a comment and must be ignored.
+ * 
+ * <p>
+ * Launchers can find the name of the FrameworkFactory implementation class in
+ * the resource and then load and construct a FrameworkFactory object for the
+ * framework implementation. The FrameworkFactory implementation class must have
+ * a public, no-argument constructor. Java&#8482; SE 6 introduced the
+ * <code>ServiceLoader</code> class which can create a FrameworkFactory instance
+ * from the resource.
+ * 
+ * @ThreadSafe
+ * @version $Revision: 6888 $
+ */
+public interface FrameworkFactory {
+
+	/**
+	 * Create a new {@link Framework} instance.
+	 * 
+	 * @param configuration The framework properties to configure the new
+	 *        framework instance. If framework properties are not provided by
+	 *        the configuration argument, the created framework instance must
+	 *        use some reasonable default configuration appropriate for the
+	 *        current VM. For example, the system packages for the current
+	 *        execution environment should be properly exported. The specified
+	 *        configuration argument may be <code>null</code>. The created
+	 *        framework instance must copy any information needed from the
+	 *        specified configuration argument since the configuration argument
+	 *        can be changed after the framework instance has been created.
+	 * @return A new, configured {@link Framework} instance. The framework
+	 *         instance must be in the {@link Bundle#INSTALLED} state.
+	 * @throws SecurityException If the caller does not have
+	 *         <code>AllPermission</code>, and the Java Runtime Environment
+	 *         supports permissions.
+	 */
+	Framework newFramework(Map configuration);
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/launch/package.html b/org.osgi.core/src/main/java/org/osgi/framework/launch/package.html
new file mode 100644
index 0000000..6b0407b
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/launch/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Framework Launch Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework.launch;version=&quot;[1.0,2.0)&quot;
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/launch/packageinfo b/org.osgi.core/src/main/java/org/osgi/framework/launch/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/launch/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/package.html b/org.osgi.core/src/main/java/org/osgi/framework/package.html
new file mode 100644
index 0000000..44d6c48
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Framework Package Version 1.5.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework;version=&quot;[1.5,2.0)&quot;
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/packageinfo b/org.osgi.core/src/main/java/org/osgi/framework/packageinfo
new file mode 100644
index 0000000..ccee95e
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/packageinfo
@@ -0,0 +1 @@
+version 1.5
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java
index 752cdd0..25c4ad9 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/BundleLocationCondition.java,v 1.18 2006/06/16 16:31:37 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2008). 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.
@@ -22,13 +20,21 @@
 import java.security.PrivilegedAction;
 import java.util.Hashtable;
 
-import org.osgi.framework.*;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
 
 /**
- * Condition to test if the location of a bundle matches a pattern. Pattern
- * matching is done according to the filter string matching rules.
+ * Condition to test if the location of a bundle matches or does not match a
+ * pattern. Since the bundle's location cannot be changed, this condition is
+ * immutable.
  * 
- * @version $Revision: 1.18 $
+ * <p>
+ * Pattern matching is done according to the filter string matching rules.
+ * 
+ * @ThreadSafe
+ * @version $Revision: 5901 $
  */
 public class BundleLocationCondition {
 	private static final String	CONDITION_TYPE	= "org.osgi.service.condpermadmin.BundleLocationCondition";
@@ -38,25 +44,31 @@
 	 * to the location pattern.
 	 * 
 	 * @param bundle The Bundle being evaluated.
-	 * @param info The ConditionInfo to construct the condition for. The args of
-	 *        the ConditionInfo must be a single String which specifies the
-	 *        location pattern to match against the Bundle location. Matching is
-	 *        done according to the filter string matching rules. Any '*'
-	 *        characters in the location argument are used as wildcards when
-	 *        matching bundle locations unless they are escaped with a '\'
-	 *        character.
+	 * @param info The ConditionInfo from which to construct the condition. The
+	 *        ConditionInfo must specify one or two arguments. The first
+	 *        argument of the ConditionInfo specifies the location pattern
+	 *        against which to match the bundle location. Matching is done
+	 *        according to the filter string matching rules. Any '*' characters
+	 *        in the first argument are used as wildcards when matching bundle
+	 *        locations unless they are escaped with a '\' character. The
+	 *        Condition is satisfied if the bundle location matches the pattern.
+	 *        The second argument of the ConditionInfo is optional. If a second
+	 *        argument is present and equal to "!", then the satisfaction of the
+	 *        Condition is negated. That is, the Condition is satisfied if the
+	 *        bundle location does NOT match the pattern. If the second argument
+	 *        is present but does not equal "!", then the second argument is
+	 *        ignored.
 	 * @return Condition object for the requested condition.
 	 */
-	static public Condition getCondition(final Bundle bundle, ConditionInfo info) {
+	static public Condition getCondition(final Bundle bundle,
+			final ConditionInfo info) {
 		if (!CONDITION_TYPE.equals(info.getType()))
 			throw new IllegalArgumentException(
 					"ConditionInfo must be of type \"" + CONDITION_TYPE + "\"");
 		String[] args = info.getArgs();
-		if (args.length != 1)
-			throw new IllegalArgumentException("Illegal number of args: "
-					+ args.length);
-		String bundleLocation = (String) AccessController
-				.doPrivileged(new PrivilegedAction() {
+		if (args.length != 1 && args.length != 2)
+			throw new IllegalArgumentException("Illegal number of args: " + args.length);
+		String bundleLocation = (String) AccessController.doPrivileged(new PrivilegedAction() {
 					public Object run() {
 						return bundle.getLocation();
 					}
@@ -67,12 +79,14 @@
 					+ escapeLocation(args[0]) + ")");
 		}
 		catch (InvalidSyntaxException e) {
-			// this should never happen, but just incase
-			throw new RuntimeException("Invalid filter: " + e.getFilter());
+			// this should never happen, but just in case
+			throw new RuntimeException("Invalid filter: " + e.getFilter(), e);
 		}
 		Hashtable matchProps = new Hashtable(2);
 		matchProps.put("location", bundleLocation);
-		return filter.match(matchProps) ? Condition.TRUE : Condition.FALSE;
+		boolean negate = (args.length == 2) ? "!".equals(args[1]) : false;
+		return (negate ^ filter.match(matchProps)) ? Condition.TRUE
+				: Condition.FALSE;
 	}
 
 	private BundleLocationCondition() {
@@ -86,7 +100,7 @@
 	 * @param value unescaped value string.
 	 * @return escaped value string.
 	 */
-	private static String escapeLocation(String value) {
+	private static String escapeLocation(final String value) {
 		boolean escaped = false;
 		int inlen = value.length();
 		int outlen = inlen << 1; /* inlen * 2 */
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java
index 31cf5ff..31b6481 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/BundleSignerCondition.java,v 1.13 2006/10/24 17:54:27 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2009). 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.
@@ -18,15 +16,19 @@
 
 package org.osgi.service.condpermadmin;
 
-import java.lang.reflect.*;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
 
 /**
- * Condition to test if the signer of a bundle matches a pattern. Since the bundle's signer can
- * only change when the bundle is updated, this condition is immutable.
+ * Condition to test if the signer of a bundle matches or does not match a
+ * pattern. Since the bundle's signer can only change when the bundle is
+ * updated, this condition is immutable.
  * <p>
  * The condition expressed using a single String that specifies a Distinguished
  * Name (DN) chain to match bundle signers against. DN's are encoded using IETF
@@ -47,68 +49,10 @@
  * must be the first RDN and will match any number of RDNs (including zero
  * RDNs).
  * 
- * @version $Revision: 1.13 $
+ * @ThreadSafe
+ * @version $Revision: 6860 $
  */
 public class BundleSignerCondition {
-	/*
-	 * NOTE: A framework implementor may also choose to replace this class in
-	 * their distribution with a class that directly interfaces with the
-	 * framework implementation. This replacement class MUST NOT alter the
-	 * public/protected signature of this class.
-	 */
-
-	/*
-	 * This class will load the BundleSignerCondition class in the package named
-	 * by the org.osgi.vendor.condpermadmin package. This class will delegate
-	 * getCondition methods calls to the vendor BundleSignerCondition class.
-	 */
-	
-	private static class ImplHolder implements PrivilegedAction {
-		private static final String	packageProperty	= "org.osgi.vendor.condpermadmin";
-		static final Method	getCondition;
-		static {
-			getCondition = (Method) AccessController.doPrivileged(new ImplHolder());
-		}
-
-		private ImplHolder() {
-		}
-
-		public Object run() {
-			String packageName = System
-			.getProperty(packageProperty);
-			if (packageName == null) {
-				throw new NoClassDefFoundError(packageProperty
-						+ " property not set");
-			}
-			
-			Class delegateClass;
-			try {
-				delegateClass = Class.forName(packageName
-						+ ".BundleSignerCondition");
-			}
-			catch (ClassNotFoundException e) {
-				throw new NoClassDefFoundError(e.toString());
-			}
-			
-			Method result;
-			try {
-				result = delegateClass.getMethod("getCondition",
-						new Class[] {Bundle.class,
-						ConditionInfo.class		});
-			}
-			catch (NoSuchMethodException e) {
-				throw new NoSuchMethodError(e.toString());
-			}
-			
-			if (!Modifier.isStatic(result.getModifiers())) {
-				throw new NoSuchMethodError(
-						"getCondition method must be static");
-			}
-			
-			return result;
-		}
-	}
-	
 	private static final String	CONDITION_TYPE	= "org.osgi.service.condpermadmin.BundleSignerCondition";
 
 	/**
@@ -116,39 +60,48 @@
 	 * to the location pattern.
 	 * 
 	 * @param bundle The Bundle being evaluated.
-	 * @param info The ConditionInfo to construct the condition for. The args of
-	 *        the ConditionInfo specify a single String specifying the chain of
-	 *        distinguished names pattern to match against the signer of the
-	 *        Bundle.
-	 * @return A Condition which checks the signers of the specified bundle.        
+	 * @param info The ConditionInfo from which to construct the condition. The
+	 *        ConditionInfo must specify one or two arguments. The first
+	 *        argument of the ConditionInfo specifies the chain of distinguished
+	 *        names pattern to match against the signer of the bundle. The
+	 *        Condition is satisfied if the signer of the bundle matches the
+	 *        pattern. The second argument of the ConditionInfo is optional. If
+	 *        a second argument is present and equal to "!", then the
+	 *        satisfaction of the Condition is negated. That is, the Condition
+	 *        is satisfied if the signer of the bundle does NOT match the
+	 *        pattern. If the second argument is present but does not equal "!",
+	 *        then the second argument is ignored.
+	 * @return A Condition which checks the signers of the specified bundle.
 	 */
-	public static Condition getCondition(Bundle bundle, ConditionInfo info) {
+	public static Condition getCondition(final Bundle bundle,
+			final ConditionInfo info) {
 		if (!CONDITION_TYPE.equals(info.getType()))
 			throw new IllegalArgumentException(
 					"ConditionInfo must be of type \"" + CONDITION_TYPE + "\"");
 		String[] args = info.getArgs();
-		if (args.length != 1)
+		if (args.length != 1 && args.length != 2)
 			throw new IllegalArgumentException("Illegal number of args: "
 					+ args.length);
 
-		try {
-			try {
-				return (Condition) ImplHolder.getCondition.invoke(null, new Object[] {
-						bundle, info});
+		Map/* <X509Certificate, List<X509Certificate>> */signers = bundle
+				.getSignerCertificates(Bundle.SIGNERS_TRUSTED);
+		boolean match = false;
+		for (Iterator iSigners = signers.values().iterator(); iSigners
+				.hasNext();) {
+			List/* <X509Certificate> */signerCerts = (List) iSigners.next();
+			List/* <String> */dnChain = new ArrayList(signerCerts.size());
+			for (Iterator iCerts = signerCerts.iterator(); iCerts.hasNext();) {
+				dnChain.add(((X509Certificate) iCerts.next()).getSubjectDN()
+						.getName());
 			}
-			catch (InvocationTargetException e) {
-				throw e.getTargetException();
+			if (FrameworkUtil.matchDistinguishedNameChain(args[0], dnChain)) {
+				match = true;
+				break;
 			}
 		}
-		catch (Error e) {
-			throw e;
-		}
-		catch (RuntimeException e) {
-			throw e;
-		}
-		catch (Throwable e) {
-			throw new RuntimeException(e.toString());
-		}
+
+		boolean negate = (args.length == 2) ? "!".equals(args[1]) : false;
+		return negate ^ match ? Condition.TRUE : Condition.FALSE;
 	}
 
 	private BundleSignerCondition() {
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/Condition.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/Condition.java
index 4716c0a..63c33b4 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/Condition.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/Condition.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/Condition.java,v 1.13 2006/06/16 16:31:37 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). 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.
@@ -25,7 +23,8 @@
  * using Conditional Permission Info. The Permissions of a ConditionalPermission
  * Info can only be used if the associated Conditions are satisfied.
  * 
- * @version $Revision: 1.13 $
+ * @ThreadSafe
+ * @version $Revision: 6464 $
  */
 public interface Condition {
 	/**
@@ -42,63 +41,75 @@
 
 	/**
 	 * Returns whether the evaluation must be postponed until the end of the
-	 * permission check. This method returns <code>true</code> if the
-	 * evaluation of the Condition must be postponed until the end of the
-	 * permission check. If this method returns <code>false</code>, 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, need to be consulted.
+	 * permission check. If this method returns <code>false</code> (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</code> to indicate the evaluation must be postponed.
-	 *         Otherwise, <code>false</code> if the evaluation can be
-	 *         immediately performed.
+	 *         Otherwise, <code>false</code> if the evaluation can be performed
+	 *         immediately.
 	 */
 	boolean isPostponed();
 
 	/**
-	 * Returns whether the Condition is satisfied.
+	 * 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</code> to indicate the Conditions is satisfied. 
+	 * @return <code>true</code> to indicate the Conditions is satisfied.
 	 *         Otherwise, <code>false</code> if the Condition is not satisfied.
 	 */
 	boolean isSatisfied();
 
 	/**
-	 * Returns whether the Condition is mutable.
+	 * Returns whether the Condition is mutable. A Condition can go from mutable
+	 * (<code>true</code>) to immutable (<code>false</code>) over time but never
+	 * from immutable (<code>false</code>) to mutable (<code>true</code>).
 	 * 
-	 * @return <code>true</code> to indicate the value returned by
-	 *         {@link #isSatisfied()} can change. Otherwise, <code>false</code>
-	 *         if the value returned by {@link #isSatisfied()} will not change.
+	 * @return <code>true</code> {@link #isSatisfied()} can change. Otherwise,
+	 *         <code>false</code> if the value returned by
+	 *         {@link #isSatisfied()} will not change for this condition.
 	 */
 	boolean isMutable();
 
 	/**
-	 * Returns whether a the set of Conditions are satisfied. Although this
-	 * method is not static, it must be implemented as if it were static. All of
-	 * the passed Conditions will be of the same type and will correspond to the
-	 * class type of the object on which this method is invoked.
+	 * Returns whether a the 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 Conditions.
+	 * @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 evaluation, the same Dictionary will be passed multiple
+	 *        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 invocatios are needed.
-	 * @return <code>true</code> if all the Conditions are satisfied.
-	 *         Otherwise, <code>false</code> if one of the Conditions is not
-	 *         satisfied.
+	 *        subsequent invocations if multiple invocations are needed.
+	 * @return <code>true</code> if all the Condition objects are satisfied.
+	 *         Otherwise, <code>false</code> if one of the Condition objects is
+	 *         not satisfied.
 	 */
 	boolean isSatisfied(Condition conditions[], Dictionary context);
-
 }
 
 /**
- * Package internal class used to define the {@link Condition#FALSE} and
+ * Package private class used to define the {@link Condition#FALSE} and
  * {@link Condition#TRUE} constants.
+ * 
+ * @Immutable
  */
 final class BooleanCondition implements Condition {
-	final boolean	satisfied;
+	private final boolean	satisfied;
 
 	BooleanCondition(boolean satisfied) {
 		this.satisfied = satisfied;
@@ -117,11 +128,10 @@
 	}
 
 	public boolean isSatisfied(Condition[] conds, Dictionary context) {
-		for (int i = 0; i < conds.length; i++) {
+		for (int i = 0, length = conds.length; i < length; i++) {
 			if (!conds[i].isSatisfied())
 				return false;
 		}
 		return true;
 	}
-
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java
index e32c4ab..6cb235c 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/ConditionInfo.java,v 1.13 2006/06/16 16:31:37 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). 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.
@@ -45,40 +43,39 @@
  * <code>ConditionInfo</code> object as arguments.
  * </ul>
  * 
- * @version $Revision: 1.13 $
+ * @Immutable
+ * @version $Revision: 6492 $
  */
 public class ConditionInfo {
-	private String		type;
-	private String[]	args;
+	private final String	type;
+	private final String[]	args;
 
 	/**
-	 * Constructs a <code>ConditionInfo</code> from the specified type and
-	 * args.
+	 * Constructs a <code>ConditionInfo</code> from the specified type and args.
 	 * 
 	 * @param type The fully qualified class name of the Condition represented
 	 *        by this <code>ConditionInfo</code>.
 	 * @param args The arguments for the Condition. These arguments are
 	 *        available to the newly created Condition by calling the
 	 *        {@link #getArgs()} method.
-	 * @throws java.lang.NullPointerException If <code>type</code> is
-	 *         <code>null</code>.
+	 * @throws NullPointerException If <code>type</code> is <code>null</code>.
 	 */
 	public ConditionInfo(String type, String[] args) {
 		this.type = type;
-		this.args = args != null ? args : new String[0];
+		this.args = (args != null) ? (String[]) args.clone() : new String[0];
 		if (type == null) {
 			throw new NullPointerException("type is null");
 		}
 	}
 
 	/**
-	 * Constructs a <code>ConditionInfo</code> object from the specified
-	 * encoded <code>ConditionInfo</code> string. White space in the encoded
+	 * Constructs a <code>ConditionInfo</code> object from the specified encoded
+	 * <code>ConditionInfo</code> string. White space in the encoded
 	 * <code>ConditionInfo</code> string is ignored.
 	 * 
 	 * @param encodedCondition The encoded <code>ConditionInfo</code>.
 	 * @see #getEncoded
-	 * @throws java.lang.IllegalArgumentException If the
+	 * @throws IllegalArgumentException If the specified
 	 *         <code>encodedCondition</code> is not properly formatted.
 	 */
 	public ConditionInfo(String encodedCondition) {
@@ -165,26 +162,25 @@
 	}
 
 	/**
-	 * Returns the string encoding of this <code>ConditionInfo</code> in a
-	 * form suitable for restoring this <code>ConditionInfo</code>.
+	 * Returns the string encoding of this <code>ConditionInfo</code> in a form
+	 * suitable for restoring this <code>ConditionInfo</code>.
 	 * 
 	 * <p>
-	 * The encoding format is:
+	 * The encoded format is:
 	 * 
 	 * <pre>
 	 *   [type &quot;arg0&quot; &quot;arg1&quot; ...]
 	 * </pre>
 	 * 
-	 * where <i>argN</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.
+	 * where <i>argN</i> are strings that must be encoded for proper parsing.
+	 * Specifically, the <code>&quot;</code>, <code>\</code>, carriage return,
+	 * and line feed characters must be escaped using <code>\&quot;</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 type and "<i>arg0</i>" and
-	 * between the arguments.
+	 * 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</code>.
 	 */
@@ -234,7 +230,7 @@
 	 *         arguments.
 	 */
 	public final String[] getArgs() {
-		return args;
+		return (String[]) args.clone();
 	}
 
 	/**
@@ -278,12 +274,11 @@
 	 */
 
 	public int hashCode() {
-		int hash = type.hashCode();
-
+		int h = 31 * 17 + type.hashCode();
 		for (int i = 0; i < args.length; i++) {
-			hash ^= args[i].hashCode();
+			h = 31 * h + args[i].hashCode();
 		}
-		return hash;
+		return h;
 	}
 
 	/**
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java
index b35f87c..2ea7d87 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java,v 1.13 2006/06/16 16:31:37 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2009). 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.
@@ -26,79 +24,213 @@
 /**
  * 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.
  * 
- * @version $Revision: 1.13 $
+ * @ThreadSafe
+ * @version $Revision: 6782 $
  */
 public interface ConditionalPermissionAdmin {
 	/**
-	 * Create a new Conditional Permission Info.
-	 * 
+	 * Create a new Conditional Permission Info in the Conditional Permission
+	 * Table.
+	 * <p>
 	 * The Conditional Permission Info will be given a unique, never reused
-	 * name.
+	 * 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 conds The Conditions that need to be satisfied to enable the
-	 *        corresponding Permissions.
-	 * @param perms The Permissions that are enable when the corresponding
-	 *        Conditions are satisfied.
+	 * @param conditions The conditions that need to be satisfied to enable the
+	 *        specified permissions. This argument can be <code>null</code> 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</code> 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</code>.
+	 * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+	 *             instead.
 	 */
-	public ConditionalPermissionInfo addConditionalPermissionInfo(
-			ConditionInfo conds[], PermissionInfo perms[]);
+	ConditionalPermissionInfo addConditionalPermissionInfo(
+			ConditionInfo conditions[], PermissionInfo permissions[]);
 
 	/**
-	 * Set or create a Conditional Permission Info with a specified name.
-	 * 
-	 * If the specified name is <code>null</code>, 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
+	 * Set or create a Conditional Permission Info with a specified name in the
+	 * Conditional Permission Table.
+	 * <p>
+	 * If the specified name is <code>null</code>, 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.
+	 * 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</code>.
-	 * @param conds The Conditions that need to be satisfied to enable the
-	 *        corresponding Permissions.
-	 * @param perms The Permissions that are enable when the corresponding
-	 *        Conditions are satisfied.
-	 * @return The ConditionalPermissionInfo that for the specified name,
-	 *         Conditions and Permissions.
+	 * @param conditions The conditions that need to be satisfied to enable the
+	 *        specified permissions. This argument can be <code>null</code> 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</code> 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</code>.
+	 * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+	 *             instead.
 	 */
-	public ConditionalPermissionInfo setConditionalPermissionInfo(String name,
-			ConditionInfo conds[], PermissionInfo perms[]);
+	ConditionalPermissionInfo setConditionalPermissionInfo(String name,
+			ConditionInfo conditions[], PermissionInfo permissions[]);
 
 	/**
-	 * Returns the Conditional Permission Infos that are currently managed by
-	 * Conditional Permission Admin. Calling
-	 * {@link ConditionalPermissionInfo#delete()} will remove the Conditional
-	 * Permission Info from Conditional Permission Admin.
+	 * 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 managed by Conditional Permission Admin.
+	 *         currently in the Conditional Permission Table.
+	 * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+	 *             instead.
 	 */
-	public Enumeration getConditionalPermissionInfos();
+	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.
+	 * @return The Conditional Permission Info with the specified name or
+	 *         <code>null</code> if no Conditional Permission Info with the
+	 *         specified name exists in the Conditional Permission Table.
+	 * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+	 *             instead.
 	 */
-	public ConditionalPermissionInfo getConditionalPermissionInfo(String name);
+	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</code> because the state is UNINSTALLED</li>
+	 * <li>All other methods return a <code>null</code></li>
+	 * </ul> 
 	 * @param signers The signers for which to return an Access Control Context.
 	 * @return An <code>AccessControlContext</code> that has the Permissions
 	 *         associated with the signer.
 	 */
-	public AccessControlContext getAccessControlContext(String[] signers);
+	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</code> method on <code>ConditionalPermissionInfo</code>
+	 * objects created with this method must throw
+	 * UnsupportedOperationException.
+	 * 
+	 * @param name The name of the created
+	 *        <code>ConditionalPermissionInfo</code> or <code>null</code> to
+	 *        have a unique name generated when the returned
+	 *        <code>ConditionalPermissionInfo</code> 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</code> 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</code> 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</code> 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</code> from the specified
+	 * encoded <code>ConditionalPermissionInfo</code> string suitable for
+	 * insertion into a {@link ConditionalPermissionUpdate}. The
+	 * <code>delete</code> method on <code>ConditionalPermissionInfo</code>
+	 * objects created with this method must throw
+	 * UnsupportedOperationException.
+	 * 
+	 * @param encodedConditionalPermissionInfo The encoded
+	 *        <code>ConditionalPermissionInfo</code>. White space in the encoded
+	 *        <code>ConditionalPermissionInfo</code> is ignored. The access
+	 *        decision value in the encoded
+	 *        <code>ConditionalPermissionInfo</code> must be evaluated case
+	 *        insensitively. If the encoded
+	 *        <code>ConditionalPermissionInfo</code> does not contain the
+	 *        optional name, <code>null</code> must be used for the name and a
+	 *        unique name will be generated when the returned
+	 *        <code>ConditionalPermissionInfo</code> is committed in an update
+	 *        to the Conditional Permission Table.
+	 * @return A <code>ConditionalPermissionInfo</code> object suitable for
+	 *         insertion into a {@link ConditionalPermissionUpdate}.
+	 * @throws IllegalArgumentException If the specified
+	 *         <code>encodedConditionalPermissionInfo</code> is not properly
+	 *         formatted.
+	 * @see ConditionalPermissionInfo#getEncoded
+	 * @since 1.1
+	 */
+	ConditionalPermissionInfo newConditionalPermissionInfo(
+			String encodedConditionalPermissionInfo);
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java
index 31e4d2c..dbe09be 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java,v 1.11 2006/06/16 16:31:37 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). 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.
@@ -21,43 +19,172 @@
 import org.osgi.service.permissionadmin.PermissionInfo;
 
 /**
- * A binding of a set of Conditions to a set of Permissions. Instances of this
- * interface are obtained from the Conditional Permission Admin service.
+ * 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.
  * 
- * @version $Revision: 1.11 $
+ * @Immutable
+ * @version $Revision: 6492 $
  */
 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.
 	 */
-	public ConditionInfo[] getConditionInfos();
+	ConditionInfo[] getConditionInfos();
 
 	/**
-	 * Returns the Permission Infos for the Permission in this Conditional
+	 * Returns the Permission Infos for the Permissions in this Conditional
 	 * Permission Info.
 	 * 
-	 * @return The Permission Infos for the Permission in this Conditional
+	 * @return The Permission Infos for the Permissions in this Conditional
 	 *         Permission Info.
 	 */
-	public PermissionInfo[] getPermissionInfos();
+	PermissionInfo[] getPermissionInfos();
 
 	/**
 	 * Removes this Conditional Permission Info from the Conditional Permission
-	 * Admin.
+	 * 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</code>.
+	 * @deprecated Since 1.1. Use
+	 *             {@link ConditionalPermissionAdmin#newConditionalPermissionUpdate()}
+	 *             instead to manage the Conditional Permissions.
 	 */
-	public void delete();
+	void delete();
 
 	/**
 	 * Returns the name of this Conditional Permission Info.
 	 * 
-	 * @return The name of this Conditional Permission Info.
+	 * @return The name of this Conditional Permission Info. This can be
+	 *         <code>null</code> if this Conditional Permission Info was created
+	 *         without a name.
 	 */
-	public String getName();
+	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</code> in a form suitable for restoring
+	 * this <code>ConditionalPermissionInfo</code>.
+	 * 
+	 * <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</code>.
+	 * 
+	 * <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;</code>. The
+	 * <i>name</i> value must be encoded for proper parsing. Specifically, the
+	 * <code>&quot;</code>, <code>\</code>, carriage return, and line feed
+	 * characters must be escaped using <code>\&quot;</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>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</code>.
+	 * @since 1.1
+	 */
+	String getEncoded();
+
+	/**
+	 * Returns the string representation of this
+	 * <code>ConditionalPermissionInfo</code>. The string is created by calling
+	 * the <code>getEncoded</code> method on this
+	 * <code>ConditionalPermissionInfo</code>.
+	 * 
+	 * @return The string representation of this
+	 *         <code>ConditionalPermissionInfo</code>.
+	 * @since 1.1
+	 */
+	String toString();
+
+	/**
+	 * Determines the equality of two <code>ConditionalPermissionInfo</code>
+	 * objects.
+	 * 
+	 * This method checks that specified object has the same access decision,
+	 * conditions, permissions and name as this
+	 * <code>ConditionalPermissionInfo</code> object.
+	 * 
+	 * @param obj The object to test for equality with this
+	 *        <code>ConditionalPermissionInfo</code> object.
+	 * @return <code>true</code> if <code>obj</code> is a
+	 *         <code>ConditionalPermissionInfo</code>, and has the same access
+	 *         decision, conditions, permissions and name as this
+	 *         <code>ConditionalPermissionInfo</code> object; <code>false</code>
+	 *         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();
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionUpdate.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionUpdate.java
new file mode 100644
index 0000000..b116cf9
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionUpdate.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). 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
+ * @version $Revision: 6492 $
+ * @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</code> 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</code> 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</code> will be thrown.
+	 * <p>
+	 * This method returns <code>false</code> if the commit did not occur
+	 * because the Conditional Permission Table has been modified since the
+	 * creation of this update.
+	 * 
+	 * @return <code>true</code> if the commit was successful.
+	 *         <code>false</code> 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</code>.
+	 * @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();
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/package.html b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/package.html
new file mode 100644
index 0000000..7930813
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/package.html
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>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.
+For example:
+<pre>
+Import-Package: org.osgi.service.condpermadmin; version=&quot;[1.1,2.0)&quot;
+</pre>
+</BODY>
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/packageinfo b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java
index 2f3deb1..67ba3e9 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.packageadmin/src/org/osgi/service/packageadmin/ExportedPackage.java,v 1.14 2006/06/16 16:31:49 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2001, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2001, 2008). 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.
@@ -43,7 +41,8 @@
  * <code>getExportingBundle()</code> and <code>getImportingBundles()</code>
  * return <code>null</code>.
  * 
- * @version $Revision: 1.14 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
  */
 public interface ExportedPackage {
 	/**
@@ -73,7 +72,8 @@
 	 * 
 	 * @return The array of resolved bundles currently wired to this exported
 	 *         package, or <code>null</code> if this
-	 *         <code>ExportedPackage</code> object has become stale.
+	 *         <code>ExportedPackage</code> object has become stale. The array
+	 *         will be empty if no bundles are wired to this exported package.
 	 */
 	public Bundle[] getImportingBundles();
 
diff --git a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java
index a382f39..c93cd28 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.packageadmin/src/org/osgi/service/packageadmin/PackageAdmin.java,v 1.19 2006/06/16 16:31:49 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2001, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2001, 2009). 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.
@@ -29,7 +27,8 @@
  * If present, there will only be a single instance of this service registered
  * with the Framework.
  * 
- * @version $Revision: 1.19 $
+ * @ThreadSafe
+ * @version $Revision: 6779 $
  * @see org.osgi.service.packageadmin.ExportedPackage
  * @see org.osgi.service.packageadmin.RequiredBundle
  */
@@ -38,8 +37,8 @@
 	 * Gets the exported packages for the specified bundle.
 	 * 
 	 * @param bundle The bundle whose exported packages are to be returned, or
-	 *        <code>null</code> if all exported packages are to be returned.
-	 *        If the specified bundle is the system bundle (that is, the bundle
+	 *        <code>null</code> 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</code>
@@ -48,6 +47,9 @@
 	 * 
 	 * @return An array of exported packages, or <code>null</code> if the
 	 *         specified bundle has no exported packages.
+	 * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+	 *         not created by the same framework instance that registered this
+	 *         <code>PackageAdmin</code> service.
 	 */
 	public ExportedPackage[] getExportedPackages(Bundle bundle);
 
@@ -93,8 +95,8 @@
 	 * 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
+	 * <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
@@ -105,9 +107,9 @@
 	 * <li>Each bundle in the graph that is in the <code>ACTIVE</code> state
 	 * will be stopped as described in the <code>Bundle.stop</code> method.
 	 * 
-	 * <li>Each bundle in the graph that is in the <code>RESOLVED</code>
-	 * state is unresolved and thus moved to the <code>INSTALLED</code> state.
-	 * The effect of this step is that bundles in the graph are no longer
+	 * <li>Each bundle in the graph that is in the <code>RESOLVED</code> state
+	 * is unresolved and thus moved to the <code>INSTALLED</code> state. The
+	 * effect of this step is that bundles in the graph are no longer
 	 * <code>RESOLVED</code>.
 	 * 
 	 * <li>Each bundle in the graph that is in the <code>UNINSTALLED</code>
@@ -137,8 +139,11 @@
 	 *        removed, or <code>null</code> 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]</code> and the
-	 *         Java runtime environment supports permissions.
+	 *         <code>AdminPermission[System Bundle,RESOLVE]</code> and the Java
+	 *         runtime environment supports permissions.
+	 * @throws IllegalArgumentException If the specified <code>Bundle</code>s
+	 *         were not created by the same framework instance that registered
+	 *         this <code>PackageAdmin</code> service.
 	 */
 	public void refreshPackages(Bundle[] bundles);
 
@@ -155,12 +160,15 @@
 	 * be refreshed, stopped, or started. This method will not return until the
 	 * operation has completed.
 	 * 
-	 * @param bundles The bundles to resolve or <code>null</code> to resolve
-	 *        all unresolved bundles installed in the Framework.
+	 * @param bundles The bundles to resolve or <code>null</code> to resolve all
+	 *        unresolved bundles installed in the Framework.
 	 * @return <code>true</code> if all specified bundles are resolved;
 	 * @throws SecurityException If the caller does not have
-	 *         <code>AdminPermission[System Bundle,RESOLVE]</code> and the
-	 *         Java runtime environment supports permissions.
+	 *         <code>AdminPermission[System Bundle,RESOLVE]</code> and the Java
+	 *         runtime environment supports permissions.
+	 * @throws IllegalArgumentException If the specified <code>Bundle</code>s
+	 *         were not created by the same framework instance that registered
+	 *         this <code>PackageAdmin</code> service.
 	 * @since 1.2
 	 */
 	public boolean resolveBundles(Bundle[] bundles);
@@ -203,8 +211,8 @@
 
 	/**
 	 * Returns an array of attached fragment bundles for the specified bundle.
-	 * If the specified bundle is a fragment then <code>null</code> is
-	 * returned. If no fragments are attached to the specified bundle then
+	 * If the specified bundle is a fragment then <code>null</code> is returned.
+	 * If no fragments are attached to the specified bundle then
 	 * <code>null</code> is returned.
 	 * <p>
 	 * This method does not attempt to resolve the specified bundle. If the
@@ -215,19 +223,24 @@
 	 * @return An array of fragment bundles or <code>null</code> if the bundle
 	 *         does not have any attached fragment bundles or the bundle is not
 	 *         resolved.
+	 * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+	 *         not created by the same framework instance that registered this
+	 *         <code>PackageAdmin</code> service.
 	 * @since 1.2
 	 */
 	public Bundle[] getFragments(Bundle bundle);
 
 	/**
-	 * Returns an array containing the host bundle to which the specified
-	 * fragment bundle is attached or <code>null</code> if the specified
-	 * bundle is not attached to a host or is not a fragment bundle. A fragment
-	 * may only be attached to a single host bundle.
+	 * Returns the host bundles to which the specified fragment bundle is
+	 * attached.
 	 * 
-	 * @param bundle The bundle whose host bundle is to be returned.
-	 * @return An array containing the host bundle or <code>null</code> if the
-	 *         bundle does not have a host bundle.
+	 * @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</code> if the specified bundle
+	 *         is not a fragment or is not attached to any host bundles.
+	 * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+	 *         not created by the same framework instance that registered this
+	 *         <code>PackageAdmin</code> service.
 	 * @since 1.2
 	 */
 	public Bundle[] getHosts(Bundle bundle);
@@ -241,7 +254,8 @@
 	 * @param clazz The class object from which to locate the bundle.
 	 * @return The bundle from which the specified class is loaded or
 	 *         <code>null</code> if the class was not loaded by a bundle class
-	 *         loader.
+	 *         loader created by the same framework instance that registered
+	 *         this <code>PackageAdmin</code> service.
 	 * @since 1.2
 	 */
 	public Bundle getBundle(Class clazz);
@@ -272,6 +286,9 @@
 	 * 
 	 * @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</code> was
+	 *         not created by the same framework instance that registered this
+	 *         <code>PackageAdmin</code> service.
 	 * @since 1.2
 	 */
 	public int getBundleType(Bundle bundle);
diff --git a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java
index 9755e86..b15c5df 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.packageadmin/src/org/osgi/service/packageadmin/RequiredBundle.java,v 1.11 2006/06/16 16:31:49 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2008). 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.
@@ -44,7 +42,8 @@
  * and <code>getRequiringBundles()</code> return <code>null</code>.
  * 
  * @since 1.2
- * @version $Revision: 1.11 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
  */
 public interface RequiredBundle {
 	/**
@@ -72,7 +71,8 @@
 	 * 
 	 * @return An array of bundles currently requiring this required bundle, or
 	 *         <code>null</code> if this <code>RequiredBundle</code> object
-	 *         has become stale.
+	 *         has become stale. The array will be empty if no bundles require
+	 *         this required package.
 	 */
 	public Bundle[] getRequiringBundles();
 
@@ -89,7 +89,7 @@
 	 * Returns <code>true</code> if the bundle associated with this
 	 * <code>RequiredBundle</code> object has been updated or uninstalled.
 	 * 
-	 * @return <code>true</code> if the reqiured bundle has been updated or
+	 * @return <code>true</code> if the required bundle has been updated or
 	 *         uninstalled, or if the <code>RequiredBundle</code> object has
 	 *         become stale; <code>false</code> otherwise.
 	 */
diff --git a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/package.html b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/package.html
new file mode 100644
index 0000000..9fc9cab
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Package 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.
+For example:
+<pre>
+Import-Package: org.osgi.service.packageadmin; version=&quot;[1.2,2.0)&quot;
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/packageinfo b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/packageinfo
new file mode 100644
index 0000000..ef7df68
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/packageinfo
@@ -0,0 +1 @@
+version 1.2
diff --git a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java
index 0588ae3..d51a9d4 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.permissionadmin/src/org/osgi/service/permissionadmin/PermissionAdmin.java,v 1.12 2006/06/16 16:31:44 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2001, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2001, 2008). 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.
@@ -24,39 +22,41 @@
  * 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.
+ * <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
+ * 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
+ * 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.
+ * 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.
+ * 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>.
+ * not reflected in the permissions returned by <code>getPermissions</code>
+ * and <code>getDefaultPermissions</code>.
  * 
- * @version $Revision: 1.12 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
  */
 public interface PermissionAdmin {
 	/**
@@ -66,8 +66,8 @@
 	 *        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.
+	 *         location, or <code>null</code> if that bundle has not been
+	 *         assigned any permissions.
 	 */
 	PermissionInfo[] getPermissions(String location);
 
@@ -77,10 +77,11 @@
 	 * 
 	 * @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.
+	 * @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>.
+	 *         <code>AllPermission</code>.
 	 */
 	void setPermissions(String location, PermissionInfo[] permissions);
 
@@ -115,7 +116,7 @@
 	 * @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>.
+	 *         <code>AllPermission</code>.
 	 */
 	void setDefaultPermissions(PermissionInfo[] permissions);
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java
index e0e72c7..e4bfae7 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.permissionadmin/src/org/osgi/service/permissionadmin/PermissionInfo.java,v 1.16 2006/06/16 16:31:44 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2001, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2001, 2009). 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.
@@ -24,8 +22,8 @@
  * <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.
+ * <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
@@ -35,22 +33,23 @@
  * <code>PermissionInfo</code> may be delayed until the package containing its
  * Permission class has been exported by a bundle.
  * 
- * @version $Revision: 1.16 $
+ * @Immutable
+ * @version $Revision: 6492 $
  */
 public class PermissionInfo {
-	private String	type;
-	private String	name;
-	private String	actions;
+	private final String	type;
+	private final String	name;
+	private final String	actions;
 
 	/**
-	 * Constructs a <code>PermissionInfo</code> from the specified type, name, and
-	 * 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.
+	 *        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
@@ -60,10 +59,9 @@
 	 *        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>.
+	 * @throws NullPointerException If <code>type</code> is <code>null</code>.
+	 * @throws 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;
@@ -78,15 +76,15 @@
 	}
 
 	/**
-	 * Constructs a <code>PermissionInfo</code> object from the specified encoded
-	 * <code>PermissionInfo</code> string. White space in the encoded
+	 * 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.
+	 * @throws IllegalArgumentException If the specified
+	 *         <code>encodedPermission</code> is not properly formatted.
 	 */
 	public PermissionInfo(String encodedPermission) {
 		if (encodedPermission == null) {
@@ -95,20 +93,22 @@
 		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");
+				throw new IllegalArgumentException("expecting open parenthesis");
 			}
 			pos++;
 
@@ -116,22 +116,23 @@
 			while (Character.isWhitespace(encoded[pos])) {
 				pos++;
 			}
-			
+
 			/* type is not quoted or encoded */
 			int begin = pos;
-			while (!Character.isWhitespace(encoded[pos]) && (encoded[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);
-			
+			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++;
@@ -142,7 +143,7 @@
 					}
 					pos++;
 				}
-				this.name = unescapeString(encoded, begin, pos);
+				parsedName = unescapeString(encoded, begin, pos);
 				pos++;
 
 				if (Character.isWhitespace(encoded[pos])) {
@@ -150,8 +151,11 @@
 					while (Character.isWhitespace(encoded[pos])) {
 						pos++;
 					}
-					
-					/* name may be followed by actions which is quoted and encoded */
+
+					/*
+					 * name may be followed by actions which is quoted and
+					 * encoded
+					 */
 					if (encoded[pos] == '"') {
 						pos++;
 						begin = pos;
@@ -161,7 +165,7 @@
 							}
 							pos++;
 						}
-						this.actions = unescapeString(encoded, begin, pos);
+						parsedActions = unescapeString(encoded, begin, pos);
 						pos++;
 
 						/* skip whitespace */
@@ -171,7 +175,7 @@
 					}
 				}
 			}
-			
+
 			/* the final character must be ')' */
 			char c = encoded[pos];
 			pos++;
@@ -179,12 +183,17 @@
 				pos++;
 			}
 			if ((c != ')') || (pos != length)) {
-				throw new IllegalArgumentException("expecting close parenthesis");
+				throw new IllegalArgumentException(
+						"expecting close parenthesis");
 			}
 		}
 		catch (ArrayIndexOutOfBoundsException e) {
 			throw new IllegalArgumentException("parsing terminated abruptly");
 		}
+
+		type = parsedType;
+		name = parsedName;
+		actions = parsedActions;
 	}
 
 	/**
@@ -210,15 +219,17 @@
 	 * (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.
+	 * where <i>name</i> and <i>actions</i> are strings that must be encoded for
+	 * proper parsing. Specifically, the <code>&quot;</code>,<code>\</code>,
+	 * carriage return, and line feed characters must be escaped using
+	 * <code>\&quot;</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;.
+	 * 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>.
 	 */
@@ -244,9 +255,9 @@
 	}
 
 	/**
-	 * 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>.
+	 * 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>.
 	 */
@@ -270,8 +281,8 @@
 	 * <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.
+	 *         <code>PermissionInfo</code>, or <code>null</code> if the
+	 *         permission does not have a name.
 	 */
 	public final String getName() {
 		return name;
@@ -282,8 +293,8 @@
 	 * <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.
+	 *         <code>PermissionInfo</code>, or <code>null</code> if the
+	 *         permission does not have any actions associated with it.
 	 */
 	public final String getActions() {
 		return actions;
@@ -297,9 +308,10 @@
 	 * 
 	 * @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.
+	 * @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) {
@@ -315,8 +327,7 @@
 		}
 		if (name != null) {
 			if (actions != null) {
-				return name.equals(other.name) && actions
-						.equals(other.actions);
+				return name.equals(other.name) && actions.equals(other.actions);
 			}
 			else {
 				return name.equals(other.name);
@@ -333,14 +344,14 @@
 	 * @return A hash code value for this object.
 	 */
 	public int hashCode() {
-		int hash = type.hashCode();
+		int h = 31 * 17 + type.hashCode();
 		if (name != null) {
-			hash ^= name.hashCode();
+			h = 31 * h + name.hashCode();
 			if (actions != null) {
-				hash ^= actions.hashCode();
+				h = 31 * h + actions.hashCode();
 			}
 		}
-		return hash;
+		return h;
 	}
 
 	/**
@@ -400,7 +411,7 @@
 			}
 			output.append(c);
 		}
-		
+
 		return output.toString();
 	}
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/package.html b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/package.html
new file mode 100644
index 0000000..396264c
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>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.
+For example:
+<pre>
+Import-Package: org.osgi.service.permissionadmin; version=&quot;[1.2,2.0)&quot;
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/packageinfo b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/packageinfo
new file mode 100644
index 0000000..ef7df68
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/packageinfo
@@ -0,0 +1 @@
+version 1.2
diff --git a/org.osgi.core/src/main/java/org/osgi/service/startlevel/StartLevel.java b/org.osgi.core/src/main/java/org/osgi/service/startlevel/StartLevel.java
index 97e79e9..8a69b03 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/startlevel/StartLevel.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/startlevel/StartLevel.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.startlevel/src/org/osgi/service/startlevel/StartLevel.java,v 1.19 2007/02/09 03:20:24 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2002, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 2009). 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.
@@ -68,7 +66,8 @@
  * The StartLevel service can be used by management bundles to alter the active
  * start level of the framework.
  * 
- * @version $Revision: 1.19 $
+ * @ThreadSafe
+ * @version $Revision: 6747 $
  */
 public interface StartLevel {
 	/**
@@ -152,7 +151,9 @@
 	 * @param bundle The target bundle.
 	 * @return The start level value of the specified Bundle.
 	 * @throws java.lang.IllegalArgumentException If the specified bundle has
-	 *         been uninstalled.
+	 *         been uninstalled or if the specified bundle was not created by
+	 *         the same framework instance that registered this
+	 *         <code>StartLevel</code> service.
 	 */
 	public int getBundleStartLevel(Bundle bundle);
 
@@ -183,11 +184,13 @@
 	 * @param bundle The target bundle.
 	 * @param startlevel The new start level for the specified Bundle.
 	 * @throws IllegalArgumentException If the specified bundle has been
-	 *         uninstalled or if the specified start level is less than or equal
-	 *         to zero, or the specified bundle is the system bundle.
+	 *         uninstalled, or if the specified start level is less than or
+	 *         equal to zero, or if the specified bundle is the system bundle,
+	 *         or if the specified bundle was not created by the same framework
+	 *         instance that registered this <code>StartLevel</code> service.
 	 * @throws SecurityException If the caller does not have
-	 *         <code>AdminPermission[bundle,EXECUTE]</code> and the Java
-	 *         runtime environment supports permissions.
+	 *         <code>AdminPermission[bundle,EXECUTE]</code> and the Java runtime
+	 *         environment supports permissions.
 	 */
 	public void setBundleStartLevel(Bundle bundle, int startlevel);
 
@@ -218,7 +221,7 @@
 	 * been called to assign a different initial bundle start level value.
 	 * 
 	 * <p>
-	 * Thie method does not change the start level values of installed bundles.
+	 * This method does not change the start level values of installed bundles.
 	 * 
 	 * @param startlevel The initial start level for newly installed bundles.
 	 * @throws IllegalArgumentException If the specified start level is less
@@ -241,7 +244,9 @@
 	 *         indicates the bundle is to be started. <code>false</code>
 	 *         otherwise.
 	 * @throws java.lang.IllegalArgumentException If the specified bundle has
-	 *         been uninstalled.
+	 *         been uninstalled or if the specified bundle was not created by
+	 *         the same framework instance that registered this
+	 *         <code>StartLevel</code> service.
 	 * @see Bundle#START_TRANSIENT
 	 */
 	public boolean isBundlePersistentlyStarted(Bundle bundle);
@@ -254,11 +259,13 @@
 	 * activation policy is to be used when the bundle is started.
 	 * 
 	 * @param bundle The bundle whose autostart setting is to be examined.
-	 * @return <code>true</code> if the bundle’s autostart setting indicates
-	 *         the activation policy declared in the manifest must be used.
+	 * @return <code>true</code> if the bundle's autostart setting indicates the
+	 *         activation policy declared in the manifest must be used.
 	 *         <code>false</code> if the bundle must be eagerly activated.
 	 * @throws java.lang.IllegalArgumentException If the specified bundle has
-	 *         been uninstalled.
+	 *         been uninstalled or if the specified bundle was not created by
+	 *         the same framework instance that registered this
+	 *         <code>StartLevel</code> service.
 	 * @since 1.1
 	 * @see Bundle#START_ACTIVATION_POLICY
 	 */
diff --git a/org.osgi.core/src/main/java/org/osgi/service/startlevel/package.html b/org.osgi.core/src/main/java/org/osgi/service/startlevel/package.html
new file mode 100644
index 0000000..4c27532
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/startlevel/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Start Level 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.
+For example:
+<pre>
+Import-Package: org.osgi.service.startlevel; version=&quot;[1.1,2.0)&quot;
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/service/startlevel/packageinfo b/org.osgi.core/src/main/java/org/osgi/service/startlevel/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/startlevel/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/AbstractURLStreamHandlerService.java b/org.osgi.core/src/main/java/org/osgi/service/url/AbstractURLStreamHandlerService.java
index b8e80dc..1ad37a2 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/url/AbstractURLStreamHandlerService.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/AbstractURLStreamHandlerService.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.url/src/org/osgi/service/url/AbstractURLStreamHandlerService.java,v 1.8 2006/06/16 16:31:31 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 2008). 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.
@@ -21,15 +19,16 @@
 import java.net.*;
 
 /**
- * Abstract implementation of the <code>URLStreamHandlerService</code> interface.
- * All the methods simply invoke the corresponding methods on
- * <code>java.net.URLStreamHandler</code> except for <code>parseURL</code> and
- * <code>setURL</code>, which use the <code>URLStreamHandlerSetter</code>
+ * Abstract implementation of the <code>URLStreamHandlerService</code>
+ * interface. All the methods simply invoke the corresponding methods on
+ * <code>java.net.URLStreamHandler</code> except for <code>parseURL</code>
+ * and <code>setURL</code>, which use the <code>URLStreamHandlerSetter</code>
  * parameter. Subclasses of this abstract class should not need to override the
  * <code>setURL</code> and <code>parseURL(URLStreamHandlerSetter,...)</code>
  * methods.
  * 
- * @version $Revision: 1.8 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
  */
 public abstract class AbstractURLStreamHandlerService extends URLStreamHandler
 		implements URLStreamHandlerService {
@@ -43,7 +42,7 @@
 	 * The <code>URLStreamHandlerSetter</code> object passed to the parseURL
 	 * method.
 	 */
-	protected URLStreamHandlerSetter	realHandler;
+	protected volatile URLStreamHandlerSetter	realHandler;
 
 	/**
 	 * Parse a URL using the <code>URLStreamHandlerSetter</code> object. This
@@ -51,8 +50,8 @@
 	 * <code>URLStreamHandlerSetter</code> object and then calls
 	 * <code>parseURL(URL,String,int,int)</code>.
 	 * 
-	 * @param realHandler The object on which the <code>setURL</code> method must
-	 *        be invoked for the specified URL.
+	 * @param realHandler The object on which the <code>setURL</code> method
+	 *        must be invoked for the specified URL.
 	 * @see "java.net.URLStreamHandler.parseURL"
 	 */
 	public void parseURL(URLStreamHandlerSetter realHandler, URL u,
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/URLConstants.java b/org.osgi.core/src/main/java/org/osgi/service/url/URLConstants.java
index 71b067e..ae95305 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/url/URLConstants.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/URLConstants.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.url/src/org/osgi/service/url/URLConstants.java,v 1.10 2006/12/01 06:38:45 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 2008). 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.
@@ -24,23 +22,23 @@
  * services.
  * 
  * <p>
- * The values associated with these keys are of type <code>java.lang.String[]</code>
- * or <code>java.lang.String</code>,
- * unless otherwise indicated.
+ * The values associated with these keys are of type
+ * <code>java.lang.String[]</code> or <code>java.lang.String</code>, unless
+ * otherwise indicated.
  * 
- * @version $Revision: 1.10 $
+ * @version $Revision: 5673 $
  */
 public interface URLConstants {
 	/**
 	 * Service property naming the protocols serviced by a
-	 * URLStreamHandlerService. The property's value is 
-	 * a protocol name or an array of protocol names.
+	 * URLStreamHandlerService. The property's value is a protocol name or an
+	 * array of protocol names.
 	 */
 	public static final String	URL_HANDLER_PROTOCOL	= "url.handler.protocol";
 	/**
 	 * Service property naming the MIME types serviced by a
-	 * java.net.ContentHandler. The property's value is a
-	 * MIME type or an array of MIME types.
+	 * java.net.ContentHandler. The property's value is a MIME type or an array
+	 * of MIME types.
 	 */
 	public static final String	URL_CONTENT_MIMETYPE	= "url.content.mimetype";
 }
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerService.java b/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerService.java
index c5cb303..b1ff7d8 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerService.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerService.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.url/src/org/osgi/service/url/URLStreamHandlerService.java,v 1.9 2006/07/11 00:53:59 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 2008). 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.
@@ -25,17 +23,19 @@
  * <code>java.net.URLStreamHandler</code> methods.
  * <p>
  * The important differences between this interface and the
- * <code>URLStreamHandler</code> class are that the <code>setURL</code> method is
- * absent and the <code>parseURL</code> method takes a
+ * <code>URLStreamHandler</code> class are that the <code>setURL</code>
+ * method is absent and the <code>parseURL</code> method takes a
  * {@link URLStreamHandlerSetter} object as the first argument. Classes
  * implementing this interface must call the <code>setURL</code> method on the
- * <code>URLStreamHandlerSetter</code> object received in the <code>parseURL</code>
- * method instead of <code>URLStreamHandler.setURL</code> to avoid a
+ * <code>URLStreamHandlerSetter</code> object received in the
+ * <code>parseURL</code> method instead of
+ * <code>URLStreamHandler.setURL</code> to avoid a
  * <code>SecurityException</code>.
  * 
  * @see AbstractURLStreamHandlerService
  * 
- * @version $Revision: 1.9 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
  */
 public interface URLStreamHandlerService {
 	/**
@@ -45,11 +45,11 @@
 
 	/**
 	 * Parse a URL. This method is called by the <code>URLStreamHandler</code>
-	 * proxy, instead of <code>java.net.URLStreamHandler.parseURL</code>, passing
-	 * a <code>URLStreamHandlerSetter</code> object.
+	 * proxy, instead of <code>java.net.URLStreamHandler.parseURL</code>,
+	 * passing a <code>URLStreamHandlerSetter</code> object.
 	 * 
-	 * @param realHandler The object on which <code>setURL</code> must be invoked
-	 *        for this URL.
+	 * @param realHandler The object on which <code>setURL</code> must be
+	 *        invoked for this URL.
 	 * @see "java.net.URLStreamHandler.parseURL"
 	 */
 	public void parseURL(URLStreamHandlerSetter realHandler, URL u,
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerSetter.java b/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerSetter.java
index fedd59f..36bdce8 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerSetter.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerSetter.java
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.service.url/src/org/osgi/service/url/URLStreamHandlerSetter.java,v 1.9 2006/07/11 00:53:59 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 2008). 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.
@@ -22,16 +20,19 @@
 
 /**
  * Interface used by <code>URLStreamHandlerService</code> objects to call the
- * <code>setURL</code> method on the proxy <code>URLStreamHandler</code> object.
+ * <code>setURL</code> method on the proxy <code>URLStreamHandler</code>
+ * object.
  * 
  * <p>
  * Objects of this type are passed to the
- * {@link URLStreamHandlerService#parseURL} method. Invoking the <code>setURL</code>
- * method on the <code>URLStreamHandlerSetter</code> object will invoke the
- * <code>setURL</code> method on the proxy <code>URLStreamHandler</code> object that
- * is actually registered with <code>java.net.URL</code> for the protocol.
+ * {@link URLStreamHandlerService#parseURL} method. Invoking the
+ * <code>setURL</code> method on the <code>URLStreamHandlerSetter</code>
+ * object will invoke the <code>setURL</code> method on the proxy
+ * <code>URLStreamHandler</code> object that is actually registered with
+ * <code>java.net.URL</code> for the protocol.
  * 
- * @version $Revision: 1.9 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
  */
 public interface URLStreamHandlerSetter {
 	/**
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/package.html b/org.osgi.core/src/main/java/org/osgi/service/url/package.html
new file mode 100644
index 0000000..4ed4d6e
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/package.html
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>URL Stream and Content Handlers Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.url; version=&quot;[1.0,2.0)&quot;
+</pre>
+</BODY>
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/packageinfo b/org.osgi.core/src/main/java/org/osgi/service/url/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/packageinfo
@@ -0,0 +1 @@
+version 1.0