Return-Path: X-Original-To: apmail-aries-commits-archive@www.apache.org Delivered-To: apmail-aries-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id C52AD957B for ; Wed, 8 Feb 2012 13:55:14 +0000 (UTC) Received: (qmail 74762 invoked by uid 500); 8 Feb 2012 13:55:14 -0000 Delivered-To: apmail-aries-commits-archive@aries.apache.org Received: (qmail 74691 invoked by uid 500); 8 Feb 2012 13:55:14 -0000 Mailing-List: contact commits-help@aries.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@aries.apache.org Delivered-To: mailing list commits@aries.apache.org Received: (qmail 74676 invoked by uid 99); 8 Feb 2012 13:55:14 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Feb 2012 13:55:14 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Feb 2012 13:55:09 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 6452C23889BB; Wed, 8 Feb 2012 13:54:49 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: 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-... Date: Wed, 08 Feb 2012 13:54:44 -0000 To: commits@aries.apache.org From: jwross@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120208135449.6452C23889BB@eris.apache.org> 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. + *

+ * 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. + *

    + *
  • {@link SubsystemConstants#SUBSYSTEM_TYPE_APPLICATION Application} - + * An implicitly scoped subsystem. Nothing is exported, and imports are + * computed based on any unsatisfied content dependencies. + *
  • + *
  • {@link SubsystemConstants#SUBSYSTEM_TYPE_COMPOSITE Composite} - An + * explicitly scoped subsystem. The sharing policy is defined by + * metadata within the subsystem archive. + *
  • + *
  • {@link SubsystemConstants#SUBSYSTEM_TYPE_FEATURE Feature} - An + * unscoped subsystem. + *
  • + *
+ * 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. + *

+ * 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. + *

+ * A subsystem has several unique identifiers. + *

    + *
  • {@link #getLocation() Location} - An identifier specified by the + * client as part of installation. It is guaranteed to be unique within + * the same framework. + *
  • + *
  • {@link #getSubsystemId() ID} - An identifier generated by the + * implementation as part of installation. It is guaranteed to be + * unique within the same framework. + *
  • {@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. + *
  • + *
+ * 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. + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
OperationFrom StateTo State
{@link #install(String, InputStream) Install} {@link State#INSTALLING INSTALLING}, {@link State#INSTALL_FAILED + * INSTALL_FAILED}, {@link State#INSTALLED INSTALLED} + *
{@link #start() Start}{@link State#INSTALLED INSTALLED}, {@link State#RESOLVED + * RESOLVED} + * {@link State#INSTALLED INSTALLED}, {@link State#RESOLVING + * RESOLVING}, {@link State#RESOLVED RESOLVED}, {@link + * State#STARTING STARTING}, {@link State#ACTIVE ACTIVE} + *
{@link #stop() Stop}{@link State#ACTIVE ACTIVE}{@link State#RESOLVED RESOLVED}, {@link State#STOPPING STOPPING} + *
{@link #uninstall() Uninstall}{@link State#INSTALLED INSTALLED}, {@link State#RESOLVED + * RESOLVED}, {@link State#ACTIVE ACTIVE} + * {@link State#UNINSTALLING UNINSTALLING}, {@link + * State#UNINSTALLED UNINSTALLED} + *
+ *

+ * 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. + *

    + *
  • {@link ResourceConstants#IDENTITY_TYPE_BUNDLE Bundle} - A bundle + * that is not a fragment. + *
  • + *
  • {@link ResourceConstants#IDENTITY_TYPE_FRAGMENT Fragment} - A + * fragment bundle. + *
  • + *
  • {@link SubsystemConstants#IDENTITY_TYPE_SUBSYSTEM Subsystem} - A + * subsystem defined by this specification. + *
  • + *
+ * 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. + *

+ *

    + *
  • A resource was listed as part of the subsystem's content. + *
  • + *
  • A subsystem resource is a child of the subsystem. + *
  • + *
  • The subsystem has a provision policy of accept transitive. + *
  • + *
  • A bundle resource was installed using the region bundle context. + *
  • + *
  • A bundle resource was installed using the bundle context of + * another resource contained by the subsystem. + *
  • + *
+ * 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. + *

+ *

    + *
  • {@link SubsystemConstants#SUBSYSTEM_ID_PROPERTY ID} - Matches the ID + * of the subsystem. + *
  • + *
  • {@link SubsystemConstants#SUBSYSTEM_SYMBOLICNAME_PROPERTY Symbolic + * Name} - Matches the symbolic name of the subsystem. + *
  • + *
  • {@link SubsystemConstants#SUBSYSTEM_VERSION_PROPERTY Version} - + * Matches the version of the subsystem. + *
  • + *
  • {@link SubsystemConstants#SUBSYSTEM_TYPE_PROPERTY Type} - Matches + * the type of the subsystem. + *
  • + *
  • {@link SubsystemConstants#SUBSYSTEM_STATE_PROPERTY State} - Matches + * the state of the subsystem. + *
  • + *
+ * 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. + *

+ *

    + *
  • The ID is {@code 0}. + *
  • + *
  • The symbolic name is {@code org.osgi.service.subsystem.root}. + *
  • + *
  • The version matches this specification's version. + *
  • + *
  • It has no parents. + *
  • + *
  • All existing bundles, including the system and subsystems + * implementation bundles, become constituents. + *
  • + *
  • The type is {@code osgi.composite} with no imports or exports. + *
  • + *
  • The provision policy is {@code acceptTransitive}. + *
  • + *
* * @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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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 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. + *

+ * 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. + *

+ * 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. + *

+ * 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 getConstituents(); + public Map 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. + *

+ * 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. + *

+ * 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 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 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. + *

+ * 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 getParents(); + + /** + * Returns the constituent resources of this subsystem. + *

+ * 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 getConstituents(); /** - * Gets the state of the subsystem. - * @return The state of the subsystem. + * Returns the current state of this subsystem. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

    + *
  • The value of the {@link SubsystemConstants#SUBSYSTEM_CONTENT + * Subsystem-Content} header, if specified. + *
  • + *
  • The subsystem URI if passed as the {@code location} along with + * the {@code content} to the {@link #install(String, InputStream) + * install} method. + *
  • + *
  • Optionally generated in an implementation specific way. + *
  • + *
+ * 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}. + *

+ * 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. + *

+ * 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. + *

+ * The subsystem version conforms to the same grammar rules as the bundle + * version and is derived from one of the following, in order. + *

    + *
  • The value of the {@code Subsystem-Version} header, if specified. + *
  • + *
  • The subsystem URI if passed as the {@code location} along with + * the {@code content} to the {@link #install(String, InputStream) + * install} method. + *
  • + *
  • Defaults to {@code 0.0.0}. + *
  • + *
+ * 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. + *

+ * 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. - *

- * 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. + *

+ * 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}. + *

+ * 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. *

- * 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}. *

- * 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. *

- * 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. *

- * 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. *

- * The following steps are required to install a subsystem: + * All installation failure flows include the following, in order. + *

    + *
  1. Uninstall all resources installed as part of this operation. + *
  2. + *
  3. Change the state to INSTALL_FAILED. + *
  4. + *
  5. Unregister the subsystem service. + *
  6. + *
  7. Uninstall the region context bundle. + *
  8. + *
  9. Throw a SubsystemException with the specified cause. + *
  10. + *
+ * The following steps are required to install a subsystem. *
    - *
  1. If there is an existing subsystem containing the same location - * identifier as the subsystem to be installed, then the existing - * subsystem is returned.
  2. - *
  3. If this is a new install, then a new Subsystem is created with - * its id set to the next available value (ascending order).
  4. - *
  5. The subsystem's state is set to INSTALLING and if EventAdmin is - * available, an event of type INSTALLING is fired.
  6. - *
  7. The following installation steps are then started and performed - * asynchronously and the new subsystem is returned to the caller.
  8. - *
  9. The subsystem content is read from the input stream.
  10. - *
  11. 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).
  12. - *
  13. If the subsystem does not include a deployment manifest, then - * the subsystem runtime must calculate one.
  14. - *
  15. 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.
  16. - *
  17. The subsystem's state is set to INSTALLED and if EventAdmin is - * available an INSTALLED event is fired.
  18. + *
  19. If an installed subsystem with the specified {@code location} + * identifier already exists, return the installed subsystem. + *
  20. + *
  21. 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. + *
  22. + *
  23. 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. + *
      + *
    • If the installing and installed subsystems' types are not equal, + * an installation failure results. + *
    • + *
    • If the installing and installed subsystems' types are equal, and + * the installed subsystem is already a child of this subsystem, + * return the installed subsystem. + *
    • + *
    • 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. + *
    • + *
    + *
  24. + *
  25. Create a new subsystem based on the specified {@code location} and + * {@code content}. + *
  26. + *
  27. If the subsystem is scoped, install and activate a new region context + * bundle. + *
  28. + *
  29. Change the state to INSTALLING and register a new subsystem service. + *
  30. + *
  31. {@link Repository Discover} the subsystem's content resources. If any + * mandatory resource is missing, an installation failure results. + *
  32. + *
  33. {@link Resolver Discover} the transitive resources required by the + * content resources. If any transitive resource is missing, an + * installation failure results. + *
  34. + *
  35. {@link ResolverHook Disable} runtime resolution for the resources. + *
  36. + *
  37. 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. + *
  38. + *
  39. If the subsystem is scoped, enable the import sharing policy. + *
  40. + *
  41. Enable runtime resolution for the resources. + *
  42. + *
  43. Change the state of the subsystem to INSTALLED. + *
  44. + *
  45. Return the new subsystem. + *
  46. *
- * @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. + *

+ * 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. + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
State + * Action + *
INSTALLINGWait
INSTALLEDResolve, Start
INSTALL_FAILEDIllegalStateException
RESOLVINGWait
RESOLVEDIf this subsystem is in the process of being
+ * started, Wait. Otherwise, Uninstall.
STARTINGWait
ACTIVEReturn
STOPPINGWait
UNINSTALLINGIllegalStateException
UNINSTALLEDIllegalStateException
+ *

+ * 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. + *

+ * 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. + *

+ * All start failure flows include the following, in order. + *

    + *
  1. Stop all resources that were started as part of this operation. + *
  2. + *
  3. Disable the export sharing policy. + *
  4. + *
  5. Change the state to either INSTALLED or RESOLVED. + *
  6. + *
  7. Throw a SubsystemException with the specified cause. + *
  8. + *
+ *

+ * 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. + *

+ * The following steps are required to start this subsystem. + *

    + *
  1. If this subsystem is in the RESOLVED state, proceed to step 5. + *
  2. + *
  3. Change the state to RESOLVING. + *
  4. + *
  5. Resolve the content resources. A resolution failure results in + * a start failure with a state of INSTALLED. + *
  6. + *
  7. Change the state to RESOLVED. + *
  8. + *
  9. If this subsystem is scoped, enable the export sharing policy. + *
  10. + *
  11. Change the state to STARTING. + *
  12. + *
  13. 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. + *
  14. + *
  15. Change the state to ACTIVE. + *
  16. + *
+ *

+ * @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. + *

+ * 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. + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
State + * Action + *
INSTALLINGWait
INSTALLEDReturn
INSTALL_FAILEDIllegalStateException
RESOLVINGWait
RESOLVEDIf this subsystem is in the process of being
+ * started, Wait. Otherwise, Return.
STARTINGWait
ACTIVEStop
STOPPINGWait
UNINSTALLINGIllegalStateException
UNINSTALLEDIllegalStateException
+ *

+ * 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. + *

+ * A subsystem must be persistently stopped. That is, a stopped subsystem + * must remain stopped across Framework and VM restarts. + *

+ * 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. + *

+ * The following steps are required to stop this subsystem. + *

    + *
  1. Change the state to STOPPING. + *
  2. + *
  3. 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. + *
  4. + *
  5. Change the state to RESOLVED. + *
  6. + *
+ * 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. + *

+ * @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. + *

+ * 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. + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
State + * Action + *
INSTALLINGWait
INSTALLEDUninstall
INSTALL_FAILEDIllegalStateException
RESOLVINGWait
RESOLVEDIf this subsystem is in the process of being
+ * started, Wait. Otherwise, Uninstall.
STARTINGWait
ACTIVEStop, Uninstall
STOPPINGWait
UNINSTALLINGWait
UNINSTALLEDReturn
*

- * 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. + *

+ * 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. + *

+ * The following steps are required to uninstall this subsystem. *

    - *
  1. If this subsystem's state is UNINSTALLED then an - * IllegalStateException is thrown.
  2. - *
  3. 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.
  4. - *
  5. This subsystem's state is set to UNINSTALLED.
  6. - *
  7. A subsystem event of type SubsystemEvent.UNINSTALLED is fired.
  8. - *
  9. This subsystem and any persistent storage area provided for this - * subsystem by the Framework are removed.
  10. + *
  11. Change the state to UNINSTALLING. + *
  12. + *
  13. 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. + *
  14. + *
  15. Change the state to UNINSTALLED. + *
  16. + *
  17. Unregister the subsystem service. + *
  18. + *
  19. Uninstall the region context bundle. + *
  20. *
- * @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. + *

+ * @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: + * + *

+ *  Action               Methods
+ *  context              Subsystem.getBundleContext
+ *  execute              Subsystem.start
+ *                       Subsystem.stop
+ *  lifecycle            Subsystem.install
+ *                       Subsystem.uninstall
+ *  metadata             Subsystem.getHeaders
+ *                       Subsystem.getLocation
+ * 
+ * + *

+ * The name of this permission is a filter expression. The filter gives access + * to the following attributes: + *

    + *
  • location - The location of a subsystem.
  • + *
  • id - The subsystem ID of the designated subsystem.
  • + *
  • name - The symbolic name of a subsystem.
  • + *
+ * 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 properties; + + /** + * ThreadLocal used to determine if we have recursively called + * getProperties. + */ + private static final ThreadLocal recurse = new ThreadLocal(); + + /** + * Create a new SubsystemPermission. + * + * This constructor must only be used to create a permission that is going + * to be checked. + *

+ * Examples: + * + *

+	 * (name=com.acme.*)(location=http://www.acme.com/subsystems/*))
+	 * (id>=1)
+	 * 
+ * + * @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. + * + *

+ * This method returns {@code true} if the specified permission is a + * SubsystemPermission AND + *

    + *
  • this object's filter matches the specified permission's subsystem ID, + * subsystem symbolic name, and subsystem location OR
  • + *
  • this object's filter is "*"
  • + *
+ * AND this object's actions include all of the specified permission's + * actions. + *

+ * 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 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. + * + *

+ * 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 getProperties() { + Map 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 map = new HashMap(4); + AccessController.doPrivileged(new PrivilegedAction() { + 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 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(); + } + + /** + * 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 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 perms; + synchronized (this) { + Map 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 elements() { + List all = new ArrayList(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 p = (HashMap) 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 @@ *

* {@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;