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> </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 "osgi.subsystem.".
*/
- 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 "subsystem.id".
+ */
+ 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 "subsystem.state".
+ */
+ 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 "subsystem.symbolicname".
+ */
+ 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 "subsystem.type".
+ */
+ public static final String SUBSYSTEM_TYPE_PROPERTY = "subsystem.type";
+
+ /**
* Manifest header value identifying an application subsystem.
+ * It is defined to be "osgi.application".
*/
public static final String SUBSYSTEM_TYPE_APPLICATION = "osgi.application";
/**
* Manifest header value identifying a composite subsystem.
+ * It is defined to be "osgi.composite".
*/
public static final String SUBSYSTEM_TYPE_COMPOSITE = "osgi.composite";
/**
* Manifest header value identifying a feature subsystem.
+ * It is defined to be "osgi.feature".
*/
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>=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;