You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by jw...@apache.org on 2012/02/08 14:54:44 UTC

svn commit: r1241900 [2/8] - in /aries/trunk/subsystem: ./ subsystem-api/ subsystem-api/src/main/java/org/osgi/service/repository/ subsystem-api/src/main/java/org/osgi/service/resolver/ subsystem-api/src/main/java/org/osgi/service/subsystem/ subsystem-...

Modified: aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/Subsystem.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/Subsystem.java?rev=1241900&r1=1241899&r2=1241900&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/Subsystem.java (original)
+++ aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/Subsystem.java Wed Feb  8 13:54:41 2012
@@ -17,333 +17,969 @@ package org.osgi.service.subsystem;
 
 import java.io.InputStream;
 import java.util.Collection;
+import java.util.Locale;
 import java.util.Map;
 
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Version;
+import org.osgi.framework.hooks.resolver.ResolverHook;
 import org.osgi.framework.resource.Resource;
+import org.osgi.framework.resource.ResourceConstants;
+import org.osgi.service.repository.Repository;
+import org.osgi.service.resolver.Resolver;
 
 /**
- * A representation of a subsystem in the framework. A subsystem is a 
- * collection of bundles and/or other resource. A subsystem has isolation 
- * semantics. Subsystem types are defined that have different default isolation 
- * semantics. For example, an Application subsystem does not export any of the 
- * packages or services provided by its content bundles, and imports any 
- * packages or services that are required to satisfy unresolved package or 
- * service dependencies of the content bundles. A subsystem is defined using a 
- * manifest format. 
+ * A subsystem is a collection of resources constituting a logical, possibly
+ * isolated, unit of functionality.
+ * <p/>
+ * A subsystem may be scoped or unscoped. Scoped subsystems are isolated by
+ * implicit or explicit sharing policies. Unscoped subsystems are not isolated
+ * and, therefore, have no sharing policy. There are three standard {@link
+ * SubsystemConstants#SUBSYSTEM_TYPE types} of subsystems.
+ * <ul>
+ * 		<li>{@link SubsystemConstants#SUBSYSTEM_TYPE_APPLICATION Application} -
+ *          An implicitly scoped subsystem. Nothing is exported, and imports are
+ *          computed based on any unsatisfied content dependencies.
+ * 		</li>
+ * 		<li>{@link SubsystemConstants#SUBSYSTEM_TYPE_COMPOSITE Composite} - An
+ *          explicitly scoped subsystem. The sharing policy is defined by
+ *          metadata within the subsystem archive.
+ * 		</li>
+ * 		<li>{@link SubsystemConstants#SUBSYSTEM_TYPE_FEATURE Feature} - An
+ *          unscoped subsystem.
+ * 		</li>
+ * </ul>
+ * Conceptually, a subsystem may be thought of as existing in an isolated region
+ * along with zero or more other subsystems. Each region has one and only one
+ * scoped subsystem, which dictates the sharing policy. The region may, however,
+ * have many unscoped subsystems. It is, therefore, possible to have shared
+ * constituents across multiple subsystems within a region. Associated with each
+ * region is a bundle whose context may be {@link #getBundleContext() retrieved}
+ * from any subsystem within that region. This context may be used to monitor
+ * activity occurring within the region.
+ * <p/>
+ * A subsystem may have {@link #getChildren() children} and, unless it's the
+ * root subsystem, must have at least one {@link #getParents() parent}.
+ * Subsystems become children of the subsystem in which they are installed.
+ * Unscoped subsystems have more than one parent if they are installed in more
+ * than one subsystem within the same region. A scoped subsystem always has only
+ * one parent. The subsystem graph may be thought of as is an acyclic digraph
+ * with one and only one source vertex, which is the root subsystem. The edges
+ * have the child as the head and parent as the tail.
+ * <p/>
+ * A subsystem has several unique identifiers.
+ * <ul>
+ * 		<li>{@link #getLocation() Location} - An identifier specified by the
+ *          client as part of installation. It is guaranteed to be unique within
+ *          the same framework.
+ *     </li>
+ * 		<li>{@link #getSubsystemId() ID} - An identifier generated by the
+ *          implementation as part of installation. It is guaranteed to be
+ *          unique within the same framework.
+ * 		<li>{@link #getSymbolicName() Symbolic Name}/{@link #getVersion()
+ *          Version} - The combination of symbolic name and version is
+ *          guaranteed to be unique within the same region. Although {@link
+ *          #getType() type} is not formally part of the identity, two
+ *          subsystems with the same symbolic names and versions but different
+ *          types are not considered to be equal.
+ *     </li>
+ * </ul>
+ * A subsystem has a well-defined {@link State life cycle}. Which stage a
+ * subsystem is in may be obtained from the subsystem's {@link #getState()
+ * state} and is dependent on which life cycle operation is currently active or
+ * was last invoked. The following table summarizes the relationship between
+ * life cycle operations and states.
+ * <p/>
+ * <table border="1">
+ * 		<tr align="center">
+ * 			<th>Operation</th>
+ * 			<th>From State</th>
+ * 			<th>To State</th>
+ * 		</tr>
+ * 		<tr align="center">
+ * 			<td>{@link #install(String, InputStream) Install}</td>
+ * 			<td>&nbsp;</td>
+ * 			<td>{@link State#INSTALLING INSTALLING}, {@link State#INSTALL_FAILED
+ *              INSTALL_FAILED}, {@link State#INSTALLED INSTALLED}
+ *      	</td>
+ * 		</tr>
+ * 		<tr align="center">
+ * 			<td>{@link #start() Start}</td>
+ * 			<td>{@link State#INSTALLED INSTALLED}, {@link State#RESOLVED 
+ *              RESOLVED}
+ *          </td>
+ * 			<td>{@link State#INSTALLED INSTALLED}, {@link State#RESOLVING
+ *              RESOLVING}, {@link State#RESOLVED RESOLVED}, {@link
+ *              State#STARTING STARTING}, {@link State#ACTIVE ACTIVE}
+ *      	</td>
+ * 		</tr>
+ * 		<tr align="center">
+ * 			<td>{@link #stop() Stop}</td>
+ * 			<td>{@link State#ACTIVE ACTIVE}</td>
+ * 			<td>{@link State#RESOLVED RESOLVED}, {@link State#STOPPING STOPPING}
+ *      	</td>
+ * 		</tr>
+ * 		<tr align="center">
+ * 			<td>{@link #uninstall() Uninstall}</td>
+ * 			<td>{@link State#INSTALLED INSTALLED}, {@link State#RESOLVED
+ *              RESOLVED}, {@link State#ACTIVE ACTIVE}
+ *      	</td>
+ * 			<td>{@link State#UNINSTALLING UNINSTALLING}, {@link
+ *              State#UNINSTALLED UNINSTALLED}
+ *      	</td>
+ * 		</tr>
+ * </table>
+ * <p/>
+ * A subsystem archive is a ZIP file having an SSA extension and containing
+ * metadata describing the subsystem. The form of the metadata may be a
+ * subsystem or deployment manifest, as well as any content resource files. The
+ * manifests are optional and will be computed if not present. The subsystem
+ * manifest headers may be {@link #getSubsystemHeaders(Locale) retrieved} in raw
+ * or localized formats. There are three standard {@link
+ * ResourceConstants#IDENTITY_TYPE_ATTRIBUTE types} of resources that may be
+ * included in a subsystem.
+ * <ul>
+ * 		<li>{@link ResourceConstants#IDENTITY_TYPE_BUNDLE Bundle} - A bundle
+ *          that is not a fragment.
+ * 		</li>
+ * 		<li>{@link ResourceConstants#IDENTITY_TYPE_FRAGMENT Fragment} - A
+ *          fragment bundle.
+ * 		</li>
+ * 		<li>{@link SubsystemConstants#IDENTITY_TYPE_SUBSYSTEM Subsystem} - A
+ *          subsystem defined by this specification.
+ * 		</li>
+ * </ul>
+ * Resources contained by a subsystem are called {@link #getConstituents()
+ * constituents}. There are several ways a resource may become a constituent of
+ * a subsystem, at least some of which are listed below.
+ * <p/>
+ * <ul>
+ * 		<li>A resource was listed as part of the subsystem's content.
+ * 		</li>
+ * 		<li>A subsystem resource is a child of the subsystem.
+ * 		</li>
+ * 		<li>The subsystem has a provision policy of accept transitive.
+ * 		</li>
+ * 		<li>A bundle resource was installed using the region bundle context.
+ * 		</li>
+ * 		<li>A bundle resource was installed using the bundle context of
+ *          another resource contained by the subsystem.
+ *      </li>
+ * </ul>
+ * In addition to invoking one of the install methods, a subsystem instance may
+ * be obtained through the service registry. Every installed subsystem has a
+ * corresponding service registration. A subsystem service has the following
+ * properties.
+ * <p/>
+ * <ul>
+ * 		<li>{@link SubsystemConstants#SUBSYSTEM_ID_PROPERTY ID} - Matches the ID
+ *          of the subsystem.
+ * 		</li>
+ * 		<li>{@link SubsystemConstants#SUBSYSTEM_SYMBOLICNAME_PROPERTY Symbolic
+ *          Name} - Matches the symbolic name of the subsystem.
+ *      </li>
+ * 		<li>{@link SubsystemConstants#SUBSYSTEM_VERSION_PROPERTY Version} -
+ *          Matches the version of the subsystem.
+ *      </li>
+ * 		<li>{@link SubsystemConstants#SUBSYSTEM_TYPE_PROPERTY Type} - Matches
+ *          the type of the subsystem.
+ *      </li>
+ * 		<li>{@link SubsystemConstants#SUBSYSTEM_STATE_PROPERTY State} - Matches
+ *          the state of the subsystem.
+ *      </li>
+ * </ul>
+ * Because a subsystem must be used to install other subsystems, a root
+ * subsystem is provided as a starting point and has the following
+ * characteristics. The root subsystem may only be obtained as a service.
+ * <p/>
+ * <ul>
+ * 		<li>The ID is {@code 0}.
+ * 		</li>
+ * 		<li>The symbolic name is {@code org.osgi.service.subsystem.root}.
+ * 		</li>
+ * 		<li>The version matches this specification's version.
+ * 		</li>
+ * 		<li>It has no parents.
+ * 		</li>
+ * 		<li>All existing bundles, including the system and subsystems
+ *          implementation bundles, become constituents.
+ *      </li>
+ *      <li>The type is {@code osgi.composite} with no imports or exports.
+ *      </li>
+ * 		<li>The provision policy is {@code acceptTransitive}.
+ * 		</li>
+ * </ul>
  * 
  * @ThreadSafe
  * @noimplement
  */
 public interface Subsystem {
 	/**
-	 * The states of a subsystem in the framework. These states match those of 
-	 * a Bundle and are derived using the same rules as CompositeBundles. As 
-	 * such, they are more a reflection of what content bundles are permitted 
-	 * to do rather than an aggregation of the content bundle states. 
+	 * An enumeration of the possible states of a subsystem.
+	 * <p/>
+	 * These states are a reflection of what constituent resources are permitted
+	 * to do, not an aggregation of resource states. 
 	 */
 	public static enum State {
 		/**
-		 * A subsystem is in the INSTALLING state when it is initially created.
+		 * The subsystem is in the process of installing.
+		 * <p/>
+		 * A subsystem is in the INSTALLING state when the {@link Subsystem#
+		 * install(String, InputStream) install} method of its parent is active,
+		 * and attempts are being made to install its content resources. If the
+		 * install method completes without exception, then the subsystem has
+		 * successfully installed and must move to the INSTALLED state.
+		 * Otherwise, the subsystem has failed to install and must move to the
+		 * INSTALL_FAILED state.
 		 */
 		INSTALLING,
 		/**
-		 * A subsystem is in the INSTALLED state when all resources are
-		 * successfully installed.
+		 * The subsystem is installed but not yet resolved.
+		 * <p/>
+		 * A subsystem is in the INSTALLED state when it has been installed in
+		 * a parent subsystem but is not or cannot be resolved. This state is
+		 * visible if the dependencies of the subsystem's content resources
+		 * cannot be resolved.
 		 */
 		INSTALLED,
 		/**
-		 *  A subsystem in the RESOLVING is allowed to have its content bundles 
-		 * resolved.
+		 * The subsystem failed to install.
+		 * <p/>
+		 * A subsystem is in the INSTALL_FAILED state when an unrecoverable
+		 * error occurred during installation. The subsystem is in an unusable
+		 * state but references to the subsystem object may still be available
+		 * and used for introspection.
+		 */
+		INSTALL_FAILED,
+		/**
+		 * The subsystem is in the process of resolving.
+		 * <p/>
+		 * A subsystem is in the RESOLVING state when the {@link Subsystem#
+		 * start() start} method is active, and attempts are being made to
+		 * resolve its content resources. If the resolve method completes
+		 * without exception, then the subsystem has successfully resolved and
+		 * must move to the RESOLVED state. Otherwise, the subsystem has failed
+		 * to resolve and must move to the INSTALLED state.
 		 */
 		RESOLVING,
 		/**
-		 *  A subsystem is in the RESOLVED state when all resources are 
-		 * resolved.
+		 * The subsystem is resolved and able to be started.
+		 * <p/>
+		 * A subsystem is in the RESOLVED state when all of its content
+		 * resources are resolved. Note that the subsystem is not active yet.
 		 */
 		RESOLVED,
 		/**
-		 * A subsystem is in the STARTING state when all its content bundles 
-		 * are enabled for activation.
+		 * The subsystem is in the process of starting.
+		 * <p/>
+		 * A subsystem is in the STARTING state when its {@link Subsystem#
+		 * start() start} method is active, and attempts are being made to start
+		 * its content and transitive resources. If the start method completes
+		 * without exception, then the subsystem has successfully started and
+		 * must move to the ACTIVE state. Otherwise, the subsystem has failed to
+		 * start and must move to the RESOLVED state.
 		 */
 		STARTING,
 		/**
-		 * A subsystem is in the ACTIVE state when it has reached the beginning 
-		 * start-level (for starting it's contents), and all its persistently 
-		 * started content bundles that are resolved and have had their 
-		 * start-levels met have completed, or failed, their activator start 
-		 * method.
+		 * The subsystem is now running.
+		 * <p/>
+		 * A subsystem is in the ACTIVE state when its content and transitive
+		 * resources have been successfully started and activated.
 		 */
 		ACTIVE,
 		/**
-		 *  A subsystem in the STOPPING state is in the process of taking its 
-		 * its active start level to zero, stopping all the content bundles.
+		 * The subsystem is in the process of stopping.
+		 * <p/>
+		 * A subsystem is in the STOPPING state when its {@link Subsystem#stop()
+		 * stop} method is active, and attempts are being made to stop its
+		 * content and transitive resources. When the stop method completes, the
+		 * subsystem is stopped and must move to the RESOLVED state.
 		 */
 		STOPPING,
-		UPDATING,
+		/**
+		 * The subsystem is in the process of uninstalling.
+		 * <p/>
+		 * A subsystem is in the UNINSTALLING state when its {@link Subsystem#
+		 * uninstall() uninstall} method is active, and attempts are being made
+		 * to uninstall its constituent and transitive resources. When the
+		 * uninstall method completes, the subsystem is uninstalled and must
+		 * move to the UNINSTALLED state.
+		 */
 		UNINSTALLING,
 		/**
-		 * A subsystem is in the UNINSTALLED state when all its content bundles 
-		 * and uninstalled and its system bundle context is invalidated.
+		 * The subsystem is uninstalled and may not be used.
+		 * <p/>
+		 * The UNINSTALLED state is only visible after a subsystem's constituent
+		 * and transitive resources are uninstalled. The subsystem is in an
+		 * unusable state but references to the subsystem object may still be
+		 * available and used for introspection.
 		 */
 		UNINSTALLED
 	}
 	
 	/**
-	 * Cancels the currently executing asynchronous life-cycle operation, if
-	 * any.
-	 * @throws SubsystemException - If this subsystem is not in one of the
-	 *         transitional states or the currently executing operation cannot
-	 *         be cancelled for any reason.
-	 */
-	public void cancel() throws SubsystemException;
-	
-	/**
-	 * Gets the subsystems managed by this service. This only includes the 
-	 * top-level Subsystems installed in the Framework, CoompositeBundle or 
-	 * Subsystem from which this service has been retrieved.
-	 * 
-	 * @return The Subsystems managed by this service.
-	 * @throws IllegalStateException If the subsystem is in the {@link 
-	 *         State#INSTALLING installing state} or transitioned to the {@link 
-	 *         State#UNINSTALLED uninstalled state} due to a failed 
-	 *         installation.
+	 * Returns the bundle context of the region within which this subsystem
+	 * resides.
+	 * <p/>
+	 * The bundle context offers the same perspective of any resource contained
+	 * by a subsystem within the region. It may be used, for example, to monitor
+	 * events internal to the region as well as external events visible to the
+	 * region. All subsystems within the same region have the same bundle
+	 * context. If this subsystem is in a state where the bundle context would
+	 * be invalid, null is returned.
+	 * 
+	 * @return The bundle context of the region within which this subsystem
+	 *         resides or null if this subsystem's state is in {{@link
+	 *         State#INSTALL_FAILED INSTALL_FAILED}, {@link State#UNINSTALLED
+	 *         UNINSTALLED}}.
+	 * @throws SecurityException If the caller does not have the appropriate 
+	 *         {@link SubsystemPermission}[this,CONTEXT], and the runtime
+	 *         supports permissions.
+	 */
+	public BundleContext getBundleContext();
+	
+	/**
+	 * Returns the child subsystems of this subsystem.
+	 * <p/>
+	 * The returned collection is an immutable snapshot of all subsystems that
+	 * are installed in this subsystem. The collection will be empty if no
+	 * subsystems are installed in this subsystem.
+	 * 
+	 * @return The child subsystems of this subsystem.
+	 * @throws IllegalStateException If this subsystem's state is in
+	 *         {{@link State#INSTALL_FAILED INSTALL_FAILED}, {@link
+	 *         State#UNINSTALLED UNINSTALLED}}.
 	 */
 	public Collection<Subsystem> getChildren();
 	
 	/**
-	 * Returns a snapshot of all {@code Resources} currently constituting this 
-	 * {@link Subsystem}. If this {@code Subsystem} has no {@code Resources}, 
-	 * the {@link Collection} will be empty.
-	 * 
-	 * @return A snapshot of all {@code Resources} currently constituting this
-	 *         {@code Subsystem}.
-	 * @throws IllegalStateException If the subsystem is in the {@link 
-	 *         State#INSTALLING installing state} or transitioned to the {@link 
-	 *         State#UNINSTALLED uninstalled state} due to a failed 
-	 *         installation.
+	 * Returns the headers for this subsystem's subsystem manifest.
+	 * <p/>
+	 * The returned map is unmodifiable. Each map key is a header name, and each
+	 * map value is the corresponding header value. Because header names are
+	 * case-insensitive, the methods of the map must treat them in a
+	 * case-insensitive manner. If the header name is not found, null is
+	 * returned. Both original and synthesized headers will be included.
+	 * <p/>
+	 * The header values are translated according to the specified locale. If
+	 * the specified locale is null or not supported, the raw values are
+	 * returned. If the translation for a particular header is not found, the
+	 * raw value is returned.
+	 * <p/>
+	 * This method must continue to return the headers while this subsystem is
+	 * in the {@link State#INSTALL_FAILED INSTALL_FAILED} or {@link
+	 * State#UNINSTALLED UNINSTALLED} states.
+	 * 
+	 * @param locale The locale for which translations are desired.
+	 * @return The headers for this subsystem's subsystem manifest.
+	 * @throws SecurityException If the caller does not have the appropriate 
+	 *         {@link SubsystemPermission}[this,METADATA], and the runtime
+	 *         supports permissions.
 	 */
-	public Collection<Resource> getConstituents();
+	public Map<String, String> getSubsystemHeaders(Locale locale);
 	
 	/**
-	 * Gets the headers used to define this subsystem. The headers will be 
-	 * localized using the locale returned by java.util.Locale.getDefault. This 
-	 * is equivalent to calling getHeaders(null).
+	 * Returns the location identifier of this subsystem.
+	 * <p/>
+	 * The location identifier is the {@code location} that was passed to the
+	 * {@link #install(String, InputStream) install} method of the {@link
+	 * #getParents() parent} subsystem. It is unique within the framework.
+	 * <p/>
+	 * This method must continue to return this subsystem's headers while this
+	 * subsystem is in the {@link State#INSTALL_FAILED INSTALL_FAILED} or {@link
+	 * State#UNINSTALLED UNINSTALLED} states.
 	 * 
-	 * @return The headers used to define this subsystem.
+	 * @return The location identifier of this subsystem.
 	 * @throws SecurityException If the caller does not have the appropriate 
-	 *         AdminPermission[this,METADATA] and the runtime supports 
-	 *         permissions.
-	 * @throws IllegalStateException If the subsystem is in the {@link 
-	 *         State#INSTALLING installing state} or transitioned to the {@link 
-	 *         State#UNINSTALLED uninstalled state} due to a failed 
-	 *         installation.
-	 */
-	public Map<String, String> getHeaders();
-	
-	/**
-	 * Gets the headers used to define this subsystem.
-	 * 
-	 * @param locale The locale name to be used to localize the headers. If the 
-	 *        locale is null then the locale returned by 
-	 *        java.util.Locale.getDefault is used. If the value is the empty 
-	 *        string then the returned headers are returned unlocalized. 
-	 * @return the headers used to define this subsystem, localized to the 
-	 *         specified locale.
-	 * @throws IllegalStateException If the subsystem is in the {@link 
-	 *         State#INSTALLING installing state} or transitioned to the {@link 
-	 *         State#UNINSTALLED uninstalled state} due to a failed 
-	 *         installation.
-	 */
-	public Map<String, String> getHeaders(String locale);
-	
-	/**
-	 * The location identifier used to install this subsystem through 
-	 * Subsystem.install. This identifier does not change while this subsystem 
-	 * remains installed, even after Subsystem.update. This location identifier 
-	 * is used in Subsystem.update if no other update source is specified. 
-	 * @return The string representation of the subsystem's location identifier.
+	 *         {@link SubsystemPermission}[this,METADATA], and the runtime
+	 *         supports permissions.
 	 */
 	public String getLocation();
 	
 	/**
-	 * Gets the parent Subsystem that scopes this subsystem instance.
+	 * Returns the parent subsystems of this subsystem.
+	 * <p/>
+	 * The returned collection is an immutable snapshot of all subsystems in
+	 * which this subsystem is installed. The collection will be empty for the
+	 * root subsystem; otherwise, it will contain at least one parent. Scoped
+	 * subsystems always have only one parent. Unscoped subsystems may have
+	 * multiple parents.
+	 * 
+	 * @return The parent subsystems of this subsystem.
+	 * @throws IllegalStateException If this subsystem's state is in {{@link
+	 *         State#INSTALL_FAILED INSTALL_FAILED}, {@link State#UNINSTALLED
+	 *         UNINSTALLED}}.
+	 */
+	public Collection<Subsystem> getParents();
+	
+	/**
+	 * Returns the constituent resources of this subsystem.
+	 * <p/>
+	 * The returned collection is an immutable snapshot of the constituent
+	 * resources of this subsystem. If this subsystem has no constituents,
+	 * the collection will be empty.
 	 * 
-	 * @return The Subsystem that scopes this subsystem or null if there is no 
-	 *         parent subsystem (e.g. if the outer scope is the framework).
-	 * @throws IllegalStateException If the subsystem is in the {@link 
-	 *         State#INSTALLING installing state} or transitioned to the {@link 
-	 *         State#UNINSTALLED uninstalled state} due to a failed 
-	 *         installation.
+	 * @return The constituent resources of this subsystem.
+	 * @throws IllegalStateException If this subsystem's state is in {{@link
+	 *         State#INSTALL_FAILED INSTALL_FAILED}, {@link State#UNINSTALLED
+	 *         UNINSTALLED}}.
 	 */
-	public Subsystem getParent();
+	public Collection<Resource> getConstituents();
 	
 	/**
-	 * Gets the state of the subsystem.
-	 * @return The state of the subsystem.
+	 * Returns the current state of this subsystem.
+	 * <p/>
+	 * This method must continue to return this subsystem's state while this
+	 * subsystem is in the {@link State#INSTALL_FAILED INSTALL_FAILED} or {@link
+	 * State#UNINSTALLED UNINSTALLED} states.
+	 * 
+	 * @return The current state of this subsystem.
 	 */
 	public State getState();
 	
 	/**
-	 * Gets the identifier of the subsystem. Subsystem identifiers are assigned 
-	 * when the subsystem is installed and are unique within the framework. 
-	 * @return The identifier of the subsystem.
+	 * Returns the identifier of this subsystem.
+	 * <p/>
+	 * The identifier is a monotonically increasing, non-negative integer
+	 * automatically generated at installation time and guaranteed to be unique
+	 * within the framework. The identifier of the root subsystem is zero.
+	 * <p/>
+	 * This method must continue to return this subsystem's identifier while
+	 * this subsystem is in the {@link State#INSTALL_FAILED INSTALL_FAILED} or
+	 * {@link State#UNINSTALLED UNINSTALLED} states.
+	 * 
+	 * @return The identifier of this subsystem.
 	 */
 	public long getSubsystemId();
 	
 	/**
-	 * Gets the symbolic name of this subsystem.
+	 * Returns the symbolic name of this subsystem.
+	 * <p/>
+	 * The subsystem symbolic name conforms to the same grammar rules as the
+	 * bundle symbolic name and is derived from one of the following, in order.
+	 * <ul>
+	 * 		<li>The value of the {@link SubsystemConstants#SUBSYSTEM_CONTENT
+	 *          Subsystem-Content} header, if specified.
+	 * 		</li>
+	 * 		<li>The subsystem URI if passed as the {@code location} along with
+	 *          the {@code content} to the {@link #install(String, InputStream)
+	 *          install} method.
+	 *      </li>
+	 * 		<li>Optionally generated in an implementation specific way.
+	 * 		</li>
+	 * </ul>
+	 * The combination of symbolic name and {@link #getVersion() version} is
+	 * unique within a region. The symbolic name of the root subsystem is {@code
+	 * org.osgi.service.subsystem.root}.
+	 * <p/>
+	 * This method must continue to return this subsystem's symbolic name while
+	 * this subsystem is in the {@link State#INSTALL_FAILED INSTALL_FAILED} or
+	 * {@link State#UNINSTALLED UNINSTALLED} states.
 	 * 
 	 * @return The symbolic name of this subsystem.
-	 * @throws IllegalStateException If the subsystem is in the {@link 
-	 *         State#INSTALLING installing state} or transitioned to the {@link 
-	 *         State#UNINSTALLED uninstalled state} due to a failed 
-	 *         installation.
 	 */
 	public String getSymbolicName();
 	
 	/**
-	 * Gets the version of this subsystem.
+	 * Returns the {@link SubsystemConstants#SUBSYSTEM_TYPE type} of this
+	 * subsystem.
+	 * <p/>
+	 * The type of the root subsystem is {@link
+	 * SubsystemConstants#SUBSYSTEM_TYPE_COMPOSITE composite}. This method must
+	 * continue to return this subsystem's type while this subsystem is in the
+	 * {@link State#INSTALL_FAILED INSTALL_FAILED} or {@link State#UNINSTALLED
+	 * UNINSTALLED} states.
+	 * 
+	 * @return The type of this subsystem.
+	 */
+	public String getType();
+	
+	/**
+	 * Returns the {@link SubsystemConstants#SUBSYSTEM_VERSION version} of this
+	 * subsystem.
+	 * <p/>
+	 * The subsystem version conforms to the same grammar rules as the bundle
+	 * version and is derived from one of the following, in order.
+	 * <ul>
+	 * 		<li>The value of the {@code Subsystem-Version} header, if specified.
+	 * 		</li>
+	 * 		<li>The subsystem URI if passed as the {@code location} along with
+	 *          the {@code content} to the {@link #install(String, InputStream)
+	 *          install} method.
+	 *      </li>
+	 * 		<li>Defaults to {@code 0.0.0}.
+	 * 		</li>
+	 * </ul>
+	 * The combination of {@link #getSymbolicName() symbolic name} and version
+	 * is unique within a region. The version of the root subsystem matches this
+	 * specification's version.
+	 * <p/>
+	 * This method must continue to return this subsystem's version while this
+	 * subsystem is in the {@link State#INSTALL_FAILED INSTALL_FAILED} or {@link
+	 * State#UNINSTALLED UNINSTALLED} states.
 	 * 
 	 * @return The version of this subsystem.
-	 * @throws IllegalStateException If the subsystem is in the {@link 
-	 *         State#INSTALLING installing state} or transitioned to the {@link 
-	 *         State#UNINSTALLED uninstalled state} due to a failed 
-	 *         installation.
 	 */
 	public Version getVersion();
 	
 	/**
-	 * Install a new subsystem from the specified location identifier.
-	 * <p>
-	 * This method performs the same function as calling install(String, 
-	 * InputStream) with the specified location identifier and a null 
-	 * InputStream.
-	 * @param location The location identifier of the subsystem to be installed.
+	 * Installs a subsystem from the specified {@code location} identifier.
+	 * <p/>
+	 * This method performs the same function as calling {@link
+	 * #install(String, InputStream)} with the specified {@code location}
+	 * identifier and {@code null} as the {@code content}.
+	 * 
+	 * @param location - The location identifier of the subsystem to install.
 	 * @return The installed subsystem.
-	 * @throws SubsystemException If the subsystem could not be installed for
-	 *         any reason.
+	 * @throws IllegalStateException If this subsystem's state is in {{@link
+	 * State#INSTALLING INSTALLING}, {@link State#INSTALL_FAILED INSTALL_FAILED}
+	 * , {@link State#UNINSTALLING UNINSTALLING}, {@link State#UNINSTALLED
+	 * UNINSTALLED}}.
+	 * @throws SubsystemException If the installation failed.
 	 * @throws SecurityException If the caller does not have the appropriate 
-	 *         AdminPermission[installed subsystem,LIFECYCLE], and the Java 
-	 *         Runtime Environment supports permissions.
+	 *         {@link SubsystemPermission}[installed subsystem,LIFECYCLE], and
+	 *         the runtime supports permissions.
+	 * @see #install(String, InputStream)
 	 */
 	public Subsystem install(String location) throws SubsystemException;
 	
 	/**
-	 * Install a new subsystem from the specified InputStream object.
+	 * Installs a subsystem from the specified {@code content}.
+	 * <p/>
+	 * The specified {@code location} will be used as an identifier of the
+	 * subsystem. Every installed subsystem is uniquely identified by its
+	 * location, which is typically in the form of a URI. If the specified
+	 * {@code location} conforms to the {@code subsystem-uri} grammar, the
+	 * required symbolic name and optional version information will be used as
+	 * default values.
 	 * <p/>
-	 * If the specified InputStream is null, the InputStream must be created 
-	 * from the specified location.
+	 * If the specified {@code content} is null, a new input stream must be
+	 * created from which to read the subsystem by interpreting, in an
+	 * implementation dependent manner, the specified {@code location}. 
 	 * <p/>
-	 * The specified location identifier will be used as the identity of the 
-	 * subsystem. Every installed subsystem is uniquely identified by its 
-	 * location identifier which is typically in the form of a URL.
+	 * A subsystem installation must be persistent. That is, an installed
+	 * subsystem must remain installed across Framework and VM restarts.
 	 * <p/>
-	 * TODO: Understand whether this all change when we can install the same 
-	 * bundle multiple times.
+	 * All references to changing the state of this subsystem include both
+	 * changing the state of the subsystem object as well as the state property
+	 * of the subsystem service registration. 
 	 * <p/>
-	 * A subsystem and its contents must remain installed across Framework and 
-	 * VM restarts. The subsystem itself is installed atomically, however its 
-	 * contents are not.
+	 * Implementations should be sensitive to the potential for long running
+	 * operations and periodically check the current thread for interruption. An
+	 * interrupted thread should result in a SubsystemException with an
+	 * InterruptedException as the cause and be treated as an installation
+	 * failure.
 	 * <p/>
-	 * The following steps are required to install a subsystem:
+	 * All installation failure flows include the following, in order.
+	 * <ol>
+	 * 		<li>Uninstall all resources installed as part of this operation.
+	 *      </li>
+	 * 		<li>Change the state to INSTALL_FAILED.
+	 * 		</li>
+	 *      <li>Unregister the subsystem service.
+	 *      </li>
+	 *      <li>Uninstall the region context bundle.
+	 *      </li>
+	 *      <li>Throw a SubsystemException with the specified cause.
+	 *      </li>
+	 * </ol>
+	 * The following steps are required to install a subsystem. 
 	 * <ol>
-	 * 		<li>If there is an existing subsystem containing the same location 
-	 *          identifier as the subsystem to be installed, then the existing
-	 *          subsystem is returned.</li>
-	 * 		<li>If this is a new install, then a new Subsystem is created with 
-	 *          its id set to the next available value (ascending order).</li>
-	 * 		<li>The subsystem's state is set to INSTALLING and if EventAdmin is 
-	 *          available, an event of type INSTALLING is fired.</li>
-	 *      <li>The following installation steps are then started and performed 
-	 *          asynchronously and the new subsystem is returned to the caller.</li>
-	 * 		<li>The subsystem content is read from the input stream.</li>
-	 * 		<li>If the subsystem requires isolation (i.e. is an application or 
-	 *          a composite), then isolation is set up while the install is in 
-	 *          progress, such that none of the content bundles can be resolved.
-	 *          This isolation is not changed until the subsystem is explicitly 
-	 *          requested to resolve (i.e. as a result of a Subsystem.start() 
-	 *          operation).</li>
-	 * 		<li>If the subsystem does not include a deployment manifest, then 
-	 *          the subsystem runtime must calculate one.</li>
-	 * 		<li>The resources identified in the deployment manifest are 
-	 *          installed into the framework.  All content resources are 
-	 *          installed into the Subsystem, whereas transitive dependencies 
-	 *          are installed into an ancestor subsystem. If any resources fail 
-	 *          to install, then the entire installation is failed. Transitive 
-	 *          resources are free to resolve and start independent of the 
-	 *          subsystem they were installed for.</li>
-	 * 		<li>The subsystem's state is set to INSTALLED and if EventAdmin is 
-	 *          available an INSTALLED event is fired.</li>
+	 * <li>If an installed subsystem with the specified {@code location}
+	 *     identifier already exists, return the installed subsystem.
+	 * </li>
+	 * <li>Read the specified {@code content} in order to determine the symbolic
+	 *     name, version, and type of the installing subsystem. If an error
+	 *     occurs while reading the content, an installation failure results.
+	 * </li>
+	 * <li>If an installed subsystem with the same symbolic name and version
+	 *     already exists within this subsystem's region, complete the
+	 *     installation with one of the following.
+	 *     <ul>
+	 *     <li>If the installing and installed subsystems' types are not equal,
+	 *         an installation failure results.
+	 *     </li>
+	 *     <li>If the installing and installed subsystems' types are equal, and
+	 *         the installed subsystem is already a child of this subsystem,
+	 *         return the installed subsystem.
+	 *     </li>
+	 *     <li>If the installing and installed subsystems' types are equal, and
+	 *         the installed subsystem is not already a child of this subsystem,
+	 *         add the installed subsystem as a child of this subsystem,
+	 *         increment the installed subsystem's reference count by one, and
+	 *         return the installed subsystem.
+	 *     </li>
+	 *     </ul>
+	 * </li>
+	 * <li>Create a new subsystem based on the specified {@code location} and
+	 *     {@code content}.
+	 * </li>
+	 * <li>If the subsystem is scoped, install and activate a new region context
+	 *     bundle.
+	 * </li>
+	 * <li>Change the state to INSTALLING and register a new subsystem service.
+	 * </li>
+	 * <li>{@link Repository Discover} the subsystem's content resources. If any
+	 *     mandatory resource is missing, an installation failure results.
+	 * </li>
+	 * <li>{@link Resolver Discover} the transitive resources required by the
+	 *     content resources. If any transitive resource is missing, an
+	 *     installation failure results.
+	 * </li>
+	 * <li>{@link ResolverHook Disable} runtime resolution for the resources.
+	 * </li>
+	 * <li>For each resource, increment the reference count by one. If the
+	 *     reference count is one, install the resource. All transitive
+	 *     resources must be installed before any content resource. If an error
+	 *     occurs while installing a resource, an install failure results with
+	 *     that error as the cause.
+	 * </li>
+	 * <li>If the subsystem is scoped, enable the import sharing policy.
+	 * </li>
+	 * <li>Enable runtime resolution for the resources.
+	 * </li>
+	 * <li>Change the state of the subsystem to INSTALLED.
+	 * </li>
+	 * <li>Return the new subsystem.
+	 * </li>
 	 * </ol>
-	 * @param location The location identifier of the subsystem to be installed.
-	 * @param content The InputStream from where the subsystem is to be 
-	 *        installed or null if the location is to be used to create the 
-	 *        InputStream.
+	 * 
+	 * @param location - The location identifier of the subsystem to be
+	 *        installed.
+	 * @param content - The input stream from which this subsystem will be read
+	 *        or null to indicate the input stream must be created from the
+	 *        specified location identifier. The input stream will always be
+	 *        closed when this method completes, even if an exception is thrown.
 	 * @return The installed subsystem.
-	 * @throws SubsystemException If the subsystem could not be installed for
-	 *         any reason.
+	 * @throws IllegalStateException If this subsystem's state is in {INSTALLING
+	 *         , INSTALL_FAILED, UNINSTALLING, UNINSTALLED}.
+	 * @throws SubsystemException If the installation failed.
 	 * @throws SecurityException If the caller does not have the appropriate 
-	 *         AdminPermission[installed subsystem,LIFECYCLE], and the Java 
-	 *         Runtime Environment supports permissions.
+	 *         SubsystemPermission[installed subsystem,LIFECYCLE], and the runtime
+	 *         supports permissions.
 	 */
 	public Subsystem install(String location, InputStream content) throws SubsystemException;
 	
 	/**
-	 * Starts the subsystem. The subsystem is started according to the rules 
-	 * defined for Bundles and the content bundles are enabled for activation. 
-	 * @throws SubsystemException If this subsystem could not be started. 
-	 * @throws IllegalStateException If this subsystem has been uninstalled. 
+	 * Starts this subsystem.
+	 * <p/>
+	 * The following table shows which actions are associated with each state.
+	 * An action of Wait means this method will block until a state transition
+	 * occurs, upon which the new state will be evaluated in order to
+	 * determine how to proceed. An action of Return means this method returns
+	 * immediately without taking any other action.
+	 * <p/>
+	 * <table border="1">
+	 * 		<tr>
+	 * 			<th>State</td>
+	 * 			<th>Action</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>INSTALLING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>INSTALLED</td>
+	 * 			<td>Resolve, Start</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>INSTALL_FAILED</td>
+	 * 			<td>IllegalStateException</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>RESOLVING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>RESOLVED</td>
+	 * 			<td>If this subsystem is in the process of being<br/>
+	 *              started, Wait. Otherwise, Uninstall.</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>STARTING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>ACTIVE</td>
+	 * 			<td>Return</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>STOPPING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>UNINSTALLING</td>
+	 * 			<td>IllegalStateException</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>UNINSTALLED</td>
+	 * 			<td>IllegalStateException</td>
+	 * 		</tr>
+	 * </table>
+	 * <p/>
+	 * All references to changing the state of this subsystem include both
+	 * changing the state of the subsystem object as well as the state property
+	 * of the subsystem service registration.
+	 * <p/>
+	 * Implementations should be sensitive to the potential for long running
+	 * operations and periodically check the current thread for interruption. An
+	 * interrupted thread should be treated as a start failure with an
+	 * InterruptedException as the cause.
+	 * <p/>
+	 * All start failure flows include the following, in order.
+	 * <ol>
+	 * 		<li>Stop all resources that were started as part of this operation.
+	 *      </li>
+	 *      <li>Disable the export sharing policy.
+	 *      </li>
+	 *      <li>Change the state to either INSTALLED or RESOLVED.
+	 * 		</li>
+	 * 		<li>Throw a SubsystemException with the specified cause.
+	 *      </li>
+	 * </ol>
+	 * <p/>
+	 * A subsystem must be persistently started. That is, a started subsystem
+	 * must be restarted across Framework and VM restarts, even if a start
+	 * failure occurs.
+	 * <p/>
+	 * The following steps are required to start this subsystem.
+	 * <ol>
+	 * 		<li>If this subsystem is in the RESOLVED state, proceed to step 5.
+	 * 		</li>
+	 *      <li>Change the state to RESOLVING.
+	 *      </li>
+	 *      <li>Resolve the content resources. A resolution failure results in
+	 *          a start failure with a state of INSTALLED.
+	 *      </li>
+	 *      <li>Change the state to RESOLVED.
+	 *      </li>
+	 *      <li>If this subsystem is scoped, enable the export sharing policy.
+	 * 		</li>
+	 * 		<li>Change the state to STARTING.
+	 *      </li>
+	 *      <li>For each eligible resource, increment the activation count by
+	 *          one. If the activation count is one, start the resource. All
+	 *          transitive resources must be started before any content
+	 *          resource, and content resources must be started according to the
+	 *          specified {@link SubsystemConstants#START_LEVEL_DIRECTIVE start
+	 *          order}. If an error occurs while starting a resource, a start
+	 *          failure results with that error as the cause.
+	 *      </li>
+	 *      <li>Change the state to ACTIVE.
+	 * 		</li>
+	 * </ol>
+	 * <p/> 
+	 * @throws SubsystemException If this subsystem fails to start. 
+	 * @throws IllegalStateException If this subsystem's state is in
+	 *         {INSTALL_FAILED, UNINSTALLING, or UNINSTALLED}, or if the state
+	 *         of at least one of this subsystem's parents is not in {STARTING,
+	 *         ACTIVE}.
 	 * @throws SecurityException If the caller does not have the appropriate 
-	 *         AdminPermission[this,EXECUTE] and the runtime supports 
+	 *         SubsystemPermission[this,EXECUTE], and the runtime supports 
 	 *         permissions.
 	 */
 	public void start() throws SubsystemException;
 	
 	/**
-	 * Stops the subsystem. The subsystem is stopped according to the rules 
-	 * defined for Bundles and the content bundles are disabled for activation 
-	 * and stopped.
-	 * @throws SubsystemException If an internal exception is thrown while 
-	 *         stopping the subsystem (e.g. a BundleException from Bundle.stop). 
-	 * @throws IllegalStateException - If this subsystem has been uninstalled. 
-	 * @throws SecurityException - If the caller does not have the appropriate 
-	 *         AdminPermission[this,EXECUTE] and the runtime supports 
+	 * Stops this subsystem.
+	 * <p/>
+	 * The following table shows which actions are associated with each state.
+	 * An action of Wait means this method will block until a state transition
+	 * occurs, upon which the new state will be evaluated in order to
+	 * determine how to proceed. An action of Return means this method returns
+	 * immediately without taking any other action.
+	 * <p/>
+	 * <table border="1"">
+	 * 		<tr>
+	 * 			<th>State</td>
+	 * 			<th>Action</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>INSTALLING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>INSTALLED</td>
+	 * 			<td>Return</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>INSTALL_FAILED</td>
+	 * 			<td>IllegalStateException</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>RESOLVING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>RESOLVED</td>
+	 * 			<td>If this subsystem is in the process of being<br/>
+	 *              started, Wait. Otherwise, Return.</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>STARTING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>ACTIVE</td>
+	 * 			<td>Stop</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>STOPPING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>UNINSTALLING</td>
+	 * 			<td>IllegalStateException</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>UNINSTALLED</td>
+	 * 			<td>IllegalStateException</td>
+	 * 		</tr>
+	 * </table>
+	 * <p/>
+	 * Implementations should be sensitive to the potential for long running
+	 * operations and periodically check the current thread for interruption, in
+	 * which case a SubsystemException with an InterruptedException as the cause
+	 * should be thrown. If an interruption occurs while waiting, this method
+	 * should terminate immediately. Once the transition to the STOPPING
+	 * state has occurred, however, this method must not terminate due to an
+	 * interruption until the stop process has completed.
+	 * <p/>
+	 * A subsystem must be persistently stopped. That is, a stopped subsystem
+	 * must remain stopped across Framework and VM restarts.
+	 * <p/>
+	 * All references to changing the state of this subsystem include both
+	 * changing the state of the subsystem object as well as the state property
+	 * of the subsystem service registration.
+	 * <p/>
+	 * The following steps are required to stop this subsystem.
+	 * <ol>
+	 * 		<li>Change the state to STOPPING.
+	 * 		</li>
+	 * 		<li>For each eligible resource, decrement the activation count by
+	 *          one. If the activation count is zero, stop the resource. All
+	 *          content resources must be stopped before any transitive
+	 *          resource, and content resources must be stopped in reverse
+	 *          {@link SubsystemConstants#START_LEVEL_DIRECTIVE start order}. If
+	 *          an error occurs while stopping a resource, a stop failure
+	 *          results with that error as the cause.
+	 *      </li>
+	 *      <li>Change the state to RESOLVED.
+	 *      </li>
+	 * </ol>
+	 * With regard to error handling, once this subsystem has transitioned to
+	 * the STOPPING state, every part of each step above must be attempted.
+	 * Errors subsequent to the first should be logged. Once the stop process
+	 * has completed, a SubsystemException must be thrown with the initial error
+	 * as the specified cause.
+	 * <p/>
+	 * @throws SubsystemException If this subsystem fails to stop cleanly.
+	 * @throws IllegalStateException If this subsystem's state is in
+	 *         {INSTALL_FAILED, UNINSTALLING, or UNINSTALLED}.
+	 * @throws SecurityException If the caller does not have the appropriate 
+	 *         SubsystemPermission[this,EXECUTE], and the runtime supports 
 	 *         permissions.
 	 */
 	public void stop() throws SubsystemException;
 	
 	/**
-	 * Uninstall the given subsystem.
+	 * Uninstalls this subsystem.
+	 * <p/>
+	 * The following table shows which actions are associated with each state.
+	 * An action of Wait means this method will block until a state transition
+	 * occurs, upon which the new state will be evaluated in order to
+	 * determine how to proceed. An action of Return means this method returns
+	 * immediately without taking any other action.
+	 * <p/>
+	 * <table border="1">
+	 * 		<tr>
+	 * 			<th>State</td>
+	 * 			<th>Action</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>INSTALLING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>INSTALLED</td>
+	 * 			<td>Uninstall</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>INSTALL_FAILED</td>
+	 * 			<td>IllegalStateException</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>RESOLVING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>RESOLVED</td>
+	 * 			<td>If this subsystem is in the process of being<br/>
+	 *              started, Wait. Otherwise, Uninstall.</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>STARTING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>ACTIVE</td>
+	 * 			<td>Stop, Uninstall</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>STOPPING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>UNINSTALLING</td>
+	 * 			<td>Wait</td>
+	 * 		</tr>
+	 * 		<tr align="center">
+	 * 			<td>UNINSTALLED</td>
+	 * 			<td>Return</td>
+	 * 		</tr>
+	 * </table>
 	 * <p/>
-	 * This method causes the Framework to notify other bundles and subsystems 
-	 * that this subsystem is being uninstalled, and then puts this subsystem 
-	 * into the UNINSTALLED state. The Framework must remove any resources 
-	 * related to this subsystem that it is able to remove. If this subsystem 
-	 * has exported any packages, the Framework must continue to make these 
-	 * packages available to their importing bundles or subsystems until the 
-	 * org.osgi.service.packageadmin.PackageAdmin.refreshPackages(
-	 * org.osgi.framework.Bundle[]) method has been called or the Framework is 
-	 * relaunched. The following steps are required to uninstall a subsystem:
+	 * Implementations should be sensitive to the potential for long running
+	 * operations and periodically check the current thread for interruption, in
+	 * which case a SubsystemException with an InterruptedException as the cause
+	 * should be thrown. If an interruption occurs while waiting, this method
+	 * should terminate immediately. Once the transition to the UNINSTALLING
+	 * state has occurred, however, this method must not terminate due to an
+	 * interruption until the uninstall process has completed.
+	 * <p/>
+	 * All references to changing the state of this subsystem include both
+	 * changing the state of the subsystem object as well as the state property
+	 * of the subsystem service registration.
+	 * <p/>
+	 * The following steps are required to uninstall this subsystem.
 	 * <ol>
-	 * 		<li>If this subsystem's state is UNINSTALLED then an 
-	 *          IllegalStateException is thrown.</li>
-	 * 		<li>If this subsystem's state is ACTIVE, STARTING or STOPPING, this 
-	 *          subsystem is stopped as described in the Subsystem.stop() 
-	 *          method. If Subsystem.stop() throws an exception, a Framework 
-	 *          event of type FrameworkEvent.ERROR is fired containing the 
-	 *          exception.</li>
-	 * 		<li>This subsystem's state is set to UNINSTALLED.</li>
-	 * 		<li>A subsystem event of type SubsystemEvent.UNINSTALLED is fired.</li>
-	 * 		<li>This subsystem and any persistent storage area provided for this 
-	 *          subsystem by the Framework are removed.</li>
+	 * 		<li>Change the state to UNINSTALLING.
+	 * 		</li>
+	 * 		<li>For each resource, decrement the reference count by one. If the
+	 * 			reference count is zero, uninstall the resource. All content
+	 * 			resources must be uninstalled before any transitive resource. If
+	 *          an error occurs while uninstalling a resource, an uninstall
+	 *          failure results with that error as the cause.
+	 *      </li>
+	 *      <li>Change the state to UNINSTALLED.
+	 *      </li>
+	 *      <li>Unregister the subsystem service.
+	 *      </li>
+	 *      <li>Uninstall the region context bundle.
+	 *      </li>
 	 * </ol>
-	 * @throws SubsystemException If the uninstall failed.
-	 * @throws IllegalStateException If the subsystem is already in the 
-	 *         UNISTALLED state.
+	 * With regard to error handling, once this subsystem has transitioned to
+	 * the UNINSTALLING state, every part of each step above must be attempted.
+	 * Errors subsequent to the first should be logged. Once the uninstall
+	 * process has completed, a SubsystemException must be thrown with the
+	 * specified cause.
+	 * <p/>
+	 * @throws SubsystemException If this subsystem fails to uninstall cleanly.
+	 * @throws IllegalStateException If this subsystem's state is in
+	 *         {INSTALL_FAILED}. 
 	 * @throws SecurityException If the caller does not have the appropriate 
-	 *         AdminPermission[this,LIFECYCLE] and the Java Runtime Environment 
-	 *         supports permissions.
+	 *         SubsystemPermission[this,LIFECYCLE], and the runtime supports
+	 *         permissions.
 	 */
 	public void uninstall() throws SubsystemException;
 }

Modified: aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/SubsystemConstants.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/SubsystemConstants.java?rev=1241900&r1=1241899&r2=1241900&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/SubsystemConstants.java (original)
+++ aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/SubsystemConstants.java Wed Feb  8 13:54:41 2012
@@ -15,18 +15,12 @@
  */
 package org.osgi.service.subsystem;
 
-import org.osgi.framework.Constants;
-import org.osgi.framework.Version;
 import org.osgi.framework.resource.ResourceConstants;
 
 /**
  * Defines the constants used by subsystems.
  */
 public class SubsystemConstants {
-	private SubsystemConstants() {
-		throw new AssertionError("This class is not designed to be instantiated");
-	}
-	
 	/**
 	 * Manifest header identifying the resources to be deployed.
 	 */
@@ -38,150 +32,37 @@ public class SubsystemConstants {
 	public static final String DEPLOYED_VERSION_ATTRIBUTE = "deployed-version";
 
 	/**
-	 * Key for the event property that holds the subsystem id.
-	 */
-	public static final String EVENT_SUBSYSTEM_ID = "subsystem.id";
-	
-	/**
-	 * Key for the event property that holds the subsystem location.
-	 */
-	public static final String EVENT_SUBSYSTEM_LOCATION = "subsystem.location";
-	
-	/**
-	 * Key for the event property that holds the subsystem state.
+	 * An identity {@link ResourceConstants#IDENTITY_TYPE_ATTRIBUTE type} 
+	 * attribute value identifying a subsystem resource type.
+	 * It is defined to be &quot;osgi.subsystem.&quot;.
 	 */
-	public static final String EVENT_SUBYSTEM_STATE = "subsystem.state";
-	
-	/**
-	 * Key for the event property that holds the subsystem symbolic name.
-	 */
-	public static final String EVENT_SUBSYSTEM_SYMBOLICNAME = "subsystem.symbolicname";
+	public static final String IDENTITY_TYPE_SUBSYSTEM = "osgi.subsystem";
 	
 	/**
-	 * Key for the event property that holds the subsystem version.
+	 * Manifest header used to express a preference for particular resources to
+	 * satisfy implicit package dependencies.
 	 */
-	public static final String EVENT_SUBSYSTEM_VERSION = "subsystem.version";
+	public static final String PREFERRED_PROVIDER = "Preferred-Provider";
 	
 	/**
-	 * The topic for subsystem event admin events.
+	 * A value for the {@link #PROVISION_POLICY_DIRECTIVE provision-policy}
+	 * directive indicating the subsystem accepts transitive resources. The root
+	 * subsystem has this provision policy.
 	 */
-	public static final String EVENT_TOPIC = "org/osgi/service/Subsystem/";
+	public static final String PROVISION_POLICY_ACCEPT_TRANSITIVE = "acceptTransitive";
 	
 	/**
-	 * The topic for subsystem internal event admin events.
-	 */
-	public static final String EVENT_TOPIC_INTERNALS = "org/osgi/service/SubsystemInternals/";
-
-	/**
-	 * The subsystem lifecycle event types that can be produced by a subsystem. 
-	 * See ? and Subsystem for details on the circumstances under which these 
-	 * events are fired.
-	 */
-	public static enum EVENT_TYPE {
-		/**
-		 * Event type used to indicate a subsystem is installing.
-		 */
-		INSTALLING,
-		/**
-		 * Event type used to indicate a subsystem has been installed.
-		 */
-		INSTALLED,
-		/**
-		 * Event type used to indicate a subsystem is resolving.
-		 */
-		RESOLVING,
-		/**
-		 * Event type used to indicate a subsystem has been resolved.
-		 */
-		RESOLVED,
-		/**
-		 * Event type used to indicate a subsystem is starting.
-		 */
-		STARTING,
-		/**
-		 * Event type used to indicate a subsystem has been started.
-		 */
-		STARTED,
-		/**
-		 * Event type used to indicate a subsystem is stopping.
-		 */
-		STOPPING,
-		/**
-		 * Event type used to indicate a subsystem has been stopped.
-		 */
-		STOPPED,
-		/**
-		 * Event type used to indicate a subsystem is updating.
-		 */
-		UPDATING,
-		/**
-		 * Event type used to indicate a subsystem has been updated.
-		 */
-		UPDATED,
-		/**
-		 * Event type used to indicate a subsystem is uninstalling.
-		 */
-		UNINSTALLING,
-		/**
-		 * Event type used to indicate a subsystem has been uninstalled.
-		 */
-		UNINSTALLED,
-		/**
-		 * Event type used to indicate that a subsystem operation is being 
-		 * cancelled.
-		 */
-		CANCELING,
-		/**
-		 * Event type used to indicate that the operations was cancelled (e.g. 
-		 * an install was cancelled).
-		 */
-		CANCELED,
-		/**
-		 * Event type used to indicate that the operation failed (e.g. an 
-		 * exception was thrown during installation).
-		 */
-		FAILED
-	}
-	
-	/**
-	 * Manifest header identifying packages offered for export.
-	 * 
-	 * @see Constants#EXPORT_PACKAGE
-	 */
-	public static final String EXPORT_PACKAGE = Constants.EXPORT_PACKAGE;
-	
-	/**
-	 * Manifest header attribute identifying the resource type. The default 
-	 * value is {@link #IDENTITY_TYPE_BUNDLE}.
-	 * 
-	 * @see ResourceConstants#IDENTITY_TYPE_ATTRIBUTE
-	 */
-	public static final String IDENTITY_TYPE_ATTRIBUTE = ResourceConstants.IDENTITY_TYPE_ATTRIBUTE;
-
-	/**
-	 * Manifest header attribute value identifying a bundle resource type.
-	 * 
-	 * @see ResourceConstants#IDENTITY_TYPE_BUNDLE
-	 */
-	public static final String IDENTITY_TYPE_BUNDLE = ResourceConstants.IDENTITY_TYPE_BUNDLE;
-
-	/**
-	 * Manifest header attribute value identifying a subsystem resource type.
-	 */
-	public static final String IDENTITY_TYPE_SUBSYSTEM = "osgi.subsystem";
-
-	/**
-	 * Manifest header identifying packages required for import.
-	 * 
-	 * @see Constants#IMPORT_PACKAGE
+	 * Manifest header directive identifying the provision policy. The default 
+	 * value is {@link #PROVISION_POLICY_REJECT_TRANSITIVE rejectTransitive}.
 	 */
-	public static final String IMPORT_PACKAGE = Constants.IMPORT_PACKAGE;
+	public static final String PROVISION_POLICY_DIRECTIVE = "provision-policy";
 	
 	/**
-	 * Manifest header used to express a preference for particular resources to
-	 * satisfy implicit package dependencies.
+	 * A value for the {@link #PROVISION_POLICY_DIRECTIVE provision-policy}
+	 * directive indicating the subsystem does not accept transitive resources.
+	 * This is the default value.
 	 */
-	public static final String PREFERRED_PROVIDER = "Preferred-Provider";
+	public static final String PROVISION_POLICY_REJECT_TRANSITIVE = "rejectTransitive";
 
 	/**
 	 * Manifest header identifying the resources to be deployed to satisfy the 
@@ -190,33 +71,6 @@ public class SubsystemConstants {
 	public static final String PROVISION_RESOURCE = "Provision-Resource";
 
 	/**
-	 * Manifest header identifying symbolic names of required bundles. 
-	 */
-	public static final String REQUIRE_BUNDLE = Constants.REQUIRE_BUNDLE;
-
-	/**
-	 * Manifest header directive identifying the resolution type. The default 
-	 * value is {@link #RESOLUTION_MANDATORY}.
-	 * 
-	 * @see Constants#RESOLUTION_DIRECTIVE
-	 */
-	public static final String RESOLUTION_DIRECTIVE = Constants.RESOLUTION_DIRECTIVE;
-	
-	/**
-	 * Manifest header directive value identifying a mandatory resolution type.
-	 * 
-	 * @see Constants#RESOLUTION_MANDATORY
-	 */
-	public static final String RESOLUTION_MANDATORY = Constants.RESOLUTION_MANDATORY;
-	
-	/**
-	 * Manifest header directive value identifying an optional resolution type.
-	 * 
-	 * @see Constants#RESOLUTION_OPTIONAL
-	 */
-	public static final String RESOLUTION_OPTIONAL = Constants.RESOLUTION_OPTIONAL;
-	
-	/**
 	 * Manifest header directive identifying the start level.
 	 */
 	public static final String START_LEVEL_DIRECTIVE = "start-level";
@@ -237,6 +91,13 @@ public class SubsystemConstants {
 	public static final String SUBSYSTEM_EXPORTSERVICE = "Subsystem-ExportService";
 	
 	/**
+	 * The name of the service property for the {@link 
+	 * Subsystem#getSubsystemId() subsystem ID}.
+	 * It is defined to be &quot;subsystem.id&quot;.
+	 */
+	public static final String SUBSYSTEM_ID_PROPERTY = "subsystem.id";
+	
+	/**
 	 * Manifest header identifying services required for import.
 	 */
 	public static final String SUBSYSTEM_IMPORTSERVICE = "Subsystem-ImportService";
@@ -248,32 +109,56 @@ public class SubsystemConstants {
 	public static final String SUBSYSTEM_MANIFESTVERSION = "Subsystem-ManifestVersion";
 	
 	/**
-	 * Human readable application name.
+	 * Human readable subsystem name.
 	 */
 	public static final String SUBSYSTEM_NAME = "Subsystem-Name";
 	
 	/**
+	 * The name of the service property for the subsystem {@link 
+	 * Subsystem#getState() state}.
+	 * It is defined to be &quot;subsystem.state&quot;.
+	 */
+	public static final String SUBSYSTEM_STATE_PROPERTY = "subsystem.state";
+	
+	/**
 	 * Symbolic name for the application. Must be present.
 	 */
 	public static final String SUBSYSTEM_SYMBOLICNAME = "Subsystem-SymbolicName";
 	
 	/**
+	 * The name of the service property for the subsystem {@link 
+	 * Subsystem#getSymbolicName() symbolic name}.
+	 * It is defined to be &quot;subsystem.symbolicname&quot;.
+	 */
+	public static final String SUBSYSTEM_SYMBOLICNAME_PROPERTY = "subsystem.symbolicname";
+	
+	/**
 	 * Manifest header identifying the subsystem type.
 	 */
 	public static final String SUBSYSTEM_TYPE = "Subsystem-Type";
 	
 	/**
+	 * The name of the service property for the subsystem {@link #SUBSYSTEM_TYPE
+	 * type}.
+	 * It is defined to be &quot;subsystem.type&quot;.
+	 */
+	public static final String SUBSYSTEM_TYPE_PROPERTY = "subsystem.type";
+	
+	/**
 	 * Manifest header value identifying an application subsystem.
+	 * It is defined to be &quot;osgi.application&quot;.
 	 */
 	public static final String SUBSYSTEM_TYPE_APPLICATION = "osgi.application";
 	
 	/**
 	 * Manifest header value identifying a composite subsystem.
+	 * It is defined to be &quot;osgi.composite&quot;.
 	 */
 	public static final String SUBSYSTEM_TYPE_COMPOSITE = "osgi.composite";
 	
 	/**
 	 * Manifest header value identifying a feature subsystem.
+	 * It is defined to be &quot;osgi.feature&quot;.
 	 */
 	public static final String SUBSYSTEM_TYPE_FEATURE = "osgi.feature";
 	
@@ -283,8 +168,8 @@ public class SubsystemConstants {
 	public static final String SUBSYSTEM_VERSION = "Subsystem-Version";
 	
 	/**
-	 * Manifest header attribute indicating a version or version range. The 
-	 * default value is {@link Version#emptyVersion}.
+	 * The name of the service property for the subsystem {@link 
+	 * Subsystem#getVersion() version}.
 	 */
-	public static final String VERSION_ATTRIBUTE = Constants.VERSION_ATTRIBUTE;
+	public static final String SUBSYSTEM_VERSION_PROPERTY = "subsystem.version";
 }

Added: aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/SubsystemPermission.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/SubsystemPermission.java?rev=1241900&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/SubsystemPermission.java (added)
+++ aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/SubsystemPermission.java Wed Feb  8 13:54:41 2012
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2011). 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.subsystem;
+
+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.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * A bundle's authority to perform specific privileged administrative operations
+ * on or to get sensitive information about a subsystem. The actions for this
+ * permission are:
+ *
+ * <pre>
+ *  Action               Methods
+ *  context              Subsystem.getBundleContext
+ *  execute              Subsystem.start
+ *                       Subsystem.stop
+ *  lifecycle            Subsystem.install
+ *                       Subsystem.uninstall
+ *  metadata             Subsystem.getHeaders
+ *                       Subsystem.getLocation
+ * </pre>
+ *
+ * <p>
+ * The name of this permission is a filter expression. The filter gives access
+ * to the following attributes:
+ * <ul>
+ * <li>location - The location of a subsystem.</li>
+ * <li>id - The subsystem ID of the designated subsystem.</li>
+ * <li>name - The symbolic name of a subsystem.</li>
+ * </ul>
+ * Filter attribute names are processed in a case sensitive manner.
+ *
+ * @ThreadSafe
+ * @version $Id: 54ab1f9f1c80794d27dcf8c72e8720a4c582d229 $
+ */
+
+public final class SubsystemPermission extends BasicPermission {
+	static final long						serialVersionUID			= 307051004521261705L;
+
+	/**
+	 * The action string {@code execute}.
+	 */
+	public final static String	EXECUTE						= "execute";
+	/**
+	 * The action string {@code lifecycle}.
+	 */
+	public final static String	LIFECYCLE					= "lifecycle";
+	/**
+	 * The action string {@code metadata}.
+	 */
+	public final static String	METADATA					= "metadata";
+	/**
+	 * The action string {@code context}.
+	 */
+	public final static String	CONTEXT						= "context";
+
+	private final static int	ACTION_EXECUTE				= 0x00000002;
+	private final static int	ACTION_LIFECYCLE			= 0x00000004;
+	private final static int	ACTION_METADATA				= 0x00000010;
+	private final static int	ACTION_CONTEXT				= 0x00000400;
+	private final static int	ACTION_ALL					= ACTION_EXECUTE
+																	| ACTION_LIFECYCLE
+																	| ACTION_METADATA
+																	| ACTION_CONTEXT;
+	final static int						ACTION_NONE					= 0;
+
+	/**
+	 * The actions in canonical form.
+	 *
+	 * @serial
+	 */
+	private volatile String		actions						= null;
+
+	/**
+	 * The actions mask.
+	 */
+	transient int							action_mask;
+
+	/**
+	 * If this SubsystemPermission was constructed with a filter, this holds a
+	 * Filter matching object used to evaluate the filter in implies.
+	 */
+	transient Filter						filter;
+
+	/**
+	 * The subsystem governed by this SubsystemPermission - only used if filter == null
+	 */
+	transient final Subsystem					subsystem;
+
+	/**
+	 * This map 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 Map<String, Object>	properties;
+
+	/**
+	 * ThreadLocal used to determine if we have recursively called
+	 * getProperties.
+	 */
+	private static final ThreadLocal<Subsystem>	recurse						= new ThreadLocal<Subsystem>();
+
+	/**
+	 * Create a new SubsystemPermission.
+	 *
+	 * This constructor must only be used to create a permission that is going
+	 * to be checked.
+	 * <p>
+	 * Examples:
+	 *
+	 * <pre>
+	 * (name=com.acme.*)(location=http://www.acme.com/subsystems/*))
+	 * (id&gt;=1)
+	 * </pre>
+	 *
+	 * @param filter A filter expression that can use, location, id, and name
+	 *        keys. Filter attribute names are processed in a case sensitive
+	 *        manner. A special value of {@code "*"} can be used to match all
+	 *        subsystems.
+	 * @param actions {@code execute}, {@code lifecycle}, {@code metadata}, or
+	 *        {@code context}.
+	 * @throws IllegalArgumentException If the filter has an invalid syntax.
+	 */
+	public SubsystemPermission(String filter, String actions) {
+		this(parseFilter(filter), parseActions(actions));
+	}
+
+	/**
+	 * Creates a new requested {@code SubsystemPermission} object to be used by the
+	 * code that must perform {@code checkPermission}. {@code SubsystemPermission}
+	 * objects created with this constructor cannot be added to an
+	 * {@code SubsystemPermission} permission collection.
+	 *
+	 * @param subsystem A subsystem.
+	 * @param actions {@code execute}, {@code lifecycle}, {@code metadata}, or
+	 *        {@code context}.
+	 */
+	public SubsystemPermission(Subsystem subsystem, String actions) {
+		super(createName(subsystem));
+		setTransients(null, parseActions(actions));
+		this.subsystem = subsystem;
+	}
+
+	/**
+	 * Create a permission name from a Subsystem
+	 *
+	 * @param subsystem Subsystem to use to create permission name.
+	 * @return permission name.
+	 */
+	private static String createName(Subsystem subsystem) {
+		if (subsystem == null) {
+			throw new IllegalArgumentException("subsystem must not be null");
+		}
+		StringBuffer sb = new StringBuffer("(id=");
+		sb.append(subsystem.getSubsystemId());
+		sb.append(")");
+		return sb.toString();
+	}
+
+	/**
+	 * Package private constructor used by SubsystemPermissionCollection.
+	 *
+	 * @param filter name filter or {@code null} for wildcard.
+	 * @param mask action mask
+	 */
+	SubsystemPermission(Filter filter, int mask) {
+		super((filter == null) ? "*" : filter.toString());
+		setTransients(filter, mask);
+		this.subsystem = null;
+	}
+
+	/**
+	 * Called by constructors and when deserialized.
+	 *
+	 * @param filter Permission's filter or {@code null} for wildcard.
+	 * @param mask action mask
+	 */
+	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;
+	}
+
+	/**
+	 * Parse action string into action mask.
+	 *
+	 * @param actions Action string.
+	 * @return action mask.
+	 */
+	private static int parseActions(String actions) {
+		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 >= 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;
+
+				}
+				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] == '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] == '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 {
+							// 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 subsystem. If the specified filterString equals
+	 *         "*", then {@code null} is returned to indicate a wildcard.
+	 * @throws IllegalArgumentException If the filter syntax is invalid.
+	 */
+	private static Filter parseFilter(String filterString) {
+		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;
+		}
+	}
+
+	/**
+	 * Determines if the specified permission is implied by this object. This
+	 * method throws an exception if the specified permission was not
+	 * constructed with a subsystem.
+	 *
+	 * <p>
+	 * This method returns {@code true} if the specified permission is a
+	 * SubsystemPermission AND
+	 * <ul>
+	 * <li>this object's filter matches the specified permission's subsystem ID,
+	 * subsystem symbolic name, and subsystem location OR</li>
+	 * <li>this object's filter is "*"</li>
+	 * </ul>
+	 * AND this object's actions include all of the specified permission's
+	 * actions.
+	 * <p>
+	 * Special case: if the specified permission was constructed with "*"
+	 * filter, then this method returns {@code true} if this object's
+	 * filter is "*" and this object's actions include all of the specified
+	 * permission's actions
+	 *
+	 * @param p The requested permission.
+	 * @return {@code true} if the specified permission is implied by this
+	 *         object; {@code false} otherwise.
+	 */
+	public boolean implies(Permission p) {
+		if (!(p instanceof SubsystemPermission)) {
+			return false;
+		}
+		SubsystemPermission requested = (SubsystemPermission) p;
+		if (subsystem != 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);
+	}
+
+	/**
+	 * Internal implies method. Used by the implies and the permission
+	 * collection implies methods.
+	 *
+	 * @param requested The requested SubsystemPermision which has already been
+	 *        validated as a proper argument. The requested SubsystemPermission must
+	 *        not have a filter expression.
+	 * @param effective The effective actions with which to start.
+	 * @return {@code true} if the specified permission is implied by this
+	 *         object; {@code false} otherwise.
+	 */
+	boolean implies0(SubsystemPermission 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.subsystem == null) {
+			return false;
+		}
+		Map<String, Object> requestedProperties = requested
+				.getProperties();
+		if (requestedProperties == null) {
+			/*
+			 * If the requested properties are null, then we have detected a
+			 * recursion getting the subsystem location. So we return true to
+			 * permit the subsystem location request in the SubsystemPermission check
+			 * up the stack to succeed.
+			 */
+			return true;
+		}
+		return f.matches(requestedProperties);
+	}
+
+	/**
+	 * Returns the canonical string representation of the
+	 * {@code SubsystemPermission} actions.
+	 *
+	 * <p>
+	 * Always returns present {@code SubsystemPermission} actions in the following
+	 * order: {@code execute}, {@code lifecycle}, {@code metadata},
+	 * {@code context}.
+	 *
+	 * @return Canonical string representation of the {@code SubsystemPermission}
+	 *         actions.
+	 */
+	public String getActions() {
+		String result = actions;
+		if (result == null) {
+			StringBuffer sb = new StringBuffer();
+
+			int mask = action_mask;
+
+			if ((mask & ACTION_EXECUTE) == ACTION_EXECUTE) {
+				sb.append(EXECUTE);
+				sb.append(',');
+			}
+
+			if ((mask & ACTION_LIFECYCLE) == ACTION_LIFECYCLE) {
+				sb.append(LIFECYCLE);
+				sb.append(',');
+			}
+
+
+			if ((mask & ACTION_METADATA) == ACTION_METADATA) {
+				sb.append(METADATA);
+				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;
+	}
+
+	/**
+	 * Returns a new {@code PermissionCollection} object suitable for
+	 * storing {@code SubsystemPermission}s.
+	 *
+	 * @return A new {@code PermissionCollection} object.
+	 */
+	public PermissionCollection newPermissionCollection() {
+		return new SubsystemPermissionCollection();
+	}
+
+	/**
+	 * Determines the equality of two {@code SubsystemPermission} objects.
+	 *
+	 * @param obj The object being compared for equality with this object.
+	 * @return {@code true} if {@code obj} is equivalent to this
+	 *         {@code SubsystemPermission}; {@code false} otherwise.
+	 */
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+
+		if (!(obj instanceof SubsystemPermission)) {
+			return false;
+		}
+
+		SubsystemPermission sp = (SubsystemPermission) obj;
+
+		return (action_mask == sp.action_mask)
+				&& ((subsystem == sp.subsystem) || ((subsystem != null) && subsystem
+						.equals(sp.subsystem)))
+				&& (filter == null ? sp.filter == null : filter
+						.equals(sp.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 (subsystem != null) {
+			h = 31 * h + subsystem.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 (subsystem != 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 implies0} on an SubsystemPermission which was constructed
+	 * with a Subsystem. This method loads a map with the filter-matchable
+	 * properties of this subsystem. The map is cached so this lookup only happens
+	 * once.
+	 *
+	 * This method should only be called on an SubsystemPermission which was
+	 * constructed with a subsystem
+	 *
+	 * @return a map of properties for this subsystem
+	 */
+	private Map<String, Object> getProperties() {
+		Map<String, Object> result = properties;
+		if (result != null) {
+			return result;
+		}
+		/*
+		 * We may have recursed here due to the Subsystem.getLocation call in the
+		 * doPrivileged below. If this is the case, return null to allow implies
+		 * to return true.
+		 */
+		final Object mark = recurse.get();
+		if (mark == subsystem) {
+			return null;
+		}
+		recurse.set(subsystem);
+		try {
+			final Map<String, Object> map = new HashMap<String, Object>(4);
+			AccessController.doPrivileged(new PrivilegedAction<Object>() {
+				public Object run() {
+					map.put("id", new Long(subsystem.getSubsystemId()));
+					map.put("location", subsystem.getLocation());
+					map.put("name", subsystem.getSymbolicName());
+					return null;
+				}
+			});
+			return properties = map;
+		}
+		finally {
+			recurse.set(null);
+		}
+	}
+}
+
+/**
+ * Stores a collection of {@code SubsystemPermission}s.
+ */
+final class SubsystemPermissionCollection extends PermissionCollection {
+	private static final long	serialVersionUID	= 3906372644575328048L;
+	/**
+	 * Collection of permissions.
+	 *
+	 * @GuardedBy this
+	 */
+	private transient Map<String, SubsystemPermission>	permissions;
+
+	/**
+	 * Boolean saying if "*" is in the collection.
+	 *
+	 * @serial
+	 * @GuardedBy this
+	 */
+	private boolean				all_allowed;
+
+	/**
+	 * Create an empty SubsystemPermissionCollection object.
+	 *
+	 */
+	public SubsystemPermissionCollection() {
+		permissions = new HashMap<String, SubsystemPermission>();
+	}
+
+	/**
+	 * Adds a permission to this permission collection.
+	 *
+	 * @param permission The {@code SubsystemPermission} object to add.
+	 * @throws IllegalArgumentException If the specified permission is not an
+	 *         {@code SubsystemPermission} instance or was constructed with a
+	 *         Subsystem object.
+	 * @throws SecurityException If this {@code SubsystemPermissionCollection}
+	 *         object has been marked read-only.
+	 */
+	public void add(Permission permission) {
+		if (!(permission instanceof SubsystemPermission)) {
+			throw new IllegalArgumentException("invalid permission: "
+					+ permission);
+		}
+		if (isReadOnly()) {
+			throw new SecurityException("attempt to add a Permission to a "
+					+ "readonly PermissionCollection");
+		}
+		final SubsystemPermission sp = (SubsystemPermission) permission;
+		if (sp.subsystem != null) {
+			throw new IllegalArgumentException("cannot add to collection: "
+					+ sp);
+		}
+		final String name = sp.getName();
+		synchronized (this) {
+			Map<String, SubsystemPermission> pc = permissions;
+			SubsystemPermission existing = pc.get(name);
+			if (existing != null) {
+				int oldMask = existing.action_mask;
+				int newMask = sp.action_mask;
+
+				if (oldMask != newMask) {
+					pc.put(name, new SubsystemPermission(existing.filter, oldMask
+							| newMask));
+				}
+			}
+			else {
+				pc.put(name, sp);
+			}
+			if (!all_allowed) {
+				if (name.equals("*")) {
+					all_allowed = true;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Determines if the specified permissions implies the permissions expressed
+	 * in {@code permission}.
+	 *
+	 * @param permission The Permission object to compare with the
+	 *        {@code SubsystemPermission} objects in this collection.
+	 * @return {@code true} if {@code permission} is implied by an
+	 *         {@code SubsystemPermission} in this collection,
+	 *         {@code false} otherwise.
+	 */
+	public boolean implies(Permission permission) {
+		if (!(permission instanceof SubsystemPermission)) {
+			return false;
+		}
+
+		SubsystemPermission requested = (SubsystemPermission) permission;
+		// if requested permission has a filter, then it is an invalid argument
+		if (requested.filter != null) {
+			return false;
+		}
+		int effective = SubsystemPermission.ACTION_NONE;
+		Collection<SubsystemPermission> perms;
+		synchronized (this) {
+			Map<String, SubsystemPermission> pc = permissions;
+			// short circuit if the "*" Permission was added
+			if (all_allowed) {
+				SubsystemPermission sp = pc.get("*");
+				if (sp != null) {
+					effective |= sp.action_mask;
+					final int desired = requested.action_mask;
+					if ((effective & desired) == desired) {
+						return true;
+					}
+				}
+			}
+			perms = pc.values();
+		}
+
+		// just iterate one by one
+		for (SubsystemPermission perm : perms) {
+			if (perm.implies0(requested, effective)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Returns an enumeration of all {@code SubsystemPermission} objects in the
+	 * container.
+	 *
+	 * @return Enumeration of all {@code SubsystemPermission} objects.
+	 */
+	public synchronized Enumeration<Permission> elements() {
+		List<Permission> all = new ArrayList<Permission>(permissions.values());
+		return Collections.enumeration(all);
+	}
+
+	/* serialization logic */
+    private static final ObjectStreamField[]	serialPersistentFields	= {
+			new ObjectStreamField("permissions", HashMap.class),
+			new ObjectStreamField("all_allowed", Boolean.TYPE)			};
+
+    private synchronized void writeObject(ObjectOutputStream out)
+			throws IOException {
+		ObjectOutputStream.PutField pfields = out.putFields();
+		pfields.put("permissions", permissions);
+		pfields.put("all_allowed", all_allowed);
+		out.writeFields();
+	}
+
+	private synchronized void readObject(java.io.ObjectInputStream in)
+			throws IOException,
+			ClassNotFoundException {
+		ObjectInputStream.GetField gfields = in.readFields();
+		HashMap<String, SubsystemPermission> p = (HashMap<String, SubsystemPermission>) gfields
+				.get("permissions", null);
+		permissions = p;
+		all_allowed = gfields.get("all_allowed", false);
+	}
+}

Modified: aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/package-info.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/package-info.java?rev=1241900&r1=1241899&r2=1241900&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/package-info.java (original)
+++ aries/trunk/subsystem/subsystem-api/src/main/java/org/osgi/service/subsystem/package-info.java Wed Feb  8 13:54:41 2012
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2010). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2010, 2011). 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.
@@ -32,7 +32,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.service.subsystem; version="[1.0,1.1)"}
  * 
- * @version $Id: b1e29b95829d6cdd9eb0d4246cda38442fb3cf37 $
+ * @version $Id: c92a6ccec8a36b4507b349e8d539a327fd2515d3 $
  */
 
-package org.osgi.service.subsystem;
\ No newline at end of file
+package org.osgi.service.subsystem;