Modify FrameworkUtil.createFilter() to return our Filter impl. Include
OSGi classes directory in framework project, since there is no way to
easily remove FrameworkUtil class from our dependencies. (FELIX-2039)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@926997 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/pom.xml b/framework/pom.xml
index c52854f..b981200 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -29,16 +29,6 @@
<artifactId>org.apache.felix.framework</artifactId>
<version>2.1.0-SNAPSHOT</version>
<dependencies>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
- <version>4.2.0</version>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.compendium</artifactId>
- <version>4.2.0</version>
- </dependency>
</dependencies>
<properties>
<dollar>$</dollar>
diff --git a/framework/src/main/java/org/osgi/framework/AdminPermission.java b/framework/src/main/java/org/osgi/framework/AdminPermission.java
new file mode 100644
index 0000000..1811791
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/AdminPermission.java
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.security.AccessController;
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A bundle's authority to perform specific privileged administrative operations
+ * on or to get sensitive information about a bundle. The actions for this
+ * permission are:
+ *
+ * <pre>
+ * Action Methods
+ * class Bundle.loadClass
+ * execute Bundle.start
+ * Bundle.stop
+ * StartLevel.setBundleStartLevel
+ * extensionLifecycle BundleContext.installBundle for extension bundles
+ * Bundle.update for extension bundles
+ * Bundle.uninstall for extension bundles
+ * lifecycle BundleContext.installBundle
+ * Bundle.update
+ * Bundle.uninstall
+ * listener BundleContext.addBundleListener for SynchronousBundleListener
+ * BundleContext.removeBundleListener for SynchronousBundleListener
+ * metadata Bundle.getHeaders
+ * Bundle.getLocation
+ * resolve PackageAdmin.refreshPackages
+ * PackageAdmin.resolveBundles
+ * resource Bundle.getResource
+ * Bundle.getResources
+ * Bundle.getEntry
+ * Bundle.getEntryPaths
+ * Bundle.findEntries
+ * Bundle resource/entry URL creation
+ * startlevel StartLevel.setStartLevel
+ * StartLevel.setInitialBundleStartLevel
+ * context Bundle.getBundleContext
+ * </pre>
+ *
+ * <p>
+ * The special action "*" will represent all actions. The
+ * <code>resolve</code> action is implied by the <code>class</code>,
+ * <code>execute</code> and <code>resource</code> actions.
+ * <p>
+ * The name of this permission is a filter expression. The filter gives access
+ * to the following attributes:
+ * <ul>
+ * <li>signer - A Distinguished Name chain used to sign a bundle. Wildcards in a
+ * DN are not matched according to the filter string rules, but according to the
+ * rules defined for a DN chain.</li>
+ * <li>location - The location of a bundle.</li>
+ * <li>id - The bundle ID of the designated bundle.</li>
+ * <li>name - The symbolic name of a bundle.</li>
+ * </ul>
+ * Filter attribute names are processed in a case sensitive manner.
+ *
+ * @ThreadSafe
+ * @version $Revision: 7743 $
+ */
+
+public final class AdminPermission extends BasicPermission {
+ static final long serialVersionUID = 307051004521261705L;
+
+ /**
+ * The action string <code>class</code>. The <code>class</code> action
+ * implies the <code>resolve</code> action.
+ *
+ * @since 1.3
+ */
+ public final static String CLASS = "class";
+ /**
+ * The action string <code>execute</code>. The <code>execute</code> action
+ * implies the <code>resolve</code> action.
+ *
+ * @since 1.3
+ */
+ public final static String EXECUTE = "execute";
+ /**
+ * The action string <code>extensionLifecycle</code>.
+ *
+ * @since 1.3
+ */
+ public final static String EXTENSIONLIFECYCLE = "extensionLifecycle";
+ /**
+ * The action string <code>lifecycle</code>.
+ *
+ * @since 1.3
+ */
+ public final static String LIFECYCLE = "lifecycle";
+ /**
+ * The action string <code>listener</code>.
+ *
+ * @since 1.3
+ */
+ public final static String LISTENER = "listener";
+ /**
+ * The action string <code>metadata</code>.
+ *
+ * @since 1.3
+ */
+ public final static String METADATA = "metadata";
+ /**
+ * The action string <code>resolve</code>. The <code>resolve</code> action
+ * is implied by the <code>class</code>, <code>execute</code> and
+ * <code>resource</code> actions.
+ *
+ * @since 1.3
+ */
+ public final static String RESOLVE = "resolve";
+ /**
+ * The action string <code>resource</code>. The <code>resource</code> action
+ * implies the <code>resolve</code> action.
+ *
+ * @since 1.3
+ */
+ public final static String RESOURCE = "resource";
+ /**
+ * The action string <code>startlevel</code>.
+ *
+ * @since 1.3
+ */
+ public final static String STARTLEVEL = "startlevel";
+
+ /**
+ * The action string <code>context</code>.
+ *
+ * @since 1.4
+ */
+ public final static String CONTEXT = "context";
+
+ private final static int ACTION_CLASS = 0x00000001;
+ private final static int ACTION_EXECUTE = 0x00000002;
+ private final static int ACTION_LIFECYCLE = 0x00000004;
+ private final static int ACTION_LISTENER = 0x00000008;
+ private final static int ACTION_METADATA = 0x00000010;
+ private final static int ACTION_RESOLVE = 0x00000040;
+ private final static int ACTION_RESOURCE = 0x00000080;
+ private final static int ACTION_STARTLEVEL = 0x00000100;
+ private final static int ACTION_EXTENSIONLIFECYCLE = 0x00000200;
+ private final static int ACTION_CONTEXT = 0x00000400;
+ private final static int ACTION_ALL = ACTION_CLASS
+ | ACTION_EXECUTE
+ | ACTION_LIFECYCLE
+ | ACTION_LISTENER
+ | ACTION_METADATA
+ | ACTION_RESOLVE
+ | ACTION_RESOURCE
+ | ACTION_STARTLEVEL
+ | ACTION_EXTENSIONLIFECYCLE
+ | ACTION_CONTEXT;
+ final static int ACTION_NONE = 0;
+
+ /**
+ * The actions in canonical form.
+ *
+ * @serial
+ */
+ private volatile String actions = null;
+
+ /**
+ * The actions mask.
+ */
+ transient int action_mask;
+
+ /**
+ * If this AdminPermission was constructed with a filter, this holds a
+ * Filter matching object used to evaluate the filter in implies.
+ */
+ transient Filter filter;
+
+ /**
+ * The bundle governed by this AdminPermission - only used if filter == null
+ */
+ transient final Bundle bundle;
+
+ /**
+ * This dictionary holds the properties of the permission, used to match a
+ * filter in implies. This is not initialized until necessary, and then
+ * cached in this object.
+ */
+ private transient volatile Dictionary properties;
+
+ /**
+ * ThreadLocal used to determine if we have recursively called
+ * getProperties.
+ */
+ private static final ThreadLocal recurse = new ThreadLocal();
+
+ /**
+ * Creates a new <code>AdminPermission</code> object that matches all
+ * bundles and has all actions. Equivalent to AdminPermission("*","*");
+ */
+ public AdminPermission() {
+ this(null, ACTION_ALL);
+ }
+
+ /**
+ * Create a new AdminPermission.
+ *
+ * This constructor must only be used to create a permission that is going
+ * to be checked.
+ * <p>
+ * Examples:
+ *
+ * <pre>
+ * (signer=\*,o=ACME,c=US)
+ * (&(signer=\*,o=ACME,c=US)(name=com.acme.*)(location=http://www.acme.com/bundles/*))
+ * (id>=1)
+ * </pre>
+ *
+ * <p>
+ * When a signer key is used within the filter expression the signer value
+ * must escape the special filter chars ('*', '(', ')').
+ * <p>
+ * Null arguments are equivalent to "*".
+ *
+ * @param filter A filter expression that can use signer, location, id, and
+ * name keys. A value of "*" or <code>null</code> matches
+ * all bundle. Filter attribute names are processed in a case
+ * sensitive manner.
+ * @param actions <code>class</code>, <code>execute</code>,
+ * <code>extensionLifecycle</code>, <code>lifecycle</code>,
+ * <code>listener</code>, <code>metadata</code>, <code>resolve</code>
+ * , <code>resource</code>, <code>startlevel</code> or
+ * <code>context</code>. A value of "*" or <code>null</code>
+ * indicates all actions.
+ * @throws IllegalArgumentException If the filter has an invalid syntax.
+ */
+ public AdminPermission(String filter, String actions) {
+ // arguments will be null if called from a PermissionInfo defined with
+ // no args
+ this(parseFilter(filter), parseActions(actions));
+ }
+
+ /**
+ * Creates a new requested <code>AdminPermission</code> object to be used by
+ * the code that must perform <code>checkPermission</code>.
+ * <code>AdminPermission</code> objects created with this constructor cannot
+ * be added to an <code>AdminPermission</code> permission collection.
+ *
+ * @param bundle A bundle.
+ * @param actions <code>class</code>, <code>execute</code>,
+ * <code>extensionLifecycle</code>, <code>lifecycle</code>,
+ * <code>listener</code>, <code>metadata</code>, <code>resolve</code>
+ * , <code>resource</code>, <code>startlevel</code>,
+ * <code>context</code>. A value of "*" or <code>null</code>
+ * indicates all actions.
+ * @since 1.3
+ */
+ public AdminPermission(Bundle bundle, String actions) {
+ super(createName(bundle));
+ setTransients(null, parseActions(actions));
+ this.bundle = bundle;
+ }
+
+ /**
+ * Create a permission name from a Bundle
+ *
+ * @param bundle Bundle to use to create permission name.
+ * @return permission name.
+ */
+ private static String createName(Bundle bundle) {
+ if (bundle == null) {
+ throw new IllegalArgumentException("bundle must not be null");
+ }
+ StringBuffer sb = new StringBuffer("(id=");
+ sb.append(bundle.getBundleId());
+ sb.append(")");
+ return sb.toString();
+ }
+
+ /**
+ * Package private constructor used by AdminPermissionCollection.
+ *
+ * @param filter name filter or <code>null</code> for wildcard.
+ * @param mask action mask
+ */
+ AdminPermission(Filter filter, int mask) {
+ super((filter == null) ? "*" : filter.toString());
+ setTransients(filter, mask);
+ this.bundle = null;
+ }
+
+ /**
+ * Called by constructors and when deserialized.
+ *
+ * @param filter Permission's filter or <code>null</code> 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) {
+ if ((actions == null) || actions.equals("*")) {
+ return ACTION_ALL;
+ }
+
+ boolean seencomma = false;
+
+ int mask = ACTION_NONE;
+
+ if (actions == null) {
+ return mask;
+ }
+
+ char[] a = actions.toCharArray();
+
+ int i = a.length - 1;
+ if (i < 0)
+ return mask;
+
+ while (i != -1) {
+ char c;
+
+ // skip whitespace
+ while ((i != -1)
+ && ((c = a[i]) == ' ' || c == '\r' || c == '\n'
+ || c == '\f' || c == '\t'))
+ i--;
+
+ // check for the known strings
+ int matchlen;
+
+ if (i >= 4 && (a[i - 4] == 'c' || a[i - 4] == 'C')
+ && (a[i - 3] == 'l' || a[i - 3] == 'L')
+ && (a[i - 2] == 'a' || a[i - 2] == 'A')
+ && (a[i - 1] == 's' || a[i - 1] == 'S')
+ && (a[i] == 's' || a[i] == 'S')) {
+ matchlen = 5;
+ mask |= ACTION_CLASS | ACTION_RESOLVE;
+
+ }
+ else
+ if (i >= 6 && (a[i - 6] == 'e' || a[i - 6] == 'E')
+ && (a[i - 5] == 'x' || a[i - 5] == 'X')
+ && (a[i - 4] == 'e' || a[i - 4] == 'E')
+ && (a[i - 3] == 'c' || a[i - 3] == 'C')
+ && (a[i - 2] == 'u' || a[i - 2] == 'U')
+ && (a[i - 1] == 't' || a[i - 1] == 'T')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 7;
+ mask |= ACTION_EXECUTE | ACTION_RESOLVE;
+
+ }
+ else
+ if (i >= 17 && (a[i - 17] == 'e' || a[i - 17] == 'E')
+ && (a[i - 16] == 'x' || a[i - 16] == 'X')
+ && (a[i - 15] == 't' || a[i - 15] == 'T')
+ && (a[i - 14] == 'e' || a[i - 14] == 'E')
+ && (a[i - 13] == 'n' || a[i - 13] == 'N')
+ && (a[i - 12] == 's' || a[i - 12] == 'S')
+ && (a[i - 11] == 'i' || a[i - 11] == 'I')
+ && (a[i - 10] == 'o' || a[i - 10] == 'O')
+ && (a[i - 9] == 'n' || a[i - 9] == 'N')
+ && (a[i - 8] == 'l' || a[i - 8] == 'L')
+ && (a[i - 7] == 'i' || a[i - 7] == 'I')
+ && (a[i - 6] == 'f' || a[i - 6] == 'F')
+ && (a[i - 5] == 'e' || a[i - 5] == 'E')
+ && (a[i - 4] == 'c' || a[i - 4] == 'C')
+ && (a[i - 3] == 'y' || a[i - 3] == 'Y')
+ && (a[i - 2] == 'c' || a[i - 2] == 'C')
+ && (a[i - 1] == 'l' || a[i - 1] == 'L')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 18;
+ mask |= ACTION_EXTENSIONLIFECYCLE;
+
+ }
+ else
+ if (i >= 8 && (a[i - 8] == 'l' || a[i - 8] == 'L')
+ && (a[i - 7] == 'i' || a[i - 7] == 'I')
+ && (a[i - 6] == 'f' || a[i - 6] == 'F')
+ && (a[i - 5] == 'e' || a[i - 5] == 'E')
+ && (a[i - 4] == 'c' || a[i - 4] == 'C')
+ && (a[i - 3] == 'y' || a[i - 3] == 'Y')
+ && (a[i - 2] == 'c' || a[i - 2] == 'C')
+ && (a[i - 1] == 'l' || a[i - 1] == 'L')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 9;
+ mask |= ACTION_LIFECYCLE;
+
+ }
+ else
+ if (i >= 7 && (a[i - 7] == 'l' || a[i - 7] == 'L')
+ && (a[i - 6] == 'i' || a[i - 6] == 'I')
+ && (a[i - 5] == 's' || a[i - 5] == 'S')
+ && (a[i - 4] == 't' || a[i - 4] == 'T')
+ && (a[i - 3] == 'e' || a[i - 3] == 'E')
+ && (a[i - 2] == 'n' || a[i - 2] == 'N')
+ && (a[i - 1] == 'e' || a[i - 1] == 'E')
+ && (a[i] == 'r' || a[i] == 'R')) {
+ matchlen = 8;
+ mask |= ACTION_LISTENER;
+
+ }
+ else
+ if (i >= 7
+ && (a[i - 7] == 'm' || a[i - 7] == 'M')
+ && (a[i - 6] == 'e' || a[i - 6] == 'E')
+ && (a[i - 5] == 't' || a[i - 5] == 'T')
+ && (a[i - 4] == 'a' || a[i - 4] == 'A')
+ && (a[i - 3] == 'd' || a[i - 3] == 'D')
+ && (a[i - 2] == 'a' || a[i - 2] == 'A')
+ && (a[i - 1] == 't' || a[i - 1] == 'T')
+ && (a[i] == 'a' || a[i] == 'A')) {
+ matchlen = 8;
+ mask |= ACTION_METADATA;
+
+ }
+ else
+ if (i >= 6
+ && (a[i - 6] == 'r' || a[i - 6] == 'R')
+ && (a[i - 5] == 'e' || a[i - 5] == 'E')
+ && (a[i - 4] == 's' || a[i - 4] == 'S')
+ && (a[i - 3] == 'o' || a[i - 3] == 'O')
+ && (a[i - 2] == 'l' || a[i - 2] == 'L')
+ && (a[i - 1] == 'v' || a[i - 1] == 'V')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 7;
+ mask |= ACTION_RESOLVE;
+
+ }
+ else
+ if (i >= 7
+ && (a[i - 7] == 'r' || a[i - 7] == 'R')
+ && (a[i - 6] == 'e' || a[i - 6] == 'E')
+ && (a[i - 5] == 's' || a[i - 5] == 'S')
+ && (a[i - 4] == 'o' || a[i - 4] == 'O')
+ && (a[i - 3] == 'u' || a[i - 3] == 'U')
+ && (a[i - 2] == 'r' || a[i - 2] == 'R')
+ && (a[i - 1] == 'c' || a[i - 1] == 'C')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 8;
+ mask |= ACTION_RESOURCE
+ | ACTION_RESOLVE;
+
+ }
+ else
+ if (i >= 9
+ && (a[i - 9] == 's' || a[i - 9] == 'S')
+ && (a[i - 8] == 't' || a[i - 8] == 'T')
+ && (a[i - 7] == 'a' || a[i - 7] == 'A')
+ && (a[i - 6] == 'r' || a[i - 6] == 'R')
+ && (a[i - 5] == 't' || a[i - 5] == 'T')
+ && (a[i - 4] == 'l' || a[i - 4] == 'L')
+ && (a[i - 3] == 'e' || a[i - 3] == 'E')
+ && (a[i - 2] == 'v' || a[i - 2] == 'V')
+ && (a[i - 1] == 'e' || a[i - 1] == 'E')
+ && (a[i] == 'l' || a[i] == 'L')) {
+ matchlen = 10;
+ mask |= ACTION_STARTLEVEL;
+
+ }
+ else
+ if (i >= 6
+ && (a[i - 6] == 'c' || a[i - 6] == 'C')
+ && (a[i - 5] == 'o' || a[i - 5] == 'O')
+ && (a[i - 4] == 'n' || a[i - 4] == 'N')
+ && (a[i - 3] == 't' || a[i - 3] == 'T')
+ && (a[i - 2] == 'e' || a[i - 2] == 'E')
+ && (a[i - 1] == 'x' || a[i - 1] == 'X')
+ && (a[i] == 't' || a[i] == 'T')) {
+ matchlen = 7;
+ mask |= ACTION_CONTEXT;
+
+ }
+ else
+ if (i >= 0 &&
+
+ (a[i] == '*')) {
+ matchlen = 1;
+ mask |= ACTION_ALL;
+
+ }
+ else {
+ // parse error
+ throw new IllegalArgumentException(
+ "invalid permission: "
+ + actions);
+ }
+
+ // make sure we didn't just match the tail of a word
+ // like "ackbarfstartlevel". Also, skip to the comma.
+ seencomma = false;
+ while (i >= matchlen && !seencomma) {
+ switch (a[i - matchlen]) {
+ case ',' :
+ seencomma = true;
+ /* FALLTHROUGH */
+ case ' ' :
+ case '\r' :
+ case '\n' :
+ case '\f' :
+ case '\t' :
+ break;
+ default :
+ throw new IllegalArgumentException(
+ "invalid permission: " + actions);
+ }
+ i--;
+ }
+
+ // point i at the location of the comma minus one (or -1).
+ i -= matchlen;
+ }
+
+ if (seencomma) {
+ throw new IllegalArgumentException("invalid permission: " +
+ actions);
+ }
+
+ return mask;
+ }
+
+ /**
+ * Parse filter string into a Filter object.
+ *
+ * @param filterString The filter string to parse.
+ * @return a Filter for this bundle. If the specified filterString is
+ * <code>null</code> or equals "*", then <code>null</code> is
+ * returned to indicate a wildcard.
+ * @throws IllegalArgumentException If the filter syntax is invalid.
+ */
+ private static Filter parseFilter(String filterString) {
+ if (filterString == null) {
+ return null;
+ }
+ filterString = filterString.trim();
+ if (filterString.equals("*")) {
+ return null;
+ }
+
+ try {
+ return FrameworkUtil.createFilter(filterString);
+ }
+ catch (InvalidSyntaxException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "invalid filter");
+ iae.initCause(e);
+ throw iae;
+ }
+ }
+
+ /**
+ * Determines if the specified permission is implied by this object. This
+ * method throws an exception if the specified permission was not
+ * constructed with a bundle.
+ *
+ * <p>
+ * This method returns <code>true</code> if the specified permission is an
+ * AdminPermission AND
+ * <ul>
+ * <li>this object's filter matches the specified permission's bundle ID,
+ * bundle symbolic name, bundle location and bundle signer distinguished
+ * name chain 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</code> 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</code> if the specified permission is implied by this
+ * object; <code>false</code> otherwise.
+ */
+ public boolean implies(Permission p) {
+ if (!(p instanceof AdminPermission)) {
+ return false;
+ }
+ AdminPermission requested = (AdminPermission) p;
+ if (bundle != null) {
+ return false;
+ }
+ // if requested permission has a filter, then it is an invalid argument
+ if (requested.filter != null) {
+ return false;
+ }
+ return implies0(requested, ACTION_NONE);
+ }
+
+ /**
+ * Internal implies method. Used by the implies and the permission
+ * collection implies methods.
+ *
+ * @param requested The requested AdminPermision which has already be
+ * validated as a proper argument. The requested AdminPermission must
+ * not have a filter expression.
+ * @param effective The effective actions with which to start.
+ * @return <code>true</code> if the specified permission is implied by this
+ * object; <code>false</code> otherwise.
+ */
+ boolean implies0(AdminPermission requested, int effective) {
+ /* check actions first - much faster */
+ effective |= action_mask;
+ final int desired = requested.action_mask;
+ if ((effective & desired) != desired) {
+ return false;
+ }
+
+ /* Get our filter */
+ Filter f = filter;
+ if (f == null) {
+ // it's "*"
+ return true;
+ }
+ /* is requested a wildcard filter? */
+ if (requested.bundle == null) {
+ return false;
+ }
+ Dictionary requestedProperties = requested.getProperties();
+ if (requestedProperties == null) {
+ /*
+ * If the requested properties are null, then we have detected a
+ * recursion getting the bundle location. So we return true to
+ * permit the bundle location request in the AdminPermission check
+ * up the stack to succeed.
+ */
+ return true;
+ }
+ return f.matchCase(requestedProperties);
+ }
+
+ /**
+ * Returns the canonical string representation of the
+ * <code>AdminPermission</code> actions.
+ *
+ * <p>
+ * Always returns present <code>AdminPermission</code> actions in the
+ * following order: <code>class</code>, <code>execute</code>,
+ * <code>extensionLifecycle</code>, <code>lifecycle</code>,
+ * <code>listener</code>, <code>metadata</code>, <code>resolve</code>,
+ * <code>resource</code>, <code>startlevel</code>, <code>context</code>.
+ *
+ * @return Canonical string representation of the
+ * <code>AdminPermission</code> actions.
+ */
+ public String getActions() {
+ String result = actions;
+ if (result == null) {
+ StringBuffer sb = new StringBuffer();
+
+ int mask = action_mask;
+ if ((mask & ACTION_CLASS) == ACTION_CLASS) {
+ sb.append(CLASS);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_EXECUTE) == ACTION_EXECUTE) {
+ sb.append(EXECUTE);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_EXTENSIONLIFECYCLE) == ACTION_EXTENSIONLIFECYCLE) {
+ sb.append(EXTENSIONLIFECYCLE);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_LIFECYCLE) == ACTION_LIFECYCLE) {
+ sb.append(LIFECYCLE);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_LISTENER) == ACTION_LISTENER) {
+ sb.append(LISTENER);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_METADATA) == ACTION_METADATA) {
+ sb.append(METADATA);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_RESOLVE) == ACTION_RESOLVE) {
+ sb.append(RESOLVE);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_RESOURCE) == ACTION_RESOURCE) {
+ sb.append(RESOURCE);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_STARTLEVEL) == ACTION_STARTLEVEL) {
+ sb.append(STARTLEVEL);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_CONTEXT) == ACTION_CONTEXT) {
+ sb.append(CONTEXT);
+ sb.append(',');
+ }
+
+ // remove trailing comma
+ if (sb.length() > 0) {
+ sb.setLength(sb.length() - 1);
+ }
+
+ actions = result = sb.toString();
+ }
+ return result;
+ }
+
+ /**
+ * Returns a new <code>PermissionCollection</code> object suitable for
+ * storing <code>AdminPermission</code>s.
+ *
+ * @return A new <code>PermissionCollection</code> object.
+ */
+ public PermissionCollection newPermissionCollection() {
+ return new AdminPermissionCollection();
+ }
+
+ /**
+ * Determines the equality of two <code>AdminPermission</code> objects.
+ *
+ * @param obj The object being compared for equality with this object.
+ * @return <code>true</code> if <code>obj</code> is equivalent to this
+ * <code>AdminPermission</code>; <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (!(obj instanceof AdminPermission)) {
+ return false;
+ }
+
+ AdminPermission ap = (AdminPermission) obj;
+
+ return (action_mask == ap.action_mask)
+ && ((bundle == ap.bundle) || ((bundle != null) && bundle
+ .equals(ap.bundle)))
+ && (filter == null ? ap.filter == null : filter
+ .equals(ap.filter));
+ }
+
+ /**
+ * Returns the hash code value for this object.
+ *
+ * @return Hash code value for this object.
+ */
+ public int hashCode() {
+ int h = 31 * 17 + getName().hashCode();
+ h = 31 * h + getActions().hashCode();
+ if (bundle != null) {
+ h = 31 * h + bundle.hashCode();
+ }
+ return h;
+ }
+
+ /**
+ * WriteObject is called to save the state of this permission object to a
+ * stream. The actions are serialized, and the superclass takes care of the
+ * name.
+ */
+ private synchronized void writeObject(java.io.ObjectOutputStream s)
+ throws IOException {
+ if (bundle != null) {
+ throw new NotSerializableException("cannot serialize");
+ }
+ // Write out the actions. The superclass takes care of the name
+ // call getActions to make sure actions field is initialized
+ if (actions == null)
+ getActions();
+ s.defaultWriteObject();
+ }
+
+ /**
+ * readObject is called to restore the state of this permission from a
+ * stream.
+ */
+ private synchronized void readObject(java.io.ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ // Read in the data, then initialize the transients
+ s.defaultReadObject();
+ setTransients(parseFilter(getName()), parseActions(actions));
+ }
+
+ /**
+ * Called by <code>implies0</code> on an AdminPermission which was
+ * constructed with a Bundle. This method loads a dictionary with the
+ * filter-matchable properties of this bundle. The dictionary is cached so
+ * this lookup only happens once.
+ *
+ * This method should only be called on an AdminPermission which was
+ * constructed with a bundle
+ *
+ * @return a dictionary of properties for this bundle
+ */
+ private Dictionary getProperties() {
+ Dictionary result = properties;
+ if (result != null) {
+ return result;
+ }
+ /*
+ * We may have recursed here due to the Bundle.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 == bundle) {
+ return null;
+ }
+ recurse.set(bundle);
+ try {
+ final Dictionary dict = new Hashtable(4);
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ dict.put("id", new Long(bundle.getBundleId()));
+ dict.put("location", bundle.getLocation());
+ String name = bundle.getSymbolicName();
+ if (name != null) {
+ dict.put("name", name);
+ }
+ SignerProperty signer = new SignerProperty(bundle);
+ if (signer.isBundleSigned()) {
+ dict.put("signer", signer);
+ }
+ return null;
+ }
+ });
+ return properties = dict;
+ }
+ finally {
+ recurse.set(null);
+ }
+ }
+}
+
+/**
+ * Stores a collection of <code>AdminPermission</code>s.
+ */
+final class AdminPermissionCollection extends PermissionCollection {
+ private static final long serialVersionUID = 3906372644575328048L;
+ /**
+ * Collection of permissions.
+ *
+ * @GuardedBy this
+ */
+ private transient Map permissions;
+
+ /**
+ * Boolean saying if "*" is in the collection.
+ *
+ * @serial
+ * @GuardedBy this
+ */
+ private boolean all_allowed;
+
+ /**
+ * Create an empty AdminPermissions object.
+ *
+ */
+ public AdminPermissionCollection() {
+ permissions = new HashMap();
+ }
+
+ /**
+ * Adds a permission to this permission collection.
+ *
+ * @param permission The <code>AdminPermission</code> object to add.
+ * @throws IllegalArgumentException If the specified permission is not an
+ * <code>AdminPermission</code> instance or was constructed with a
+ * Bundle object.
+ * @throws SecurityException If this <code>AdminPermissionCollection</code>
+ * object has been marked read-only.
+ */
+ public void add(Permission permission) {
+ if (!(permission instanceof AdminPermission)) {
+ throw new IllegalArgumentException("invalid permission: "
+ + permission);
+ }
+ if (isReadOnly()) {
+ throw new SecurityException("attempt to add a Permission to a "
+ + "readonly PermissionCollection");
+ }
+ final AdminPermission ap = (AdminPermission) permission;
+ if (ap.bundle != null) {
+ throw new IllegalArgumentException("cannot add to collection: "
+ + ap);
+ }
+ final String name = ap.getName();
+ synchronized (this) {
+ Map pc = permissions;
+ AdminPermission existing = (AdminPermission) pc.get(name);
+ if (existing != null) {
+ int oldMask = existing.action_mask;
+ int newMask = ap.action_mask;
+
+ if (oldMask != newMask) {
+ pc.put(name, new AdminPermission(existing.filter, oldMask
+ | newMask));
+ }
+ }
+ else {
+ pc.put(name, ap);
+ }
+ if (!all_allowed) {
+ if (name.equals("*")) {
+ all_allowed = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Determines if the specified permissions implies the permissions expressed
+ * in <code>permission</code>.
+ *
+ * @param permission The Permission object to compare with the
+ * <code>AdminPermission</code> objects in this collection.
+ * @return <code>true</code> if <code>permission</code> is implied by an
+ * <code>AdminPermission</code> in this collection,
+ * <code>false</code> otherwise.
+ */
+ public boolean implies(Permission permission) {
+ if (!(permission instanceof AdminPermission)) {
+ return false;
+ }
+
+ AdminPermission requested = (AdminPermission) permission;
+ // if requested permission has a filter, then it is an invalid argument
+ if (requested.filter != null) {
+ return false;
+ }
+ int effective = AdminPermission.ACTION_NONE;
+ Collection perms;
+ synchronized (this) {
+ Map pc = permissions;
+ // short circuit if the "*" Permission was added
+ if (all_allowed) {
+ AdminPermission ap = (AdminPermission) pc.get("*");
+ if (ap != null) {
+ effective |= ap.action_mask;
+ final int desired = requested.action_mask;
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ }
+ perms = pc.values();
+ }
+
+ // just iterate one by one
+ for (Iterator iter = perms.iterator(); iter.hasNext();) {
+ if (((AdminPermission) iter.next()).implies0(requested, effective)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an enumeration of all <code>AdminPermission</code> objects in the
+ * container.
+ *
+ * @return Enumeration of all <code>AdminPermission</code> objects.
+ */
+ public synchronized Enumeration elements() {
+ return Collections.enumeration(permissions.values());
+ }
+
+ /* serialization logic */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("permissions", Hashtable.class),
+ new ObjectStreamField("all_allowed", Boolean.TYPE) };
+
+ private synchronized void writeObject(ObjectOutputStream out)
+ throws IOException {
+ Hashtable hashtable = new Hashtable(permissions);
+ ObjectOutputStream.PutField pfields = out.putFields();
+ pfields.put("permissions", hashtable);
+ pfields.put("all_allowed", all_allowed);
+ out.writeFields();
+ }
+
+ private synchronized void readObject(java.io.ObjectInputStream in)
+ throws IOException,
+ ClassNotFoundException {
+ ObjectInputStream.GetField gfields = in.readFields();
+ Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+ permissions = new HashMap(hashtable);
+ all_allowed = gfields.get("all_allowed", false);
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/AllServiceListener.java b/framework/src/main/java/org/osgi/framework/AllServiceListener.java
new file mode 100644
index 0000000..688f51e
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/AllServiceListener.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) OSGi Alliance (2005, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * A <code>ServiceEvent</code> listener that does not filter based upon
+ * package wiring. <code>AllServiceListener</code> is a listener interface
+ * that may be implemented by a bundle developer. When a
+ * <code>ServiceEvent</code> is fired, it is synchronously delivered to an
+ * <code>AllServiceListener</code>. The Framework may deliver
+ * <code>ServiceEvent</code> objects to an <code>AllServiceListener</code>
+ * out of order and may concurrently call and/or reenter an
+ * <code>AllServiceListener</code>.
+ * <p>
+ * An <code>AllServiceListener</code> object is registered with the Framework
+ * using the <code>BundleContext.addServiceListener</code> method.
+ * <code>AllServiceListener</code> objects are called with a
+ * <code>ServiceEvent</code> object when a service is registered, modified, or
+ * is in the process of unregistering.
+ *
+ * <p>
+ * <code>ServiceEvent</code> object delivery to
+ * <code>AllServiceListener</code> objects is filtered by the filter specified
+ * when the listener was registered. If the Java Runtime Environment supports
+ * permissions, then additional filtering is done. <code>ServiceEvent</code>
+ * objects are only delivered to the listener if the bundle which defines the
+ * listener object's class has the appropriate <code>ServicePermission</code>
+ * to get the service using at least one of the named classes under which the
+ * service was registered.
+ *
+ * <p>
+ * Unlike normal <code>ServiceListener</code> objects,
+ * <code>AllServiceListener</code> objects receive all
+ * <code>ServiceEvent</code> objects regardless of whether the package source
+ * of the listening bundle is equal to the package source of the bundle that
+ * registered the service. This means that the listener may not be able to cast
+ * the service object to any of its corresponding service interfaces if the
+ * service object is retrieved.
+ *
+ * @see ServiceEvent
+ * @see ServicePermission
+ * @ThreadSafe
+ * @since 1.3
+ * @version $Revision: 5673 $
+ */
+
+public interface AllServiceListener extends ServiceListener {
+ // This is a marker interface
+}
diff --git a/framework/src/main/java/org/osgi/framework/Bundle.java b/framework/src/main/java/org/osgi/framework/Bundle.java
new file mode 100644
index 0000000..692bc5e
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/Bundle.java
@@ -0,0 +1,1194 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Map;
+
+/**
+ * An installed bundle in the Framework.
+ *
+ * <p>
+ * A <code>Bundle</code> object is the access point to define the lifecycle of
+ * an installed bundle. Each bundle installed in the OSGi environment must have
+ * an associated <code>Bundle</code> object.
+ *
+ * <p>
+ * A bundle must have a unique identity, a <code>long</code>, chosen by the
+ * Framework. This identity must not change during the lifecycle of a bundle,
+ * even when the bundle is updated. Uninstalling and then reinstalling the
+ * bundle must create a new unique identity.
+ *
+ * <p>
+ * A bundle can be in one of six states:
+ * <ul>
+ * <li>{@link #UNINSTALLED}
+ * <li>{@link #INSTALLED}
+ * <li>{@link #RESOLVED}
+ * <li>{@link #STARTING}
+ * <li>{@link #STOPPING}
+ * <li>{@link #ACTIVE}
+ * </ul>
+ * <p>
+ * Values assigned to these states have no specified ordering; they represent
+ * bit values that may be ORed together to determine if a bundle is in one of
+ * the valid states.
+ *
+ * <p>
+ * A bundle should only execute code when its state is one of
+ * <code>STARTING</code>,<code>ACTIVE</code>, or <code>STOPPING</code>.
+ * An <code>UNINSTALLED</code> bundle can not be set to another state; it is a
+ * zombie and can only be reached because references are kept somewhere.
+ *
+ * <p>
+ * The Framework is the only entity that is allowed to create
+ * <code>Bundle</code> objects, and these objects are only valid within the
+ * Framework that created them.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6906 $
+ */
+public interface Bundle {
+ /**
+ * The bundle is uninstalled and may not be used.
+ *
+ * <p>
+ * The <code>UNINSTALLED</code> state is only visible after a bundle is
+ * uninstalled; the bundle is in an unusable state but references to the
+ * <code>Bundle</code> object may still be available and used for
+ * introspection.
+ * <p>
+ * The value of <code>UNINSTALLED</code> is 0x00000001.
+ */
+ public static final int UNINSTALLED = 0x00000001;
+
+ /**
+ * The bundle is installed but not yet resolved.
+ *
+ * <p>
+ * A bundle is in the <code>INSTALLED</code> state when it has been
+ * installed in the Framework but is not or cannot be resolved.
+ * <p>
+ * This state is visible if the bundle's code dependencies are not resolved.
+ * The Framework may attempt to resolve an <code>INSTALLED</code> bundle's
+ * code dependencies and move the bundle to the <code>RESOLVED</code>
+ * state.
+ * <p>
+ * The value of <code>INSTALLED</code> is 0x00000002.
+ */
+ public static final int INSTALLED = 0x00000002;
+
+ /**
+ * The bundle is resolved and is able to be started.
+ *
+ * <p>
+ * A bundle is in the <code>RESOLVED</code> state when the Framework has
+ * successfully resolved the bundle's code dependencies. These dependencies
+ * include:
+ * <ul>
+ * <li>The bundle's class path from its {@link Constants#BUNDLE_CLASSPATH}
+ * Manifest header.
+ * <li>The bundle's package dependencies from its
+ * {@link Constants#EXPORT_PACKAGE} and {@link Constants#IMPORT_PACKAGE}
+ * Manifest headers.
+ * <li>The bundle's required bundle dependencies from its
+ * {@link Constants#REQUIRE_BUNDLE} Manifest header.
+ * <li>A fragment bundle's host dependency from its
+ * {@link Constants#FRAGMENT_HOST} Manifest header.
+ * </ul>
+ * <p>
+ * Note that the bundle is not active yet. A bundle must be put in the
+ * <code>RESOLVED</code> state before it can be started. The Framework may
+ * attempt to resolve a bundle at any time.
+ * <p>
+ * The value of <code>RESOLVED</code> is 0x00000004.
+ */
+ public static final int RESOLVED = 0x00000004;
+
+ /**
+ * The bundle is in the process of starting.
+ *
+ * <p>
+ * A bundle is in the <code>STARTING</code> state when its
+ * {@link #start(int) start} method is active. A bundle must be in this
+ * state when the bundle's {@link BundleActivator#start} is called. If the
+ * <code>BundleActivator.start</code> method completes without exception,
+ * then the bundle has successfully started and must move to the
+ * <code>ACTIVE</code> state.
+ * <p>
+ * If the bundle has a
+ * {@link Constants#ACTIVATION_LAZY lazy activation policy}, then the
+ * bundle may remain in this state for some time until the activation is
+ * triggered.
+ * <p>
+ * The value of <code>STARTING</code> is 0x00000008.
+ */
+ public static final int STARTING = 0x00000008;
+
+ /**
+ * The bundle is in the process of stopping.
+ *
+ * <p>
+ * A bundle is in the <code>STOPPING</code> state when its
+ * {@link #stop(int) stop} method is active. A bundle must be in this state
+ * when the bundle's {@link BundleActivator#stop} method is called. When the
+ * <code>BundleActivator.stop</code> method completes the bundle is
+ * stopped and must move to the <code>RESOLVED</code> state.
+ * <p>
+ * The value of <code>STOPPING</code> is 0x00000010.
+ */
+ public static final int STOPPING = 0x00000010;
+
+ /**
+ * The bundle is now running.
+ *
+ * <p>
+ * A bundle is in the <code>ACTIVE</code> state when it has been
+ * successfully started and activated.
+ * <p>
+ * The value of <code>ACTIVE</code> is 0x00000020.
+ */
+ public static final int ACTIVE = 0x00000020;
+
+ /**
+ * The bundle start operation is transient and the persistent autostart
+ * setting of the bundle is not modified.
+ *
+ * <p>
+ * This bit may be set when calling {@link #start(int)} to notify the
+ * framework that the autostart setting of the bundle must not be modified.
+ * If this bit is not set, then the autostart setting of the bundle is
+ * modified.
+ *
+ * @since 1.4
+ * @see #start(int)
+ */
+ public static final int START_TRANSIENT = 0x00000001;
+
+ /**
+ * The bundle start operation must activate the bundle according to the
+ * bundle's declared
+ * {@link Constants#BUNDLE_ACTIVATIONPOLICY activation policy}.
+ *
+ * <p>
+ * This bit may be set when calling {@link #start(int)} to notify the
+ * framework that the bundle must be activated using the bundle's declared
+ * activation policy.
+ *
+ * @since 1.4
+ * @see Constants#BUNDLE_ACTIVATIONPOLICY
+ * @see #start(int)
+ */
+ public static final int START_ACTIVATION_POLICY = 0x00000002;
+
+ /**
+ * The bundle stop is transient and the persistent autostart setting of the
+ * bundle is not modified.
+ *
+ * <p>
+ * This bit may be set when calling {@link #stop(int)} to notify the
+ * framework that the autostart setting of the bundle must not be modified.
+ * If this bit is not set, then the autostart setting of the bundle is
+ * modified.
+ *
+ * @since 1.4
+ * @see #stop(int)
+ */
+ public static final int STOP_TRANSIENT = 0x00000001;
+
+ /**
+ * Request that all certificates used to sign the bundle be returned.
+ *
+ * @since 1.5
+ * @see #getSignerCertificates(int)
+ */
+ public final static int SIGNERS_ALL = 1;
+
+ /**
+ * Request that only certificates used to sign the bundle that are trusted
+ * by the framework be returned.
+ *
+ * @since 1.5
+ * @see #getSignerCertificates(int)
+ */
+ public final static int SIGNERS_TRUSTED = 2;
+
+ /**
+ * Returns this bundle's current state.
+ *
+ * <p>
+ * A bundle can be in only one state at any time.
+ *
+ * @return An element of <code>UNINSTALLED</code>,<code>INSTALLED</code>,
+ * <code>RESOLVED</code>,<code>STARTING</code>,
+ * <code>STOPPING</code>,<code>ACTIVE</code>.
+ */
+ public int getState();
+
+ /**
+ * Starts this bundle.
+ *
+ * <p>
+ * If this bundle's state is <code>UNINSTALLED</code> then an
+ * <code>IllegalStateException</code> is thrown.
+ * <p>
+ * If the Framework implements the optional Start Level service and the
+ * current start level is less than this bundle's start level:
+ * <ul>
+ * <li>If the {@link #START_TRANSIENT} option is set, then a
+ * <code>BundleException</code> is thrown indicating this bundle cannot be
+ * started due to the Framework's current start level.
+ *
+ * <li>Otherwise, the Framework must set this bundle's persistent autostart
+ * setting to <em>Started with declared activation</em> if the
+ * {@link #START_ACTIVATION_POLICY} option is set or
+ * <em>Started with eager activation</em> if not set.
+ * </ul>
+ * <p>
+ * When the Framework's current start level becomes equal to or more than
+ * this bundle's start level, this bundle will be started.
+ * <p>
+ * Otherwise, the following steps are required to start this bundle:
+ * <ol>
+ * <li>If this bundle is in the process of being activated or deactivated
+ * then this method must wait for activation or deactivation to complete
+ * before continuing. If this does not occur in a reasonable time, a
+ * <code>BundleException</code> is thrown to indicate this bundle was unable
+ * to be started.
+ *
+ * <li>If this bundle's state is <code>ACTIVE</code> then this method
+ * returns immediately.
+ *
+ * <li>If the {@link #START_TRANSIENT} option is not set then set this
+ * bundle's autostart setting to <em>Started with declared activation</em>
+ * if the {@link #START_ACTIVATION_POLICY} option is set or
+ * <em>Started with eager activation</em> if not set. When the Framework is
+ * restarted and this bundle's autostart setting is not <em>Stopped</em>,
+ * this bundle must be automatically started.
+ *
+ * <li>If this bundle's state is not <code>RESOLVED</code>, an attempt is
+ * made to resolve this bundle. If the Framework cannot resolve this bundle,
+ * a <code>BundleException</code> is thrown.
+ *
+ * <li>If the {@link #START_ACTIVATION_POLICY} option is set and this
+ * bundle's declared activation policy is {@link Constants#ACTIVATION_LAZY
+ * lazy} then:
+ * <ul>
+ * <li>If this bundle's state is <code>STARTING</code> then this method
+ * returns immediately.
+ * <li>This bundle's state is set to <code>STARTING</code>.
+ * <li>A bundle event of type {@link BundleEvent#LAZY_ACTIVATION} is fired.
+ * <li>This method returns immediately and the remaining steps will be
+ * followed when this bundle's activation is later triggered.
+ * </ul>
+ * <i></i>
+ * <li>This bundle's state is set to <code>STARTING</code>.
+ *
+ * <li>A bundle event of type {@link BundleEvent#STARTING} is fired.
+ *
+ * <li>The {@link BundleActivator#start} method of this bundle's
+ * <code>BundleActivator</code>, if one is specified, is called. If the
+ * <code>BundleActivator</code> is invalid or throws an exception then:
+ * <ul>
+ * <li>This bundle's state is set to <code>STOPPING</code>.
+ * <li>A bundle event of type {@link BundleEvent#STOPPING} is fired.
+ * <li>Any services registered by this bundle must be unregistered.
+ * <li>Any services used by this bundle must be released.
+ * <li>Any listeners registered by this bundle must be removed.
+ * <li>This bundle's state is set to <code>RESOLVED</code>.
+ * <li>A bundle event of type {@link BundleEvent#STOPPED} is fired.
+ * <li>A <code>BundleException</code> is then thrown.
+ * </ul>
+ * <i></i>
+ * <li>If this bundle's state is <code>UNINSTALLED</code>, because this
+ * bundle was uninstalled while the <code>BundleActivator.start</code>
+ * method was running, a <code>BundleException</code> is thrown.
+ *
+ * <li>This bundle's state is set to <code>ACTIVE</code>.
+ *
+ * <li>A bundle event of type {@link BundleEvent#STARTED} is fired.
+ * </ol>
+ *
+ * <b>Preconditions </b>
+ * <ul>
+ * <li><code>getState()</code> in { <code>INSTALLED</code>,
+ * <code>RESOLVED</code> } or { <code>INSTALLED</code>,
+ * <code>RESOLVED</code>, <code>STARTING</code> } if this bundle has
+ * a lazy activation policy.
+ * </ul>
+ * <b>Postconditions, no exceptions thrown </b>
+ * <ul>
+ * <li>Bundle autostart setting is modified unless the
+ * {@link #START_TRANSIENT} option was set.
+ * <li><code>getState()</code> in { <code>ACTIVE</code> }
+ * unless the lazy activation policy was used.
+ * <li><code>BundleActivator.start()</code> has been called and did not
+ * throw an exception unless the lazy activation policy was used.
+ * </ul>
+ * <b>Postconditions, when an exception is thrown </b>
+ * <ul>
+ * <li>Depending on when the exception occurred, bundle autostart setting is
+ * modified unless the {@link #START_TRANSIENT} option was set.
+ * <li><code>getState()</code> not in { <code>STARTING</code>,
+ * <code>ACTIVE</code> }.
+ * </ul>
+ *
+ * @param options The options for starting this bundle. See
+ * {@link #START_TRANSIENT} and {@link #START_ACTIVATION_POLICY}. The
+ * Framework must ignore unrecognized options.
+ * @throws BundleException If this bundle could not be started. This could
+ * be because a code dependency could not be resolved or the
+ * specified <code>BundleActivator</code> could not be loaded or
+ * threw an exception or this bundle is a fragment.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @since 1.4
+ */
+ public void start(int options) throws BundleException;
+
+ /**
+ * Starts this bundle with no options.
+ *
+ * <p>
+ * This method performs the same function as calling <code>start(0)</code>.
+ *
+ * @throws BundleException If this bundle could not be started. This could
+ * be because a code dependency could not be resolved or the
+ * specified <code>BundleActivator</code> could not be loaded or
+ * threw an exception or this bundle is a fragment.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @see #start(int)
+ */
+ public void start() throws BundleException;
+
+ /**
+ * Stops this bundle.
+ *
+ * <p>
+ * The following steps are required to stop a bundle:
+ * <ol>
+ * <li>If this bundle's state is <code>UNINSTALLED</code> then an
+ * <code>IllegalStateException</code> is thrown.
+ *
+ * <li>If this bundle is in the process of being activated or deactivated
+ * then this method must wait for activation or deactivation to complete
+ * before continuing. If this does not occur in a reasonable time, a
+ * <code>BundleException</code> is thrown to indicate this bundle was unable
+ * to be stopped.
+ * <li>If the {@link #STOP_TRANSIENT} option is not set then then set this
+ * bundle's persistent autostart setting to to <em>Stopped</em>. When the
+ * Framework is restarted and this bundle's autostart setting is
+ * <em>Stopped</em>, this bundle must not be automatically started.
+ *
+ * <li>If this bundle's state is not <code>STARTING</code> or
+ * <code>ACTIVE</code> then this method returns immediately.
+ *
+ * <li>This bundle's state is set to <code>STOPPING</code>.
+ *
+ * <li>A bundle event of type {@link BundleEvent#STOPPING} is fired.
+ *
+ * <li>If this bundle's state was <code>ACTIVE</code> prior to setting the
+ * state to <code>STOPPING</code>, the {@link BundleActivator#stop} method
+ * of this bundle's <code>BundleActivator</code>, if one is specified, is
+ * called. If that method throws an exception, this method must continue to
+ * stop this bundle and a <code>BundleException</code> must be thrown after
+ * completion of the remaining steps.
+ *
+ * <li>Any services registered by this bundle must be unregistered.
+ * <li>Any services used by this bundle must be released.
+ * <li>Any listeners registered by this bundle must be removed.
+ *
+ * <li>If this bundle's state is <code>UNINSTALLED</code>, because this
+ * bundle was uninstalled while the <code>BundleActivator.stop</code> method
+ * was running, a <code>BundleException</code> must be thrown.
+ *
+ * <li>This bundle's state is set to <code>RESOLVED</code>.
+ *
+ * <li>A bundle event of type {@link BundleEvent#STOPPED} is fired.
+ * </ol>
+ *
+ * <b>Preconditions </b>
+ * <ul>
+ * <li><code>getState()</code> in { <code>ACTIVE</code> }.
+ * </ul>
+ * <b>Postconditions, no exceptions thrown </b>
+ * <ul>
+ * <li>Bundle autostart setting is modified unless the
+ * {@link #STOP_TRANSIENT} option was set.
+ * <li><code>getState()</code> not in { <code>ACTIVE</code>,
+ * <code>STOPPING</code> }.
+ * <li><code>BundleActivator.stop</code> has been called and did not throw
+ * an exception.
+ * </ul>
+ * <b>Postconditions, when an exception is thrown </b>
+ * <ul>
+ * <li>Bundle autostart setting is modified unless the
+ * {@link #STOP_TRANSIENT} option was set.
+ * </ul>
+ *
+ * @param options The options for stoping this bundle. See
+ * {@link #STOP_TRANSIENT}. The Framework must ignore unrecognized
+ * options.
+ * @throws BundleException If this bundle's <code>BundleActivator</code>
+ * threw an exception or this bundle is a fragment.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @since 1.4
+ */
+ public void stop(int options) throws BundleException;
+
+ /**
+ * Stops this bundle with no options.
+ *
+ * <p>
+ * This method performs the same function as calling <code>stop(0)</code>.
+ *
+ * @throws BundleException If this bundle's <code>BundleActivator</code>
+ * threw an exception or this bundle is a fragment.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @see #start(int)
+ */
+ public void stop() throws BundleException;
+
+ /**
+ * Updates this bundle from an <code>InputStream</code>.
+ *
+ * <p>
+ * If the specified <code>InputStream</code> is <code>null</code>, the
+ * Framework must create the <code>InputStream</code> from which to read the
+ * updated bundle by interpreting, in an implementation dependent manner,
+ * this bundle's {@link Constants#BUNDLE_UPDATELOCATION
+ * Bundle-UpdateLocation} Manifest header, if present, or this bundle's
+ * original location.
+ *
+ * <p>
+ * If this bundle's state is <code>ACTIVE</code>, it must be stopped before
+ * the update and started after the update successfully completes.
+ *
+ * <p>
+ * If this bundle has exported any packages that are imported by another
+ * bundle, these packages must not be updated. Instead, the previous package
+ * version must remain exported until the
+ * <code>PackageAdmin.refreshPackages</code> method has been has been called
+ * or the Framework is relaunched.
+ *
+ * <p>
+ * The following steps are required to update a bundle:
+ * <ol>
+ * <li>If this bundle's state is <code>UNINSTALLED</code> then an
+ * <code>IllegalStateException</code> is thrown.
+ *
+ * <li>If this bundle's state is <code>ACTIVE</code>, <code>STARTING</code>
+ * or <code>STOPPING</code>, this bundle is stopped as described in the
+ * <code>Bundle.stop</code> method. If <code>Bundle.stop</code> throws an
+ * exception, the exception is rethrown terminating the update.
+ *
+ * <li>The updated version of this bundle is read from the input stream and
+ * installed. If the Framework is unable to install the updated version of
+ * this bundle, the original version of this bundle must be restored and a
+ * <code>BundleException</code> must be thrown after completion of the
+ * remaining steps.
+ *
+ * <li>This bundle's state is set to <code>INSTALLED</code>.
+ *
+ * <li>If the updated version of this bundle was successfully installed, a
+ * bundle event of type {@link BundleEvent#UPDATED} is fired.
+ *
+ * <li>If this bundle's state was originally <code>ACTIVE</code>, the
+ * updated bundle is started as described in the <code>Bundle.start</code>
+ * method. If <code>Bundle.start</code> throws an exception, a Framework
+ * event of type {@link FrameworkEvent#ERROR} is fired containing the
+ * exception.
+ * </ol>
+ *
+ * <b>Preconditions </b>
+ * <ul>
+ * <li><code>getState()</code> not in { <code>UNINSTALLED</code>
+ * }.
+ * </ul>
+ * <b>Postconditions, no exceptions thrown </b>
+ * <ul>
+ * <li><code>getState()</code> in { <code>INSTALLED</code>,
+ * <code>RESOLVED</code>, <code>ACTIVE</code> }.
+ * <li>This bundle has been updated.
+ * </ul>
+ * <b>Postconditions, when an exception is thrown </b>
+ * <ul>
+ * <li><code>getState()</code> in { <code>INSTALLED</code>,
+ * <code>RESOLVED</code>, <code>ACTIVE</code> }.
+ * <li>Original bundle is still used; no update occurred.
+ * </ul>
+ *
+ * @param input The <code>InputStream</code> from which to read the new
+ * bundle or <code>null</code> to indicate the Framework must create
+ * the input stream from this bundle's
+ * {@link Constants#BUNDLE_UPDATELOCATION Bundle-UpdateLocation}
+ * Manifest header, if present, or this bundle's original location.
+ * The input stream must always be closed when this method completes,
+ * even if an exception is thrown.
+ * @throws BundleException If the input stream cannot be read or the update
+ * fails.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code> for both the current
+ * bundle and the updated bundle, and the Java Runtime Environment
+ * supports permissions.
+ * @see #stop()
+ * @see #start()
+ */
+ public void update(InputStream input) throws BundleException;
+
+ /**
+ * Updates this bundle.
+ *
+ * <p>
+ * This method performs the same function as calling
+ * {@link #update(InputStream)} with a <code>null</code> InputStream.
+ *
+ * @throws BundleException If the update fails.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code> for both the current
+ * bundle and the updated bundle, and the Java Runtime Environment
+ * supports permissions.
+ * @see #update(InputStream)
+ */
+ public void update() throws BundleException;
+
+ /**
+ * Uninstalls this bundle.
+ *
+ * <p>
+ * This method causes the Framework to notify other bundles that this bundle
+ * is being uninstalled, and then puts this bundle into the
+ * <code>UNINSTALLED</code> state. The Framework must remove any resources
+ * related to this bundle that it is able to remove.
+ *
+ * <p>
+ * If this bundle has exported any packages, the Framework must continue to
+ * make these packages available to their importing bundles until the
+ * <code>PackageAdmin.refreshPackages</code> method has been called or the
+ * Framework is relaunched.
+ *
+ * <p>
+ * The following steps are required to uninstall a bundle:
+ * <ol>
+ * <li>If this bundle's state is <code>UNINSTALLED</code> then an
+ * <code>IllegalStateException</code> is thrown.
+ *
+ * <li>If this bundle's state is <code>ACTIVE</code>, <code>STARTING</code>
+ * or <code>STOPPING</code>, this bundle is stopped as described in the
+ * <code>Bundle.stop</code> method. If <code>Bundle.stop</code> throws an
+ * exception, a Framework event of type {@link FrameworkEvent#ERROR} is
+ * fired containing the exception.
+ *
+ * <li>This bundle's state is set to <code>UNINSTALLED</code>.
+ *
+ * <li>A bundle event of type {@link BundleEvent#UNINSTALLED} is fired.
+ *
+ * <li>This bundle and any persistent storage area provided for this bundle
+ * by the Framework are removed.
+ * </ol>
+ *
+ * <b>Preconditions </b>
+ * <ul>
+ * <li><code>getState()</code> not in { <code>UNINSTALLED</code>
+ * }.
+ * </ul>
+ * <b>Postconditions, no exceptions thrown </b>
+ * <ul>
+ * <li><code>getState()</code> in { <code>UNINSTALLED</code>
+ * }.
+ * <li>This bundle has been uninstalled.
+ * </ul>
+ * <b>Postconditions, when an exception is thrown </b>
+ * <ul>
+ * <li><code>getState()</code> not in { <code>UNINSTALLED</code>
+ * }.
+ * <li>This Bundle has not been uninstalled.
+ * </ul>
+ *
+ * @throws BundleException If the uninstall failed. This can occur if
+ * another thread is attempting to change this bundle's state and
+ * does not complete in a timely manner.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+ * Runtime Environment supports permissions.
+ * @see #stop()
+ */
+ public void uninstall() throws BundleException;
+
+ /**
+ * Returns this bundle's Manifest headers and values. This method returns
+ * all the Manifest headers and values from the main section of this
+ * bundle's Manifest file; that is, all lines prior to the first blank line.
+ *
+ * <p>
+ * Manifest header names are case-insensitive. The methods of the returned
+ * <code>Dictionary</code> object must operate on header names in a
+ * case-insensitive manner.
+ *
+ * If a Manifest header value starts with "%", it must be
+ * localized according to the default locale. If no localization is found
+ * for a header value, the header value without the leading "%" is
+ * returned.
+ *
+ * <p>
+ * For example, the following Manifest headers and values are included if
+ * they are present in the Manifest file:
+ *
+ * <pre>
+ * Bundle-Name
+ * Bundle-Vendor
+ * Bundle-Version
+ * Bundle-Description
+ * Bundle-DocURL
+ * Bundle-ContactAddress
+ * </pre>
+ *
+ * <p>
+ * This method must continue to return Manifest header information while
+ * this bundle is in the <code>UNINSTALLED</code> state.
+ *
+ * @return A <code>Dictionary</code> object containing this bundle's
+ * Manifest headers and values.
+ * @throws SecurityException If the caller does not have the
+ * appropriate <code>AdminPermission[this,METADATA]</code>, and
+ * the Java Runtime Environment supports permissions.
+ * @see Constants#BUNDLE_LOCALIZATION
+ */
+ public Dictionary/* <String,String> */getHeaders();
+
+ /**
+ * Returns this bundle's unique identifier. This bundle is assigned a unique
+ * identifier by the Framework when it was installed in the OSGi
+ * environment.
+ *
+ * <p>
+ * A bundle's unique identifier has the following attributes:
+ * <ul>
+ * <li>Is unique and persistent.
+ * <li>Is a <code>long</code>.
+ * <li>Its value is not reused for another bundle, even after a bundle is
+ * uninstalled.
+ * <li>Does not change while a bundle remains installed.
+ * <li>Does not change when a bundle is updated.
+ * </ul>
+ *
+ * <p>
+ * This method must continue to return this bundle's unique identifier while
+ * this bundle is in the <code>UNINSTALLED</code> state.
+ *
+ * @return The unique identifier of this bundle.
+ */
+ public long getBundleId();
+
+ /**
+ * Returns this bundle's location identifier.
+ *
+ * <p>
+ * The location identifier is the location passed to
+ * <code>BundleContext.installBundle</code> when a bundle is installed.
+ * The location identifier does not change while this bundle remains
+ * installed, even if this bundle is updated.
+ *
+ * <p>
+ * This method must continue to return this bundle's location identifier
+ * while this bundle is in the <code>UNINSTALLED</code> state.
+ *
+ * @return The string representation of this bundle's location identifier.
+ * @throws SecurityException If the caller does not have the
+ * appropriate <code>AdminPermission[this,METADATA]</code>, and
+ * the Java Runtime Environment supports permissions.
+ */
+ public String getLocation();
+
+ /**
+ * Returns this bundle's <code>ServiceReference</code> list for all
+ * services it has registered or <code>null</code> if this bundle has no
+ * registered services.
+ *
+ * <p>
+ * If the Java runtime supports permissions, a <code>ServiceReference</code>
+ * object to a service is included in the returned list only if the caller
+ * has the <code>ServicePermission</code> to get the service using at
+ * least one of the named classes the service was registered under.
+ *
+ * <p>
+ * The list is valid at the time of the call to this method, however, as the
+ * Framework is a very dynamic environment, services can be modified or
+ * unregistered at anytime.
+ *
+ * @return An array of <code>ServiceReference</code> objects or
+ * <code>null</code>.
+ * @throws IllegalStateException If this bundle has been
+ * uninstalled.
+ * @see ServiceRegistration
+ * @see ServiceReference
+ * @see ServicePermission
+ */
+ public ServiceReference[] getRegisteredServices();
+
+ /**
+ * Returns this bundle's <code>ServiceReference</code> list for all
+ * services it is using or returns <code>null</code> if this bundle is not
+ * using any services. A bundle is considered to be using a service if its
+ * use count for that service is greater than zero.
+ *
+ * <p>
+ * If the Java Runtime Environment supports permissions, a
+ * <code>ServiceReference</code> object to a service is included in the
+ * returned list only if the caller has the <code>ServicePermission</code>
+ * to get the service using at least one of the named classes the service
+ * was registered under.
+ * <p>
+ * The list is valid at the time of the call to this method, however, as the
+ * Framework is a very dynamic environment, services can be modified or
+ * unregistered at anytime.
+ *
+ * @return An array of <code>ServiceReference</code> objects or
+ * <code>null</code>.
+ * @throws IllegalStateException If this bundle has been
+ * uninstalled.
+ * @see ServiceReference
+ * @see ServicePermission
+ */
+ public ServiceReference[] getServicesInUse();
+
+ /**
+ * Determines if this bundle has the specified permissions.
+ *
+ * <p>
+ * If the Java Runtime Environment does not support permissions, this method
+ * always returns <code>true</code>.
+ * <p>
+ * <code>permission</code> is of type <code>Object</code> to avoid
+ * referencing the <code>java.security.Permission</code> class directly.
+ * This is to allow the Framework to be implemented in Java environments
+ * which do not support permissions.
+ *
+ * <p>
+ * If the Java Runtime Environment does support permissions, this bundle and
+ * all its resources including embedded JAR files, belong to the same
+ * <code>java.security.ProtectionDomain</code>; that is, they must share
+ * the same set of permissions.
+ *
+ * @param permission The permission to verify.
+ * @return <code>true</code> if this bundle has the specified permission
+ * or the permissions possessed by this bundle imply the specified
+ * permission; <code>false</code> if this bundle does not have the
+ * specified permission or <code>permission</code> is not an
+ * <code>instanceof</code> <code>java.security.Permission</code>.
+ * @throws IllegalStateException If this bundle has been
+ * uninstalled.
+ */
+ public boolean hasPermission(Object permission);
+
+ /**
+ * Find the specified resource from this bundle's class loader.
+ *
+ * This bundle's class loader is called to search for the specified
+ * resource. If this bundle's state is <code>INSTALLED</code>, this method
+ * must attempt to resolve this bundle before attempting to get the
+ * specified resource. If this bundle cannot be resolved, then only this
+ * bundle must be searched for the specified resource. Imported packages
+ * cannot be searched when this bundle has not been resolved. If this bundle
+ * is a fragment bundle then <code>null</code> is returned.
+ * <p>
+ * Note: Jar and zip files are not required to include directory entries.
+ * URLs to directory entries will not be returned if the bundle contents do
+ * not contain directory entries.
+ *
+ * @param name The name of the resource. See
+ * <code>ClassLoader.getResource</code> for a description of the
+ * format of a resource name.
+ * @return A URL to the named resource, or <code>null</code> if the resource
+ * could not be found or if this bundle is a fragment bundle or if
+ * the caller does not have the appropriate
+ * <code>AdminPermission[this,RESOURCE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been uninstalled.
+ * @see #getEntry
+ * @see #findEntries
+ * @since 1.1
+ */
+ public URL getResource(String name);
+
+ /**
+ * Returns this bundle's Manifest headers and values localized to the
+ * specified locale.
+ *
+ * <p>
+ * This method performs the same function as
+ * <code>Bundle.getHeaders()</code> except the manifest header values are
+ * localized to the specified locale.
+ *
+ * <p>
+ * If a Manifest header value starts with "%", it must be
+ * localized according to the specified locale. If a locale is specified and
+ * cannot be found, then the header values must be returned using the
+ * default locale. Localizations are searched for in the following order:
+ *
+ * <pre>
+ * bn + "_" + Ls + "_" + Cs + "_" + Vs
+ * bn + "_" + Ls + "_" + Cs
+ * bn + "_" + Ls
+ * bn + "_" + Ld + "_" + Cd + "_" + Vd
+ * bn + "_" + Ld + "_" + Cd
+ * bn + "_" + Ld
+ * bn
+ * </pre>
+ *
+ * Where <code>bn</code> is this bundle's localization basename,
+ * <code>Ls</code>, <code>Cs</code> and <code>Vs</code> are the
+ * specified locale (language, country, variant) and <code>Ld</code>,
+ * <code>Cd</code> and <code>Vd</code> are the default locale (language,
+ * country, variant).
+ *
+ * If <code>null</code> is specified as the locale string, the header
+ * values must be localized using the default locale. If the empty string
+ * ("") is specified as the locale string, the header values must
+ * not be localized and the raw (unlocalized) header values, including any
+ * leading "%", must be returned. If no localization is found for
+ * a header value, the header value without the leading "%" is
+ * returned.
+ *
+ * <p>
+ * This method must continue to return Manifest header information while
+ * this bundle is in the <code>UNINSTALLED</code> state, however the
+ * header values must only be available in the raw and default locale
+ * values.
+ *
+ * @param locale The locale name into which the header values are to be
+ * localized. If the specified locale is <code>null</code> then the
+ * locale returned by <code>java.util.Locale.getDefault</code> is
+ * used. If the specified locale is the empty string, this method
+ * will return the raw (unlocalized) manifest headers including any
+ * leading "%".
+ * @return A <code>Dictionary</code> object containing this bundle's
+ * Manifest headers and values.
+ * @throws SecurityException If the caller does not have the
+ * appropriate <code>AdminPermission[this,METADATA]</code>, and
+ * the Java Runtime Environment supports permissions.
+ * @see #getHeaders()
+ * @see Constants#BUNDLE_LOCALIZATION
+ * @since 1.3
+ */
+ public Dictionary/* <String,String> */getHeaders(String locale);
+
+ /**
+ * Returns the symbolic name of this bundle as specified by its
+ * <code>Bundle-SymbolicName</code> manifest header. The bundle symbolic
+ * name together with a version must identify a unique bundle. The bundle
+ * symbolic name should be based on the reverse domain name naming
+ * convention like that used for java packages.
+ *
+ * <p>
+ * This method must continue to return this bundle's symbolic name while
+ * this bundle is in the <code>UNINSTALLED</code> state.
+ *
+ * @return The symbolic name of this bundle or <code>null</code> if this
+ * bundle does not have a symbolic name.
+ * @since 1.3
+ */
+ public String getSymbolicName();
+
+ /**
+ * Loads the specified class using this bundle's class loader.
+ *
+ * <p>
+ * If this bundle is a fragment bundle then this method must throw a
+ * <code>ClassNotFoundException</code>.
+ *
+ * <p>
+ * If this bundle's state is <code>INSTALLED</code>, this method must
+ * attempt to resolve this bundle before attempting to load the class.
+ *
+ * <p>
+ * If this bundle cannot be resolved, a Framework event of type
+ * {@link FrameworkEvent#ERROR} is fired containing a
+ * <code>BundleException</code> with details of the reason this bundle
+ * could not be resolved. This method must then throw a
+ * <code>ClassNotFoundException</code>.
+ *
+ * <p>
+ * If this bundle's state is <code>UNINSTALLED</code>, then an
+ * <code>IllegalStateException</code> is thrown.
+ *
+ * @param name The name of the class to load.
+ * @return The Class object for the requested class.
+ * @throws ClassNotFoundException If no such class can be found or
+ * if this bundle is a fragment bundle or if the caller does not
+ * have the appropriate <code>AdminPermission[this,CLASS]</code>,
+ * and the Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been
+ * uninstalled.
+ * @since 1.3
+ */
+ public Class loadClass(String name) throws ClassNotFoundException;
+
+ /**
+ * Find the specified resources from this bundle's class loader.
+ *
+ * This bundle's class loader is called to search for the specified
+ * resources. If this bundle's state is <code>INSTALLED</code>, this method
+ * must attempt to resolve this bundle before attempting to get the
+ * specified resources. If this bundle cannot be resolved, then only this
+ * bundle must be searched for the specified resources. Imported packages
+ * cannot be searched when a bundle has not been resolved. If this bundle is
+ * a fragment bundle then <code>null</code> is returned.
+ * <p>
+ * Note: Jar and zip files are not required to include directory entries.
+ * URLs to directory entries will not be returned if the bundle contents do
+ * not contain directory entries.
+ *
+ * @param name The name of the resource. See
+ * <code>ClassLoader.getResources</code> for a description of the
+ * format of a resource name.
+ * @return An enumeration of URLs to the named resources, or
+ * <code>null</code> if the resource could not be found or if this
+ * bundle is a fragment bundle or if the caller does not have the
+ * appropriate <code>AdminPermission[this,RESOURCE]</code>, and the
+ * Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been uninstalled.
+ * @throws IOException If there is an I/O error.
+ * @since 1.3
+ */
+ public Enumeration/* <URL> */getResources(String name) throws IOException;
+
+ /**
+ * Returns an Enumeration of all the paths (<code>String</code> objects)
+ * to entries within this bundle whose longest sub-path matches the
+ * specified path. This bundle's class loader is not used to search for
+ * entries. Only the contents of this bundle are searched.
+ * <p>
+ * The specified path is always relative to the root of this bundle and may
+ * begin with a "/". A path value of "/" indicates the
+ * root of this bundle.
+ * <p>
+ * Returned paths indicating subdirectory paths end with a "/".
+ * The returned paths are all relative to the root of this bundle and must
+ * not begin with "/".
+ * <p>
+ * Note: Jar and zip files are not required to include directory entries.
+ * Paths to directory entries will not be returned if the bundle contents do
+ * not contain directory entries.
+ *
+ * @param path The path name for which to return entry paths.
+ * @return An Enumeration of the entry paths (<code>String</code>
+ * objects) or <code>null</code> if no entry could be found or if
+ * the caller does not have the appropriate
+ * <code>AdminPermission[this,RESOURCE]</code> and the Java
+ * Runtime Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been
+ * uninstalled.
+ * @since 1.3
+ */
+ public Enumeration/* <String> */getEntryPaths(String path);
+
+ /**
+ * Returns a URL to the entry at the specified path in this bundle. This
+ * bundle's class loader is not used to search for the entry. Only the
+ * contents of this bundle are searched for the entry.
+ * <p>
+ * The specified path is always relative to the root of this bundle and may
+ * begin with "/". A path value of "/" indicates the
+ * root of this bundle.
+ * <p>
+ * Note: Jar and zip files are not required to include directory entries.
+ * URLs to directory entries will not be returned if the bundle contents do
+ * not contain directory entries.
+ *
+ * @param path The path name of the entry.
+ * @return A URL to the entry, or <code>null</code> if no entry could be
+ * found or if the caller does not have the appropriate
+ * <code>AdminPermission[this,RESOURCE]</code> and the Java
+ * Runtime Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been
+ * uninstalled.
+ * @since 1.3
+ */
+ public URL getEntry(String path);
+
+ /**
+ * Returns the time when this bundle was last modified. A bundle is
+ * considered to be modified when it is installed, updated or uninstalled.
+ *
+ * <p>
+ * The time value is the number of milliseconds since January 1, 1970,
+ * 00:00:00 GMT.
+ *
+ * @return The time when this bundle was last modified.
+ * @since 1.3
+ */
+ public long getLastModified();
+
+ /**
+ * Returns entries in this bundle and its attached fragments. This bundle's
+ * class loader is not used to search for entries. Only the contents of this
+ * bundle and its attached fragments are searched for the specified entries.
+ *
+ * If this bundle's state is <code>INSTALLED</code>, this method must
+ * attempt to resolve this bundle before attempting to find entries.
+ *
+ * <p>
+ * This method is intended to be used to obtain configuration, setup,
+ * localization and other information from this bundle. This method takes
+ * into account that the "contents" of this bundle can be extended
+ * with fragments. This "bundle space" is not a namespace with
+ * unique members; the same entry name can be present multiple times. This
+ * method therefore returns an enumeration of URL objects. These URLs can
+ * come from different JARs but have the same path name. This method can
+ * either return only entries in the specified path or recurse into
+ * subdirectories returning entries in the directory tree beginning at the
+ * specified path. Fragments can be attached after this bundle is resolved,
+ * possibly changing the set of URLs returned by this method. If this bundle
+ * is not resolved, only the entries in the JAR file of this bundle are
+ * returned.
+ * <p>
+ * Examples:
+ *
+ * <pre>
+ * // List all XML files in the OSGI-INF directory and below
+ * Enumeration e = b.findEntries("OSGI-INF", "*.xml", true);
+ *
+ * // Find a specific localization file
+ * Enumeration e = b
+ * .findEntries("OSGI-INF/l10n", "bundle_nl_DU.properties", false);
+ * if (e.hasMoreElements())
+ * return (URL) e.nextElement();
+ * </pre>
+ *
+ * <p>
+ * Note: Jar and zip files are not required to include directory entries.
+ * URLs to directory entries will not be returned if the bundle contents do
+ * not contain directory entries.
+ *
+ * @param path The path name in which to look. The path is always relative
+ * to the root of this bundle and may begin with "/". A
+ * path value of "/" indicates the root of this bundle.
+ * @param filePattern The file name pattern for selecting entries in the
+ * specified path. The pattern is only matched against the last
+ * element of the entry path. If the entry is a directory then the
+ * trailing "/" is not used for pattern matching. Substring
+ * matching is supported, as specified in the Filter specification,
+ * using the wildcard character ("*"). If null is
+ * specified, this is equivalent to "*" and matches all
+ * files.
+ * @param recurse If <code>true</code>, recurse into subdirectories.
+ * Otherwise only return entries from the specified path.
+ * @return An enumeration of URL objects for each matching entry, or
+ * <code>null</code> if an entry could not be found or if the caller
+ * does not have the appropriate
+ * <code>AdminPermission[this,RESOURCE]</code>, and the Java Runtime
+ * Environment supports permissions. The URLs are sorted such that
+ * entries from this bundle are returned first followed by the
+ * entries from attached fragments in ascending bundle id order. If
+ * this bundle is a fragment, then only matching entries in this
+ * fragment are returned.
+ * @throws IllegalStateException If this bundle has been uninstalled.
+ * @since 1.3
+ */
+ public Enumeration/* <URL> */findEntries(String path, String filePattern,
+ boolean recurse);
+
+ /**
+ * Returns this bundle's {@link BundleContext}. The returned
+ * <code>BundleContext</code> can be used by the caller to act on behalf
+ * of this bundle.
+ *
+ * <p>
+ * If this bundle is not in the {@link #STARTING}, {@link #ACTIVE}, or
+ * {@link #STOPPING} states or this bundle is a fragment bundle, then this
+ * bundle has no valid <code>BundleContext</code>. This method will
+ * return <code>null</code> if this bundle has no valid
+ * <code>BundleContext</code>.
+ *
+ * @return A <code>BundleContext</code> for this bundle or
+ * <code>null</code> if this bundle has no valid
+ * <code>BundleContext</code>.
+ * @throws SecurityException If the caller does not have the
+ * appropriate <code>AdminPermission[this,CONTEXT]</code>, and
+ * the Java Runtime Environment supports permissions.
+ * @since 1.4
+ */
+ public BundleContext getBundleContext();
+
+ /**
+ * Return the certificates for the signers of this bundle and the
+ * certificate chains for those signers.
+ *
+ * @param signersType If {@link #SIGNERS_ALL} is specified, then information
+ * on all signers of this bundle is returned. If
+ * {@link #SIGNERS_TRUSTED} is specified, then only information on
+ * the signers of this bundle trusted by the framework is returned.
+ * @return The <code>X509Certificate</code>s for the signers of this bundle
+ * and the <code>X509Certificate</code> chains for those signers.
+ * The keys of the <code>Map</code> are the
+ * <code>X509Certificate</code>s of the signers of this bundle. The
+ * value for a key is a <code>List</code> containing the
+ * <code>X509Certificate</code> chain for the signer. The first item
+ * in the <code>List</code> is the signer's
+ * <code>X509Certificate</code> which is then followed by the rest
+ * of the <code>X509Certificate</code> chain. The returned
+ * <code>Map</code> will be empty if there are no signers. The
+ * returned <code>Map</code> is the property of the caller who is
+ * free to modify it.
+ * @throws IllegalArgumentException If the specified
+ * <code>signersType</code> is not {@link #SIGNERS_ALL} or
+ * {@link #SIGNERS_TRUSTED}.
+ * @since 1.5
+ */
+ public Map/* <X509Certificate, List<X509Certificate>> */getSignerCertificates(
+ int signersType);
+
+ /**
+ * Returns the version of this bundle as specified by its
+ * <code>Bundle-Version</code> manifest header. If this bundle does not have a
+ * specified version then {@link Version#emptyVersion} is returned.
+ *
+ * <p>
+ * This method must continue to return this bundle's version while
+ * this bundle is in the <code>UNINSTALLED</code> state.
+ *
+ * @return The version of this bundle.
+ * @since 1.5
+ */
+ public Version getVersion();
+}
diff --git a/framework/src/main/java/org/osgi/framework/BundleActivator.java b/framework/src/main/java/org/osgi/framework/BundleActivator.java
new file mode 100644
index 0000000..56660b1
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/BundleActivator.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * Customizes the starting and stopping of a bundle.
+ * <p>
+ * <code>BundleActivator</code> is an interface that may be implemented when a
+ * bundle is started or stopped. The Framework can create instances of a
+ * bundle's <code>BundleActivator</code> as required. If an instance's
+ * <code>BundleActivator.start</code> method executes successfully, it is
+ * guaranteed that the same instance's <code>BundleActivator.stop</code>
+ * method will be called when the bundle is to be stopped. The Framework must
+ * not concurrently call a <code>BundleActivator</code> object.
+ *
+ * <p>
+ * <code>BundleActivator</code> is specified through the
+ * <code>Bundle-Activator</code> Manifest header. A bundle can only specify a
+ * single <code>BundleActivator</code> in the Manifest file. Fragment bundles
+ * must not have a <code>BundleActivator</code>. The form of the Manifest
+ * header is:
+ *
+ * <p>
+ * <code>Bundle-Activator: <i>class-name</i></code>
+ *
+ * <p>
+ * where <code><i>class-name</i></code> is a fully qualified Java classname.
+ * <p>
+ * The specified <code>BundleActivator</code> class must have a public
+ * constructor that takes no parameters so that a <code>BundleActivator</code>
+ * object can be created by <code>Class.newInstance()</code>.
+ *
+ * @NotThreadSafe
+ * @version $Revision: 6361 $
+ */
+
+public interface BundleActivator {
+ /**
+ * Called when this bundle is started so the Framework can perform the
+ * bundle-specific activities necessary to start this bundle. This method
+ * can be used to register services or to allocate any resources that this
+ * bundle needs.
+ *
+ * <p>
+ * This method must complete and return to its caller in a timely manner.
+ *
+ * @param context The execution context of the bundle being started.
+ * @throws Exception If this method throws an exception, this
+ * bundle is marked as stopped and the Framework will remove this
+ * bundle's listeners, unregister all services registered by this
+ * bundle, and release all services used by this bundle.
+ */
+ public void start(BundleContext context) throws Exception;
+
+ /**
+ * Called when this bundle is stopped so the Framework can perform the
+ * bundle-specific activities necessary to stop the bundle. In general, this
+ * method should undo the work that the <code>BundleActivator.start</code>
+ * method started. There should be no active threads that were started by
+ * this bundle when this bundle returns. A stopped bundle must not call any
+ * Framework objects.
+ *
+ * <p>
+ * This method must complete and return to its caller in a timely manner.
+ *
+ * @param context The execution context of the bundle being stopped.
+ * @throws Exception If this method throws an exception, the
+ * bundle is still marked as stopped, and the Framework will remove
+ * the bundle's listeners, unregister all services registered by the
+ * bundle, and release all services used by the bundle.
+ */
+ public void stop(BundleContext context) throws Exception;
+}
diff --git a/framework/src/main/java/org/osgi/framework/BundleContext.java b/framework/src/main/java/org/osgi/framework/BundleContext.java
new file mode 100644
index 0000000..44b3801
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/BundleContext.java
@@ -0,0 +1,756 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Dictionary;
+
+/**
+ * A bundle's execution context within the Framework. The context is used to
+ * grant access to other methods so that this bundle can interact with the
+ * Framework.
+ *
+ * <p>
+ * <code>BundleContext</code> methods allow a bundle to:
+ * <ul>
+ * <li>Subscribe to events published by the Framework.
+ * <li>Register service objects with the Framework service registry.
+ * <li>Retrieve <code>ServiceReferences</code> from the Framework service
+ * registry.
+ * <li>Get and release service objects for a referenced service.
+ * <li>Install new bundles in the Framework.
+ * <li>Get the list of bundles installed in the Framework.
+ * <li>Get the {@link Bundle} object for a bundle.
+ * <li>Create <code>File</code> objects for files in a persistent storage
+ * area provided for the bundle by the Framework.
+ * </ul>
+ *
+ * <p>
+ * A <code>BundleContext</code> object will be created and provided to the
+ * bundle associated with this context when it is started using the
+ * {@link BundleActivator#start} method. The same <code>BundleContext</code>
+ * object will be passed to the bundle associated with this context when it is
+ * stopped using the {@link BundleActivator#stop} method. A
+ * <code>BundleContext</code> object is generally for the private use of its
+ * associated bundle and is not meant to be shared with other bundles in the
+ * OSGi environment.
+ *
+ * <p>
+ * The <code>Bundle</code> object associated with a <code>BundleContext</code>
+ * object is called the <em>context bundle</em>.
+ *
+ * <p>
+ * The <code>BundleContext</code> object is only valid during the execution of
+ * its context bundle; that is, during the period from when the context bundle
+ * is in the <code>STARTING</code>, <code>STOPPING</code>, and
+ * <code>ACTIVE</code> bundle states. If the <code>BundleContext</code>
+ * object is used subsequently, an <code>IllegalStateException</code> must be
+ * thrown. The <code>BundleContext</code> object must never be reused after
+ * its context bundle is stopped.
+ *
+ * <p>
+ * The Framework is the only entity that can create <code>BundleContext</code>
+ * objects and they are only valid within the Framework that created them.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6781 $
+ */
+
+public interface BundleContext {
+ /**
+ * Returns the value of the specified property. If the key is not found in
+ * the Framework properties, the system properties are then searched. The
+ * method returns <code>null</code> if the property is not found.
+ *
+ * <p>
+ * All bundles must have permission to read properties whose names start
+ * with "org.osgi.".
+ *
+ * @param key The name of the requested property.
+ * @return The value of the requested property, or <code>null</code> if the
+ * property is undefined.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>PropertyPermission</code> to read the property, and the
+ * Java Runtime Environment supports permissions.
+ */
+ public String getProperty(String key);
+
+ /**
+ * Returns the <code>Bundle</code> object associated with this
+ * <code>BundleContext</code>. This bundle is called the context bundle.
+ *
+ * @return The <code>Bundle</code> object associated with this
+ * <code>BundleContext</code>.
+ * @throws IllegalStateException If this BundleContext is no
+ * longer valid.
+ */
+ public Bundle getBundle();
+
+ /**
+ * Installs a bundle from the specified <code>InputStream</code> object.
+ *
+ * <p>
+ * If the specified <code>InputStream</code> is <code>null</code>, the
+ * Framework must create the <code>InputStream</code> from which to read the
+ * bundle by interpreting, in an implementation dependent manner, the
+ * specified <code>location</code>.
+ *
+ * <p>
+ * The specified <code>location</code> identifier will be used as the
+ * identity of the bundle. Every installed bundle is uniquely identified by
+ * its location identifier which is typically in the form of a URL.
+ *
+ * <p>
+ * The following steps are required to install a bundle:
+ * <ol>
+ * <li>If a bundle containing the same location identifier is already
+ * installed, the <code>Bundle</code> object for that bundle is returned.
+ *
+ * <li>The bundle's content is read from the input stream. If this fails, a
+ * {@link BundleException} is thrown.
+ *
+ * <li>The bundle's associated resources are allocated. The associated
+ * resources minimally consist of a unique identifier and a persistent
+ * storage area if the platform has file system support. If this step fails,
+ * a <code>BundleException</code> is thrown.
+ *
+ * <li>The bundle's state is set to <code>INSTALLED</code>.
+ *
+ * <li>A bundle event of type {@link BundleEvent#INSTALLED} is fired.
+ *
+ * <li>The <code>Bundle</code> object for the newly or previously installed
+ * bundle is returned.
+ * </ol>
+ *
+ * <b>Postconditions, no exceptions thrown </b>
+ * <ul>
+ * <li><code>getState()</code> in { <code>INSTALLED</code>,
+ * <code>RESOLVED</code> }.
+ * <li>Bundle has a unique ID.
+ * </ul>
+ * <b>Postconditions, when an exception is thrown </b>
+ * <ul>
+ * <li>Bundle is not installed and no trace of the bundle exists.
+ * </ul>
+ *
+ * @param location The location identifier of the bundle to install.
+ * @param input The <code>InputStream</code> object from which this bundle
+ * will be read or <code>null</code> to indicate the Framework must
+ * create the input stream from the specified location identifier.
+ * The input stream must always be closed when this method completes,
+ * even if an exception is thrown.
+ * @return The <code>Bundle</code> object of the installed bundle.
+ * @throws BundleException If the input stream cannot be read or the
+ * installation failed.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[installed bundle,LIFECYCLE]</code>, and the
+ * Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
+ */
+ public Bundle installBundle(String location, InputStream input)
+ throws BundleException;
+
+ /**
+ * Installs a bundle from the specified <code>location</code> identifier.
+ *
+ * <p>
+ * This method performs the same function as calling
+ * {@link #installBundle(String,InputStream)} with the specified
+ * <code>location</code> identifier and a <code>null</code> InputStream.
+ *
+ * @param location The location identifier of the bundle to install.
+ * @return The <code>Bundle</code> object of the installed bundle.
+ * @throws BundleException If the installation failed.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[installed bundle,LIFECYCLE]</code>, and the
+ * Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
+ * @see #installBundle(String, InputStream)
+ */
+ public Bundle installBundle(String location) throws BundleException;
+
+ /**
+ * Returns the bundle with the specified identifier.
+ *
+ * @param id The identifier of the bundle to retrieve.
+ * @return A <code>Bundle</code> object or <code>null</code> if the
+ * identifier does not match any installed bundle.
+ */
+ public Bundle getBundle(long id);
+
+ /**
+ * Returns a list of all installed bundles.
+ * <p>
+ * This method returns a list of all bundles installed in the OSGi
+ * environment at the time of the call to this method. However, since the
+ * Framework is a very dynamic environment, bundles can be installed or
+ * uninstalled at anytime.
+ *
+ * @return An array of <code>Bundle</code> objects, one object per
+ * installed bundle.
+ */
+ public Bundle[] getBundles();
+
+ /**
+ * Adds the specified <code>ServiceListener</code> object with the
+ * specified <code>filter</code> to the context bundle's list of
+ * listeners. See {@link Filter} for a description of the filter syntax.
+ * <code>ServiceListener</code> objects are notified when a service has a
+ * lifecycle state change.
+ *
+ * <p>
+ * If the context bundle's list of listeners already contains a listener
+ * <code>l</code> such that <code>(l==listener)</code>, then this
+ * method replaces that listener's filter (which may be <code>null</code>)
+ * with the specified one (which may be <code>null</code>).
+ *
+ * <p>
+ * The listener is called if the filter criteria is met. To filter based
+ * upon the class of the service, the filter should reference the
+ * {@link Constants#OBJECTCLASS} property. If <code>filter</code> is
+ * <code>null</code>, all services are considered to match the filter.
+ *
+ * <p>
+ * When using a <code>filter</code>, it is possible that the
+ * <code>ServiceEvent</code>s for the complete lifecycle of a service
+ * will not be delivered to the listener. For example, if the
+ * <code>filter</code> only matches when the property <code>x</code> has
+ * the value <code>1</code>, the listener will not be called if the
+ * service is registered with the property <code>x</code> not set to the
+ * value <code>1</code>. Subsequently, when the service is modified
+ * setting property <code>x</code> to the value <code>1</code>, the
+ * filter will match and the listener will be called with a
+ * <code>ServiceEvent</code> of type <code>MODIFIED</code>. Thus, the
+ * listener will not be called with a <code>ServiceEvent</code> of type
+ * <code>REGISTERED</code>.
+ *
+ * <p>
+ * If the Java Runtime Environment supports permissions, the
+ * <code>ServiceListener</code> object will be notified of a service event
+ * only if the bundle that is registering it has the
+ * <code>ServicePermission</code> to get the service using at least one of
+ * the named classes the service was registered under.
+ *
+ * @param listener The <code>ServiceListener</code> object to be added.
+ * @param filter The filter criteria.
+ * @throws InvalidSyntaxException If <code>filter</code> contains an
+ * invalid filter string that cannot be parsed.
+ * @throws IllegalStateException If this BundleContext is no
+ * longer valid.
+ * @see ServiceEvent
+ * @see ServiceListener
+ * @see ServicePermission
+ */
+ public void addServiceListener(ServiceListener listener, String filter)
+ throws InvalidSyntaxException;
+
+ /**
+ * Adds the specified <code>ServiceListener</code> object to the context
+ * bundle's list of listeners.
+ *
+ * <p>
+ * This method is the same as calling
+ * <code>BundleContext.addServiceListener(ServiceListener listener,
+ * String filter)</code>
+ * with <code>filter</code> set to <code>null</code>.
+ *
+ * @param listener The <code>ServiceListener</code> object to be added.
+ * @throws IllegalStateException If this BundleContext is no
+ * longer valid.
+ * @see #addServiceListener(ServiceListener, String)
+ */
+ public void addServiceListener(ServiceListener listener);
+
+ /**
+ * Removes the specified <code>ServiceListener</code> object from the
+ * context bundle's list of listeners.
+ *
+ * <p>
+ * If <code>listener</code> is not contained in this context bundle's list
+ * of listeners, this method does nothing.
+ *
+ * @param listener The <code>ServiceListener</code> to be removed.
+ * @throws IllegalStateException If this BundleContext is no
+ * longer valid.
+ */
+ public void removeServiceListener(ServiceListener listener);
+
+ /**
+ * Adds the specified <code>BundleListener</code> object to the context
+ * bundle's list of listeners if not already present. BundleListener objects
+ * are notified when a bundle has a lifecycle state change.
+ *
+ * <p>
+ * If the context bundle's list of listeners already contains a listener
+ * <code>l</code> such that <code>(l==listener)</code>, this method
+ * does nothing.
+ *
+ * @param listener The <code>BundleListener</code> to be added.
+ * @throws IllegalStateException If this BundleContext is no
+ * longer valid.
+ * @throws SecurityException If listener is a
+ * <code>SynchronousBundleListener</code> and the caller does not
+ * have the appropriate
+ * <code>AdminPermission[context bundle,LISTENER]</code>, and the
+ * Java Runtime Environment supports permissions.
+ * @see BundleEvent
+ * @see BundleListener
+ */
+ public void addBundleListener(BundleListener listener);
+
+ /**
+ * Removes the specified <code>BundleListener</code> object from the
+ * context bundle's list of listeners.
+ *
+ * <p>
+ * If <code>listener</code> is not contained in the context bundle's list
+ * of listeners, this method does nothing.
+ *
+ * @param listener The <code>BundleListener</code> object to be removed.
+ * @throws IllegalStateException If this BundleContext is no
+ * longer valid.
+ * @throws SecurityException If listener is a
+ * <code>SynchronousBundleListener</code> and the caller does not
+ * have the appropriate
+ * <code>AdminPermission[context bundle,LISTENER]</code>, and the
+ * Java Runtime Environment supports permissions.
+ */
+ public void removeBundleListener(BundleListener listener);
+
+ /**
+ * Adds the specified <code>FrameworkListener</code> object to the context
+ * bundle's list of listeners if not already present. FrameworkListeners are
+ * notified of general Framework events.
+ *
+ * <p>
+ * If the context bundle's list of listeners already contains a listener
+ * <code>l</code> such that <code>(l==listener)</code>, this method
+ * does nothing.
+ *
+ * @param listener The <code>FrameworkListener</code> object to be added.
+ * @throws IllegalStateException If this BundleContext is no
+ * longer valid.
+ * @see FrameworkEvent
+ * @see FrameworkListener
+ */
+ public void addFrameworkListener(FrameworkListener listener);
+
+ /**
+ * Removes the specified <code>FrameworkListener</code> object from the
+ * context bundle's list of listeners.
+ *
+ * <p>
+ * If <code>listener</code> is not contained in the context bundle's list
+ * of listeners, this method does nothing.
+ *
+ * @param listener The <code>FrameworkListener</code> object to be
+ * removed.
+ * @throws IllegalStateException If this BundleContext is no
+ * longer valid.
+ */
+ public void removeFrameworkListener(FrameworkListener listener);
+
+ /**
+ * Registers the specified service object with the specified properties
+ * under the specified class names into the Framework. A
+ * <code>ServiceRegistration</code> object is returned. The
+ * <code>ServiceRegistration</code> object is for the private use of the
+ * bundle registering the service and should not be shared with other
+ * bundles. The registering bundle is defined to be the context bundle.
+ * Other bundles can locate the service by using either the
+ * {@link #getServiceReferences} or {@link #getServiceReference} method.
+ *
+ * <p>
+ * A bundle can register a service object that implements the
+ * {@link ServiceFactory} interface to have more flexibility in providing
+ * service objects to other bundles.
+ *
+ * <p>
+ * The following steps are required to register a service:
+ * <ol>
+ * <li>If <code>service</code> is not a <code>ServiceFactory</code>, an
+ * <code>IllegalArgumentException</code> is thrown if <code>service</code>
+ * is not an <code>instanceof</code> all the specified class names.
+ * <li>The Framework adds the following service properties to the service
+ * properties from the specified <code>Dictionary</code> (which may be
+ * <code>null</code>): <br/>
+ * A property named {@link Constants#SERVICE_ID} identifying the
+ * registration number of the service <br/>
+ * A property named {@link Constants#OBJECTCLASS} containing all the
+ * specified classes. <br/>
+ * Properties with these names in the specified <code>Dictionary</code> will
+ * be ignored.
+ * <li>The service is added to the Framework service registry and may now be
+ * used by other bundles.
+ * <li>A service event of type {@link ServiceEvent#REGISTERED} is fired.
+ * <li>A <code>ServiceRegistration</code> object for this registration is
+ * returned.
+ * </ol>
+ *
+ * @param clazzes The class names under which the service can be located.
+ * The class names in this array will be stored in the service's
+ * properties under the key {@link Constants#OBJECTCLASS}.
+ * @param service The service object or a <code>ServiceFactory</code>
+ * object.
+ * @param properties The properties for this service. The keys in the
+ * properties object must all be <code>String</code> objects. See
+ * {@link Constants} for a list of standard service property keys.
+ * Changes should not be made to this object after calling this
+ * method. To update the service's properties the
+ * {@link ServiceRegistration#setProperties} method must be called.
+ * The set of properties may be <code>null</code> if the service has
+ * no properties.
+ * @return A <code>ServiceRegistration</code> object for use by the bundle
+ * registering the service to update the service's properties or to
+ * unregister the service.
+ * @throws IllegalArgumentException If one of the following is true:
+ * <ul>
+ * <li><code>service</code> is <code>null</code>. <li><code>service
+ * </code> is not a <code>ServiceFactory</code> object and is not an
+ * instance of all the named classes in <code>clazzes</code>. <li>
+ * <code>properties</code> contains case variants of the same key
+ * name.
+ * </ul>
+ * @throws SecurityException If the caller does not have the
+ * <code>ServicePermission</code> to register the service for all
+ * the named classes and the Java Runtime Environment supports
+ * permissions.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
+ * @see ServiceRegistration
+ * @see ServiceFactory
+ */
+ public ServiceRegistration registerService(String[] clazzes,
+ Object service, Dictionary properties);
+
+ /**
+ * Registers the specified service object with the specified properties
+ * under the specified class name with the Framework.
+ *
+ * <p>
+ * This method is otherwise identical to
+ * {@link #registerService(String[], Object, Dictionary)} and is provided as
+ * a convenience when <code>service</code> will only be registered under a
+ * single class name. Note that even in this case the value of the service's
+ * {@link Constants#OBJECTCLASS} property will be an array of string, rather
+ * than just a single string.
+ *
+ * @param clazz The class name under which the service can be located.
+ * @param service The service object or a <code>ServiceFactory</code>
+ * object.
+ * @param properties The properties for this service.
+ * @return A <code>ServiceRegistration</code> object for use by the bundle
+ * registering the service to update the service's properties or to
+ * unregister the service.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
+ * @see #registerService(String[], Object, Dictionary)
+ */
+ public ServiceRegistration registerService(String clazz, Object service,
+ Dictionary properties);
+
+ /**
+ * Returns an array of <code>ServiceReference</code> objects. The returned
+ * array of <code>ServiceReference</code> objects contains services that
+ * were registered under the specified class, match the specified filter
+ * expression, and the packages for the class names under which the services
+ * were registered match the context bundle's packages as defined in
+ * {@link ServiceReference#isAssignableTo(Bundle, String)}.
+ *
+ * <p>
+ * The list is valid at the time of the call to this method. However since
+ * the Framework is a very dynamic environment, services can be modified or
+ * unregistered at any time.
+ *
+ * <p>
+ * The specified <code>filter</code> expression is used to select the
+ * registered services whose service properties contain keys and values
+ * which satisfy the filter expression. See {@link Filter} for a description
+ * of the filter syntax. If the specified <code>filter</code> is
+ * <code>null</code>, all registered services are considered to match the
+ * filter. If the specified <code>filter</code> expression cannot be parsed,
+ * an {@link InvalidSyntaxException} will be thrown with a human readable
+ * message where the filter became unparsable.
+ *
+ * <p>
+ * The result is an array of <code>ServiceReference</code> objects for all
+ * services that meet all of the following conditions:
+ * <ul>
+ * <li>If the specified class name, <code>clazz</code>, is not
+ * <code>null</code>, the service must have been registered with the
+ * specified class name. The complete list of class names with which a
+ * service was registered is available from the service's
+ * {@link Constants#OBJECTCLASS objectClass} property.
+ * <li>If the specified <code>filter</code> is not <code>null</code>, the
+ * filter expression must match the service.
+ * <li>If the Java Runtime Environment supports permissions, the caller must
+ * have <code>ServicePermission</code> with the <code>GET</code> action for
+ * at least one of the class names under which the service was registered.
+ * <li>For each class name with which the service was registered, calling
+ * {@link ServiceReference#isAssignableTo(Bundle, String)} with the context
+ * bundle and the class name on the service's <code>ServiceReference</code>
+ * object must return <code>true</code>
+ * </ul>
+ *
+ * @param clazz The class name with which the service was registered or
+ * <code>null</code> for all services.
+ * @param filter The filter expression or <code>null</code> for all
+ * services.
+ * @return An array of <code>ServiceReference</code> objects or
+ * <code>null</code> if no services are registered which satisfy the
+ * search.
+ * @throws InvalidSyntaxException If the specified <code>filter</code>
+ * contains an invalid filter expression that cannot be parsed.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
+ */
+ public ServiceReference[] getServiceReferences(String clazz, String filter)
+ throws InvalidSyntaxException;
+
+ /**
+ * Returns an array of <code>ServiceReference</code> objects. The returned
+ * array of <code>ServiceReference</code> objects contains services that
+ * were registered under the specified class and match the specified filter
+ * expression.
+ *
+ * <p>
+ * The list is valid at the time of the call to this method. However since
+ * the Framework is a very dynamic environment, services can be modified or
+ * unregistered at any time.
+ *
+ * <p>
+ * The specified <code>filter</code> expression is used to select the
+ * registered services whose service properties contain keys and values
+ * which satisfy the filter expression. See {@link Filter} for a description
+ * of the filter syntax. If the specified <code>filter</code> is
+ * <code>null</code>, all registered services are considered to match the
+ * filter. If the specified <code>filter</code> expression cannot be parsed,
+ * an {@link InvalidSyntaxException} will be thrown with a human readable
+ * message where the filter became unparsable.
+ *
+ * <p>
+ * The result is an array of <code>ServiceReference</code> objects for all
+ * services that meet all of the following conditions:
+ * <ul>
+ * <li>If the specified class name, <code>clazz</code>, is not
+ * <code>null</code>, the service must have been registered with the
+ * specified class name. The complete list of class names with which a
+ * service was registered is available from the service's
+ * {@link Constants#OBJECTCLASS objectClass} property.
+ * <li>If the specified <code>filter</code> is not <code>null</code>, the
+ * filter expression must match the service.
+ * <li>If the Java Runtime Environment supports permissions, the caller must
+ * have <code>ServicePermission</code> with the <code>GET</code> action for
+ * at least one of the class names under which the service was registered.
+ * </ul>
+ *
+ * @param clazz The class name with which the service was registered or
+ * <code>null</code> for all services.
+ * @param filter The filter expression or <code>null</code> for all
+ * services.
+ * @return An array of <code>ServiceReference</code> objects or
+ * <code>null</code> if no services are registered which satisfy the
+ * search.
+ * @throws InvalidSyntaxException If the specified <code>filter</code>
+ * contains an invalid filter expression that cannot be parsed.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
+ * @since 1.3
+ */
+ public ServiceReference[] getAllServiceReferences(String clazz,
+ String filter) throws InvalidSyntaxException;
+
+ /**
+ * Returns a <code>ServiceReference</code> object for a service that
+ * implements and was registered under the specified class.
+ *
+ * <p>
+ * The returned <code>ServiceReference</code> object is valid at the time of
+ * the call to this method. However as the Framework is a very dynamic
+ * environment, services can be modified or unregistered at any time.
+ *
+ * <p>
+ * This method is the same as calling
+ * {@link BundleContext#getServiceReferences(String, String)} with a
+ * <code>null</code> filter expression. It is provided as a convenience for
+ * when the caller is interested in any service that implements the
+ * specified class.
+ * <p>
+ * If multiple such services exist, the service with the highest ranking (as
+ * specified in its {@link Constants#SERVICE_RANKING} property) is returned.
+ * <p>
+ * If there is a tie in ranking, the service with the lowest service ID (as
+ * specified in its {@link Constants#SERVICE_ID} property); that is, the
+ * service that was registered first is returned.
+ *
+ * @param clazz The class name with which the service was registered.
+ * @return A <code>ServiceReference</code> object, or <code>null</code> if
+ * no services are registered which implement the named class.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
+ * @see #getServiceReferences(String, String)
+ */
+ public ServiceReference getServiceReference(String clazz);
+
+ /**
+ * Returns the service object referenced by the specified
+ * <code>ServiceReference</code> object.
+ * <p>
+ * A bundle's use of a service is tracked by the bundle's use count of that
+ * service. Each time a service's service object is returned by
+ * {@link #getService(ServiceReference)} the context bundle's use count for
+ * that service is incremented by one. Each time the service is released by
+ * {@link #ungetService(ServiceReference)} the context bundle's use count
+ * for that service is decremented by one.
+ * <p>
+ * When a bundle's use count for a service drops to zero, the bundle should
+ * no longer use that service.
+ *
+ * <p>
+ * This method will always return <code>null</code> when the service
+ * associated with this <code>reference</code> has been unregistered.
+ *
+ * <p>
+ * The following steps are required to get the service object:
+ * <ol>
+ * <li>If the service has been unregistered, <code>null</code> is returned.
+ * <li>The context bundle's use count for this service is incremented by
+ * one.
+ * <li>If the context bundle's use count for the service is currently one
+ * and the service was registered with an object implementing the
+ * <code>ServiceFactory</code> interface, the
+ * {@link ServiceFactory#getService(Bundle, ServiceRegistration)} method is
+ * called to create a service object for the context bundle. This service
+ * object is cached by the Framework. While the context bundle's use count
+ * for the service is greater than zero, subsequent calls to get the
+ * services's service object for the context bundle will return the cached
+ * service object. <br>
+ * If the service object returned by the <code>ServiceFactory</code> object
+ * is not an <code>instanceof</code> all the classes named when the service
+ * was registered or the <code>ServiceFactory</code> object throws an
+ * exception, <code>null</code> is returned and a Framework event of type
+ * {@link FrameworkEvent#ERROR} containing a {@link ServiceException}
+ * describing the error is fired.
+ * <li>The service object for the service is returned.
+ * </ol>
+ *
+ * @param reference A reference to the service.
+ * @return A service object for the service associated with
+ * <code>reference</code> or <code>null</code> if the service is not
+ * registered, the service object returned by a
+ * <code>ServiceFactory</code> does not implement the classes under
+ * which it was registered or the <code>ServiceFactory</code> threw
+ * an exception.
+ * @throws SecurityException If the caller does not have the
+ * <code>ServicePermission</code> to get the service using at least
+ * one of the named classes the service was registered under and the
+ * Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this BundleContext is no
+ * longer valid.
+ * @throws IllegalArgumentException If the specified
+ * <code>ServiceReference</code> was not created by the same
+ * framework instance as this <code>BundleContext</code>.
+ * @see #ungetService(ServiceReference)
+ * @see ServiceFactory
+ */
+ public Object getService(ServiceReference reference);
+
+ /**
+ * Releases the service object referenced by the specified
+ * <code>ServiceReference</code> object. If the context bundle's use count
+ * for the service is zero, this method returns <code>false</code>.
+ * Otherwise, the context bundle's use count for the service is decremented
+ * by one.
+ *
+ * <p>
+ * The service's service object should no longer be used and all references
+ * to it should be destroyed when a bundle's use count for the service drops
+ * to zero.
+ *
+ * <p>
+ * The following steps are required to unget the service object:
+ * <ol>
+ * <li>If the context bundle's use count for the service is zero or the
+ * service has been unregistered, <code>false</code> is returned.
+ * <li>The context bundle's use count for this service is decremented by
+ * one.
+ * <li>If the context bundle's use count for the service is currently zero
+ * and the service was registered with a <code>ServiceFactory</code> object,
+ * the
+ * {@link ServiceFactory#ungetService(Bundle, ServiceRegistration, Object)}
+ * method is called to release the service object for the context bundle.
+ * <li><code>true</code> is returned.
+ * </ol>
+ *
+ * @param reference A reference to the service to be released.
+ * @return <code>false</code> if the context bundle's use count for the
+ * service is zero or if the service has been unregistered;
+ * <code>true</code> otherwise.
+ * @throws IllegalStateException If this BundleContext is no
+ * longer valid.
+ * @throws IllegalArgumentException If the specified
+ * <code>ServiceReference</code> was not created by the same
+ * framework instance as this <code>BundleContext</code>.
+ * @see #getService
+ * @see ServiceFactory
+ */
+ public boolean ungetService(ServiceReference reference);
+
+ /**
+ * Creates a <code>File</code> object for a file in the persistent storage
+ * area provided for the bundle by the Framework. This method will return
+ * <code>null</code> if the platform does not have file system support.
+ *
+ * <p>
+ * A <code>File</code> object for the base directory of the persistent
+ * storage area provided for the context bundle by the Framework can be
+ * obtained by calling this method with an empty string as
+ * <code>filename</code>.
+ *
+ * <p>
+ * If the Java Runtime Environment supports permissions, the Framework will
+ * ensure that the bundle has the <code>java.io.FilePermission</code> with
+ * actions <code>read</code>,<code>write</code>,<code>delete</code>
+ * for all files (recursively) in the persistent storage area provided for
+ * the context bundle.
+ *
+ * @param filename A relative name to the file to be accessed.
+ * @return A <code>File</code> object that represents the requested file
+ * or <code>null</code> if the platform does not have file system
+ * support.
+ * @throws IllegalStateException If this BundleContext is no
+ * longer valid.
+ */
+ public File getDataFile(String filename);
+
+ /**
+ * Creates a <code>Filter</code> object. This <code>Filter</code> object may
+ * be used to match a <code>ServiceReference</code> object or a
+ * <code>Dictionary</code> object.
+ *
+ * <p>
+ * If the filter cannot be parsed, an {@link InvalidSyntaxException} will be
+ * thrown with a human readable message where the filter became unparsable.
+ *
+ * @param filter The filter string.
+ * @return A <code>Filter</code> object encapsulating the filter string.
+ * @throws InvalidSyntaxException If <code>filter</code> contains an invalid
+ * filter string that cannot be parsed.
+ * @throws NullPointerException If <code>filter</code> is null.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
+ * @see "Framework specification for a description of the filter string syntax."
+ * @see FrameworkUtil#createFilter(String)
+ * @since 1.1
+ */
+ public Filter createFilter(String filter) throws InvalidSyntaxException;
+}
diff --git a/framework/src/main/java/org/osgi/framework/BundleEvent.java b/framework/src/main/java/org/osgi/framework/BundleEvent.java
new file mode 100644
index 0000000..7a8fb8d
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/BundleEvent.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.util.EventObject;
+
+/**
+ * An event from the Framework describing a bundle lifecycle change.
+ * <p>
+ * <code>BundleEvent</code> objects are delivered to
+ * <code>SynchronousBundleListener</code>s and <code>BundleListener</code>s
+ * when a change occurs in a bundle's lifecycle. A type code is used to identify
+ * the event type for future extendability.
+ *
+ * <p>
+ * OSGi Alliance reserves the right to extend the set of types.
+ *
+ * @Immutable
+ * @see BundleListener
+ * @see SynchronousBundleListener
+ * @version $Revision: 6542 $
+ */
+
+public class BundleEvent extends EventObject {
+ static final long serialVersionUID = 4080640865971756012L;
+ /**
+ * Bundle that had a change occur in its lifecycle.
+ */
+ private final Bundle bundle;
+
+ /**
+ * Type of bundle lifecycle change.
+ */
+ private final int type;
+
+ /**
+ * The bundle has been installed.
+ *
+ * @see BundleContext#installBundle(String)
+ */
+ public final static int INSTALLED = 0x00000001;
+
+ /**
+ * The bundle has been started.
+ * <p>
+ * The bundle's
+ * {@link BundleActivator#start(BundleContext) BundleActivator start} method
+ * has been executed if the bundle has a bundle activator class.
+ *
+ * @see Bundle#start()
+ */
+ public final static int STARTED = 0x00000002;
+
+ /**
+ * The bundle has been stopped.
+ * <p>
+ * The bundle's
+ * {@link BundleActivator#stop(BundleContext) BundleActivator stop} method
+ * has been executed if the bundle has a bundle activator class.
+ *
+ * @see Bundle#stop()
+ */
+ public final static int STOPPED = 0x00000004;
+
+ /**
+ * The bundle has been updated.
+ *
+ * @see Bundle#update()
+ */
+ public final static int UPDATED = 0x00000008;
+
+ /**
+ * The bundle has been uninstalled.
+ *
+ * @see Bundle#uninstall
+ */
+ public final static int UNINSTALLED = 0x00000010;
+
+ /**
+ * The bundle has been resolved.
+ *
+ * @see Bundle#RESOLVED
+ * @since 1.3
+ */
+ public final static int RESOLVED = 0x00000020;
+
+ /**
+ * The bundle has been unresolved.
+ *
+ * @see Bundle#INSTALLED
+ * @since 1.3
+ */
+ public final static int UNRESOLVED = 0x00000040;
+
+ /**
+ * The bundle is about to be activated.
+ * <p>
+ * The bundle's
+ * {@link BundleActivator#start(BundleContext) BundleActivator start} method
+ * is about to be called if the bundle has a bundle activator class. This
+ * event is only delivered to {@link SynchronousBundleListener}s. It is not
+ * delivered to <code>BundleListener</code>s.
+ *
+ * @see Bundle#start()
+ * @since 1.3
+ */
+ public final static int STARTING = 0x00000080;
+
+ /**
+ * The bundle is about to deactivated.
+ * <p>
+ * The bundle's
+ * {@link BundleActivator#stop(BundleContext) BundleActivator stop} method
+ * is about to be called if the bundle has a bundle activator class. This
+ * event is only delivered to {@link SynchronousBundleListener}s. It is not
+ * delivered to <code>BundleListener</code>s.
+ *
+ * @see Bundle#stop()
+ * @since 1.3
+ */
+ public final static int STOPPING = 0x00000100;
+
+ /**
+ * The bundle will be lazily activated.
+ * <p>
+ * The bundle has a {@link Constants#ACTIVATION_LAZY lazy activation policy}
+ * and is waiting to be activated. It is now in the
+ * {@link Bundle#STARTING STARTING} state and has a valid
+ * <code>BundleContext</code>. This event is only delivered to
+ * {@link SynchronousBundleListener}s. It is not delivered to
+ * <code>BundleListener</code>s.
+ *
+ * @since 1.4
+ */
+ public final static int LAZY_ACTIVATION = 0x00000200;
+
+ /**
+ * Creates a bundle event of the specified type.
+ *
+ * @param type The event type.
+ * @param bundle The bundle which had a lifecycle change.
+ */
+
+ public BundleEvent(int type, Bundle bundle) {
+ super(bundle);
+ this.bundle = bundle;
+ this.type = type;
+ }
+
+ /**
+ * Returns the bundle which had a lifecycle change. This bundle is the
+ * source of the event.
+ *
+ * @return The bundle that had a change occur in its lifecycle.
+ */
+ public Bundle getBundle() {
+ return bundle;
+ }
+
+ /**
+ * Returns the type of lifecyle event. The type values are:
+ * <ul>
+ * <li>{@link #INSTALLED}
+ * <li>{@link #RESOLVED}
+ * <li>{@link #LAZY_ACTIVATION}
+ * <li>{@link #STARTING}
+ * <li>{@link #STARTED}
+ * <li>{@link #STOPPING}
+ * <li>{@link #STOPPED}
+ * <li>{@link #UPDATED}
+ * <li>{@link #UNRESOLVED}
+ * <li>{@link #UNINSTALLED}
+ * </ul>
+ *
+ * @return The type of lifecycle event.
+ */
+
+ public int getType() {
+ return type;
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/BundleException.java b/framework/src/main/java/org/osgi/framework/BundleException.java
new file mode 100644
index 0000000..500d147
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/BundleException.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * A Framework exception used to indicate that a bundle lifecycle problem
+ * occurred.
+ *
+ * <p>
+ * A <code>BundleException</code> object is created by the Framework to denote
+ * an exception condition in the lifecycle of a bundle.
+ * <code>BundleException</code>s should not be created by bundle developers.
+ * A type code is used to identify the exception type for future extendability.
+ *
+ * <p>
+ * OSGi Alliance reserves the right to extend the set of types.
+ *
+ * <p>
+ * This exception conforms to the general purpose exception chaining mechanism.
+ *
+ * @version $Revision: 6083 $
+ */
+
+public class BundleException extends Exception {
+ static final long serialVersionUID = 3571095144220455665L;
+ /**
+ * Type of bundle exception.
+ *
+ * @since 1.5
+ */
+ private final int type;
+
+ /**
+ * No exception type is unspecified.
+ *
+ * @since 1.5
+ */
+ public static final int UNSPECIFIED = 0;
+ /**
+ * The operation was unsupported.
+ *
+ * @since 1.5
+ */
+ public static final int UNSUPPORTED_OPERATION = 1;
+ /**
+ * The operation was invalid.
+ *
+ * @since 1.5
+ */
+ public static final int INVALID_OPERATION = 2;
+ /**
+ * The bundle manifest was in error.
+ *
+ * @since 1.5
+ */
+ public static final int MANIFEST_ERROR = 3;
+ /**
+ * The bundle was not resolved.
+ *
+ * @since 1.5
+ */
+ public static final int RESOLVE_ERROR = 4;
+ /**
+ * The bundle activator was in error.
+ *
+ * @since 1.5
+ */
+ public static final int ACTIVATOR_ERROR = 5;
+ /**
+ * The operation failed due to insufficient permissions.
+ *
+ * @since 1.5
+ */
+ public static final int SECURITY_ERROR = 6;
+ /**
+ * The operation failed to complete the requested lifecycle state change.
+ *
+ * @since 1.5
+ */
+ public static final int STATECHANGE_ERROR = 7;
+
+ /**
+ * The bundle could not be resolved due to an error with the
+ * Bundle-NativeCode header.
+ *
+ * @since 1.5
+ */
+ public static final int NATIVECODE_ERROR = 8;
+
+ /**
+ * The install or update operation failed because another
+ * already installed bundle has the same symbolic name and version.
+ * @since 1.5
+ */
+ public static final int DUPLICATE_BUNDLE_ERROR = 9;
+
+ /**
+ * The start transient operation failed because the start level of the
+ * bundle is greater than the current framework start level
+ *
+ * @since 1.5
+ */
+ public static final int START_TRANSIENT_ERROR = 10;
+
+ /**
+ * Creates a <code>BundleException</code> with the specified message and
+ * exception cause.
+ *
+ * @param msg The associated message.
+ * @param cause The cause of this exception.
+ */
+ public BundleException(String msg, Throwable cause) {
+ this(msg, UNSPECIFIED, cause);
+ }
+
+ /**
+ * Creates a <code>BundleException</code> with the specified message.
+ *
+ * @param msg The message.
+ */
+ public BundleException(String msg) {
+ this(msg, UNSPECIFIED);
+ }
+
+ /**
+ * Creates a <code>BundleException</code> with the specified message, type
+ * and exception cause.
+ *
+ * @param msg The associated message.
+ * @param type The type for this exception.
+ * @param cause The cause of this exception.
+ * @since 1.5
+ */
+ public BundleException(String msg, int type, Throwable cause) {
+ super(msg, cause);
+ this.type = type;
+ }
+
+ /**
+ * Creates a <code>BundleException</code> with the specified message and
+ * type.
+ *
+ * @param msg The message.
+ * @param type The type for this exception.
+ * @since 1.5
+ */
+ public BundleException(String msg, int type) {
+ super(msg);
+ this.type = type;
+ }
+
+ /**
+ * Returns the cause of this exception or <code>null</code> if no cause was
+ * specified when this exception was created.
+ *
+ * <p>
+ * This method predates the general purpose exception chaining mechanism.
+ * The <code>getCause()</code> method is now the preferred means of
+ * obtaining this information.
+ *
+ * @return The result of calling <code>getCause()</code>.
+ */
+ public Throwable getNestedException() {
+ return getCause();
+ }
+
+ /**
+ * Returns the cause of this exception or <code>null</code> if no cause was
+ * set.
+ *
+ * @return The cause of this exception or <code>null</code> if no cause was
+ * set.
+ * @since 1.3
+ */
+ public Throwable getCause() {
+ return super.getCause();
+ }
+
+ /**
+ * Initializes the cause of this exception to the specified value.
+ *
+ * @param cause The cause of this exception.
+ * @return This exception.
+ * @throws IllegalArgumentException If the specified cause is this
+ * exception.
+ * @throws IllegalStateException If the cause of this exception has already
+ * been set.
+ * @since 1.3
+ */
+ public Throwable initCause(Throwable cause) {
+ return super.initCause(cause);
+ }
+
+ /**
+ * Returns the type for this exception or <code>UNSPECIFIED</code> if the
+ * type was unspecified or unknown.
+ *
+ * @return The type of this exception.
+ * @since 1.5
+ */
+ public int getType() {
+ return type;
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/BundleListener.java b/framework/src/main/java/org/osgi/framework/BundleListener.java
new file mode 100644
index 0000000..9dd7151
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/BundleListener.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.util.EventListener;
+
+/**
+ * A <code>BundleEvent</code> listener. <code>BundleListener</code> is a
+ * listener interface that may be implemented by a bundle developer. When a
+ * <code>BundleEvent</code> is fired, it is asynchronously delivered to a
+ * <code>BundleListener</code>. The Framework delivers
+ * <code>BundleEvent</code> objects to a <code>BundleListener</code> in
+ * order and must not concurrently call a <code>BundleListener</code>.
+ * <p>
+ * A <code>BundleListener</code> object is registered with the Framework using
+ * the {@link BundleContext#addBundleListener} method.
+ * <code>BundleListener</code>s are called with a <code>BundleEvent</code>
+ * object when a bundle has been installed, resolved, started, stopped, updated,
+ * unresolved, or uninstalled.
+ *
+ * @see BundleEvent
+ * @NotThreadSafe
+ * @version $Revision: 5673 $
+ */
+
+public interface BundleListener extends EventListener {
+ /**
+ * Receives notification that a bundle has had a lifecycle change.
+ *
+ * @param event The <code>BundleEvent</code>.
+ */
+ public void bundleChanged(BundleEvent event);
+}
diff --git a/framework/src/main/java/org/osgi/framework/BundlePermission.java b/framework/src/main/java/org/osgi/framework/BundlePermission.java
new file mode 100644
index 0000000..8677e69
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/BundlePermission.java
@@ -0,0 +1,606 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+/**
+ * A bundle's authority to require or provide a bundle or to receive or attach
+ * fragments.
+ *
+ * <p>
+ * A bundle symbolic name defines a unique fully qualified name. Wildcards may
+ * be used.
+ *
+ * <pre>
+ * name ::= <symbolic name> | <symbolic name ending in ".*"> | *
+ * </pre>
+ *
+ * Examples:
+ *
+ * <pre>
+ * org.osgi.example.bundle
+ * org.osgi.example.*
+ * *
+ * </pre>
+ *
+ * <p>
+ * <code>BundlePermission</code> has four actions: <code>provide</code>,
+ * <code>require</code>,<code>host</code>, and <code>fragment</code>. The
+ * <code>provide</code> action implies the <code>require</code> action.
+ *
+ * @since 1.3
+ * @ThreadSafe
+ * @version $Revision: 6860 $
+ */
+
+public final class BundlePermission extends BasicPermission {
+
+ private static final long serialVersionUID = 3257846601685873716L;
+
+ /**
+ * The action string <code>provide</code>. The <code>provide</code> action
+ * implies the <code>require</code> action.
+ */
+ public final static String PROVIDE = "provide";
+
+ /**
+ * The action string <code>require</code>. The <code>require</code> action
+ * is implied by the <code>provide</code> action.
+ */
+ public final static String REQUIRE = "require";
+
+ /**
+ * The action string <code>host</code>.
+ */
+ public final static String HOST = "host";
+
+ /**
+ * The action string <code>fragment</code>.
+ */
+ public final static String FRAGMENT = "fragment";
+
+ private final static int ACTION_PROVIDE = 0x00000001;
+ private final static int ACTION_REQUIRE = 0x00000002;
+ private final static int ACTION_HOST = 0x00000004;
+ private final static int ACTION_FRAGMENT = 0x00000008;
+ private final static int ACTION_ALL = ACTION_PROVIDE
+ | ACTION_REQUIRE
+ | ACTION_HOST
+ | ACTION_FRAGMENT;
+ final static int ACTION_NONE = 0;
+ /**
+ * The actions mask.
+ */
+ private transient int action_mask;
+
+ /**
+ * The actions in canonical form.
+ *
+ * @serial
+ */
+ private volatile String actions = null;
+
+ /**
+ * Defines the authority to provide and/or require and or specify a host
+ * fragment symbolic name within the OSGi environment.
+ * <p>
+ * Bundle Permissions are granted over all possible versions of a bundle.
+ *
+ * A bundle that needs to provide a bundle must have the appropriate
+ * <code>BundlePermission</code> for the symbolic name; a bundle that
+ * requires a bundle must have the appropriate <code>BundlePermssion</code>
+ * for that symbolic name; a bundle that specifies a fragment host must have
+ * the appropriate <code>BundlePermission</code> for that symbolic name.
+ *
+ * @param symbolicName The bundle symbolic name.
+ * @param actions <code>provide</code>,<code>require</code>,
+ * <code>host</code>,<code>fragment</code> (canonical order).
+ */
+ public BundlePermission(String symbolicName, String actions) {
+ this(symbolicName, parseActions(actions));
+ }
+
+ /**
+ * Package private constructor used by BundlePermissionCollection.
+ *
+ * @param symbolicName the bundle symbolic name
+ * @param mask the action mask
+ */
+ BundlePermission(String symbolicName, int mask) {
+ super(symbolicName);
+ setTransients(mask);
+ }
+
+ /**
+ * Called by constructors and when deserialized.
+ *
+ * @param mask
+ */
+ private synchronized void setTransients(int mask) {
+ if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
+ throw new IllegalArgumentException("invalid action string");
+ }
+
+ action_mask = mask;
+ }
+
+ /**
+ * Returns the current action mask.
+ * <p>
+ * Used by the BundlePermissionCollection class.
+ *
+ * @return Current action mask.
+ */
+ synchronized int getActionsMask() {
+ return action_mask;
+ }
+
+ /**
+ * Parse action string into action mask.
+ *
+ * @param actions Action string.
+ * @return action mask.
+ */
+ private static int 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] == 'p' || a[i - 6] == 'P')
+ && (a[i - 5] == 'r' || a[i - 5] == 'R')
+ && (a[i - 4] == 'o' || a[i - 4] == 'O')
+ && (a[i - 3] == 'v' || a[i - 3] == 'V')
+ && (a[i - 2] == 'i' || a[i - 2] == 'I')
+ && (a[i - 1] == 'd' || a[i - 1] == 'D')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 7;
+ mask |= ACTION_PROVIDE | ACTION_REQUIRE;
+ }
+ else
+ if (i >= 6 && (a[i - 6] == 'r' || a[i - 6] == 'R')
+ && (a[i - 5] == 'e' || a[i - 5] == 'E')
+ && (a[i - 4] == 'q' || a[i - 4] == 'Q')
+ && (a[i - 3] == 'u' || a[i - 3] == 'U')
+ && (a[i - 2] == 'i' || a[i - 2] == 'I')
+ && (a[i - 1] == 'r' || a[i - 1] == 'R')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 7;
+ mask |= ACTION_REQUIRE;
+ }
+ else
+ if (i >= 3 && (a[i - 3] == 'h' || a[i - 3] == 'H')
+ && (a[i - 2] == 'o' || a[i - 2] == 'O')
+ && (a[i - 1] == 's' || a[i - 1] == 'S')
+ && (a[i] == 't' || a[i] == 'T')) {
+ matchlen = 4;
+ mask |= ACTION_HOST;
+ }
+ else
+ if (i >= 7 && (a[i - 7] == 'f' || a[i - 7] == 'F')
+ && (a[i - 6] == 'r' || a[i - 6] == 'R')
+ && (a[i - 5] == 'a' || a[i - 5] == 'A')
+ && (a[i - 4] == 'g' || a[i - 4] == 'G')
+ && (a[i - 3] == 'm' || a[i - 3] == 'M')
+ && (a[i - 2] == 'e' || a[i - 2] == 'E')
+ && (a[i - 1] == 'n' || a[i - 1] == 'N')
+ && (a[i] == 't' || a[i] == 'T')) {
+ matchlen = 8;
+ mask |= ACTION_FRAGMENT;
+ }
+ else {
+ // parse error
+ throw new IllegalArgumentException(
+ "invalid permission: " + actions);
+ }
+
+ // make sure we didn't just match the tail of a word
+ // like "ackbarfrequire". 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;
+ }
+
+ /**
+ * Determines if the specified permission is implied by this object.
+ *
+ * <p>
+ * This method checks that the symbolic name of the target is implied by the
+ * symbolic name of this object. The list of <code>BundlePermission</code>
+ * actions must either match or allow for the list of the target object to
+ * imply the target <code>BundlePermission</code> action.
+ * <p>
+ * The permission to provide a bundle implies the permission to require the
+ * named symbolic name.
+ *
+ * <pre>
+ * x.y.*,"provide" -> x.y.z,"provide" is true
+ * *,"require" -> x.y, "require" is true
+ * *,"provide" -> x.y, "require" is true
+ * x.y,"provide" -> x.y.z, "provide" is false
+ * </pre>
+ *
+ * @param p The requested permission.
+ * @return <code>true</code> if the specified <code>BundlePermission</code>
+ * action is implied by this object; <code>false</code> otherwise.
+ */
+ public boolean implies(Permission p) {
+ if (!(p instanceof BundlePermission)) {
+ return false;
+ }
+ BundlePermission requested = (BundlePermission) p;
+
+ final int effective = getActionsMask();
+ final int desired = requested.getActionsMask();
+ return ((effective & desired) == desired)
+ && super.implies(requested);
+ }
+
+ /**
+ * Returns the canonical string representation of the
+ * <code>BundlePermission</code> actions.
+ *
+ * <p>
+ * Always returns present <code>BundlePermission</code> actions in the
+ * following order: <code>provide</code>, <code>require</code>,
+ * <code>host</code>, <code>fragment</code>.
+ *
+ * @return Canonical string representation of the <code>BundlePermission
+ * </code> actions.
+ */
+ public String getActions() {
+ String result = actions;
+ if (result == null) {
+ StringBuffer sb = new StringBuffer();
+ boolean comma = false;
+
+ if ((action_mask & ACTION_PROVIDE) == ACTION_PROVIDE) {
+ sb.append(PROVIDE);
+ comma = true;
+ }
+
+ if ((action_mask & ACTION_REQUIRE) == ACTION_REQUIRE) {
+ if (comma)
+ sb.append(',');
+ sb.append(REQUIRE);
+ comma = true;
+ }
+
+ if ((action_mask & ACTION_HOST) == ACTION_HOST) {
+ if (comma)
+ sb.append(',');
+ sb.append(HOST);
+ comma = true;
+ }
+
+ if ((action_mask & ACTION_FRAGMENT) == ACTION_FRAGMENT) {
+ if (comma)
+ sb.append(',');
+ sb.append(FRAGMENT);
+ }
+
+ actions = result = sb.toString();
+ }
+ return result;
+ }
+
+ /**
+ * Returns a new <code>PermissionCollection</code> object suitable for
+ * storing <code>BundlePermission</code> objects.
+ *
+ * @return A new <code>PermissionCollection</code> object.
+ */
+ public PermissionCollection newPermissionCollection() {
+ return new BundlePermissionCollection();
+ }
+
+ /**
+ * Determines the equality of two <code>BundlePermission</code> objects.
+ *
+ * This method checks that specified bundle has the same bundle symbolic
+ * name and <code>BundlePermission</code> actions as this
+ * <code>BundlePermission</code> object.
+ *
+ * @param obj The object to test for equality with this
+ * <code>BundlePermission</code> object.
+ * @return <code>true</code> if <code>obj</code> is a
+ * <code>BundlePermission</code>, and has the same bundle symbolic
+ * name and actions as this <code>BundlePermission</code> object;
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (!(obj instanceof BundlePermission)) {
+ return false;
+ }
+
+ BundlePermission bp = (BundlePermission) obj;
+
+ return (getActionsMask() == bp.getActionsMask())
+ && getName().equals(bp.getName());
+ }
+
+ /**
+ * Returns the hash code value for this object.
+ *
+ * @return A hash code value for this object.
+ */
+ public int hashCode() {
+ int h = 31 * 17 + getName().hashCode();
+ h = 31 * h + getActions().hashCode();
+ return h;
+ }
+
+ /**
+ * WriteObject is called to save the state of the
+ * <code>BundlePermission</code> object to a stream. The actions are
+ * serialized, and the superclass takes care of the name.
+ */
+ private synchronized void writeObject(java.io.ObjectOutputStream s)
+ throws IOException {
+ // Write out the actions. The superclass takes care of the name
+ // call getActions to make sure actions field is initialized
+ if (actions == null)
+ getActions();
+ s.defaultWriteObject();
+ }
+
+ /**
+ * readObject is called to restore the state of the BundlePermission from a
+ * stream.
+ */
+ private synchronized void readObject(java.io.ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ // Read in the action, then initialize the rest
+ s.defaultReadObject();
+ setTransients(parseActions(actions));
+ }
+}
+
+/**
+ * Stores a set of <code>BundlePermission</code> permissions.
+ *
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ */
+
+final class BundlePermissionCollection extends PermissionCollection {
+ private static final long serialVersionUID = 3258407326846433079L;
+
+ /**
+ * Table 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 BundlePermissions object.
+ *
+ */
+ public BundlePermissionCollection() {
+ permissions = new HashMap();
+ all_allowed = false;
+ }
+
+ /**
+ * Add a permission to this permission collection.
+ *
+ * @param permission The <code>BundlePermission</code> object to add.
+ * @throws IllegalArgumentException If the permission is not a
+ * <code>BundlePermission</code> instance.
+ * @throws SecurityException If this <code>BundlePermissionCollection</code>
+ * object has been marked read-only.
+ */
+ public void add(final Permission permission) {
+ if (!(permission instanceof BundlePermission)) {
+ throw new IllegalArgumentException("invalid permission: "
+ + permission);
+ }
+ if (isReadOnly()) {
+ throw new SecurityException("attempt to add a Permission to a "
+ + "readonly PermissionCollection");
+ }
+ final BundlePermission bp = (BundlePermission) permission;
+ final String name = bp.getName();
+ synchronized (this) {
+ Map pc = permissions;
+ BundlePermission existing = (BundlePermission) pc.get(name);
+ if (existing != null) {
+ final int oldMask = existing.getActionsMask();
+ final int newMask = bp.getActionsMask();
+ if (oldMask != newMask) {
+ pc.put(name, new BundlePermission(name, oldMask
+ | newMask));
+
+ }
+ }
+ else {
+ pc.put(name, bp);
+ }
+
+ if (!all_allowed) {
+ if (name.equals("*"))
+ all_allowed = true;
+ }
+ }
+ }
+
+ /**
+ * Determines if the specified permissions implies the permissions expressed
+ * in <code>permission</code>.
+ *
+ * @param permission The Permission object to compare with this
+ * <code>BundlePermission</code> object.
+ * @return <code>true</code> if <code>permission</code> is a proper subset
+ * of a permission in the set; <code>false</code> otherwise.
+ */
+ public boolean implies(final Permission permission) {
+ if (!(permission instanceof BundlePermission)) {
+ return false;
+ }
+ BundlePermission requested = (BundlePermission) permission;
+ String requestedName = requested.getName();
+ final int desired = requested.getActionsMask();
+ int effective = BundlePermission.ACTION_NONE;
+ BundlePermission bp;
+
+ synchronized (this) {
+ Map pc = permissions;
+ /* short circuit if the "*" Permission was added */
+ if (all_allowed) {
+ bp = (BundlePermission) pc.get("*");
+ if (bp != null) {
+ effective |= bp.getActionsMask();
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ }
+ bp = (BundlePermission) pc.get(requestedName);
+ // strategy:
+ // Check for full match first. Then work our way up the
+ // name looking for matches on a.b.*
+ if (bp != null) {
+ // we have a direct hit!
+ effective |= bp.getActionsMask();
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ // work our way up the tree...
+ int last;
+ int offset = requestedName.length() - 1;
+ while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+ requestedName = requestedName.substring(0, last + 1) + "*";
+ bp = (BundlePermission) pc.get(requestedName);
+ if (bp != null) {
+ effective |= bp.getActionsMask();
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ offset = last - 1;
+ }
+ // we don't have to check for "*" as it was already checked
+ // at the top (all_allowed), so we just return false
+ return false;
+ }
+ }
+
+ /**
+ * Returns an enumeration of all <code>BundlePermission</code> objects in
+ * the container.
+ *
+ * @return Enumeration of all <code>BundlePermission</code> objects.
+ */
+ public synchronized Enumeration elements() {
+ return Collections.enumeration(permissions.values());
+ }
+
+ /* serialization logic */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("permissions", Hashtable.class),
+ new ObjectStreamField("all_allowed", Boolean.TYPE) };
+
+ private synchronized void writeObject(ObjectOutputStream out)
+ throws IOException {
+ Hashtable hashtable = new Hashtable(permissions);
+ ObjectOutputStream.PutField pfields = out.putFields();
+ pfields.put("permissions", hashtable);
+ pfields.put("all_allowed", all_allowed);
+ out.writeFields();
+ }
+
+ private synchronized void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ ObjectInputStream.GetField gfields = in.readFields();
+ Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+ permissions = new HashMap(hashtable);
+ all_allowed = gfields.get("all_allowed", false);
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/BundleReference.java b/framework/src/main/java/org/osgi/framework/BundleReference.java
new file mode 100644
index 0000000..f9c4183
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/BundleReference.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * A reference to a Bundle.
+ *
+ * @since 1.5
+ * @ThreadSafe
+ * @version $Revision: 6860 $
+ */
+public interface BundleReference {
+ /**
+ * Returns the <code>Bundle</code> object associated with this
+ * <code>BundleReference</code>.
+ *
+ * @return The <code>Bundle</code> object associated with this
+ * <code>BundleReference</code>.
+ */
+ public Bundle getBundle();
+}
diff --git a/framework/src/main/java/org/osgi/framework/Configurable.java b/framework/src/main/java/org/osgi/framework/Configurable.java
new file mode 100644
index 0000000..b30910c
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/Configurable.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * Supports a configuration object.
+ *
+ * <p>
+ * <code>Configurable</code> is an interface that should be used by a bundle
+ * developer in support of a configurable service. Bundles that need to
+ * configure a service may test to determine if the service object is an
+ * <code>instanceof Configurable</code>.
+ *
+ * @deprecated As of 1.2. Please use Configuration Admin service.
+ * @version $Revision: 6361 $
+ */
+public interface Configurable {
+ /**
+ * Returns this service's configuration object.
+ *
+ * <p>
+ * Services implementing <code>Configurable</code> should take care when
+ * returning a service configuration object since this object is probably
+ * sensitive.
+ * <p>
+ * If the Java Runtime Environment supports permissions, it is recommended
+ * that the caller is checked for some appropriate permission before
+ * returning the configuration object.
+ *
+ * @return The configuration object for this service.
+ * @throws SecurityException If the caller does not have an
+ * appropriate permission and the Java Runtime Environment supports
+ * permissions.
+ * @deprecated As of 1.2. Please use Configuration Admin service.
+ */
+ public Object getConfigurationObject();
+}
diff --git a/framework/src/main/java/org/osgi/framework/Constants.java b/framework/src/main/java/org/osgi/framework/Constants.java
new file mode 100644
index 0000000..16a10d8
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/Constants.java
@@ -0,0 +1,1312 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * Defines standard names for the OSGi environment system properties, service
+ * properties, and Manifest header attribute keys.
+ *
+ * <p>
+ * The values associated with these keys are of type
+ * <code>String</code>, unless otherwise indicated.
+ *
+ * @since 1.1
+ * @version $Revision: 6552 $
+ */
+
+public interface Constants {
+ /**
+ * Location identifier of the OSGi <i>system bundle </i>, which is defined
+ * to be "System Bundle".
+ */
+ public static final String SYSTEM_BUNDLE_LOCATION = "System Bundle";
+
+ /**
+ * Alias for the symbolic name of the OSGi <i>system bundle </i>. It is
+ * defined to be "system.bundle".
+ *
+ * @since 1.3
+ */
+ public static final String SYSTEM_BUNDLE_SYMBOLICNAME = "system.bundle";
+
+ /**
+ * Manifest header identifying the bundle's category.
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_CATEGORY = "Bundle-Category";
+
+ /**
+ * Manifest header identifying a list of directories and embedded JAR files,
+ * which are bundle resources used to extend the bundle's classpath.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_CLASSPATH = "Bundle-ClassPath";
+
+ /**
+ * Manifest header identifying the bundle's copyright information.
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_COPYRIGHT = "Bundle-Copyright";
+
+ /**
+ * Manifest header containing a brief description of the bundle's
+ * functionality.
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_DESCRIPTION = "Bundle-Description";
+
+ /**
+ * Manifest header identifying the bundle's name.
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_NAME = "Bundle-Name";
+
+ /**
+ * Manifest header identifying a number of hardware environments and the
+ * native language code libraries that the bundle is carrying for each of
+ * these environments.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_NATIVECODE = "Bundle-NativeCode";
+
+ /**
+ * Manifest header identifying the packages that the bundle offers to the
+ * Framework for export.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String EXPORT_PACKAGE = "Export-Package";
+
+ /**
+ * Manifest header identifying the fully qualified class names of the
+ * services that the bundle may register (used for informational purposes
+ * only).
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @deprecated As of 1.2.
+ */
+ public static final String EXPORT_SERVICE = "Export-Service";
+
+ /**
+ * Manifest header identifying the packages on which the bundle depends.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String IMPORT_PACKAGE = "Import-Package";
+
+ /**
+ * Manifest header identifying the packages that the bundle may dynamically
+ * import during execution.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @since 1.2
+ */
+ public static final String DYNAMICIMPORT_PACKAGE = "DynamicImport-Package";
+
+ /**
+ * Manifest header identifying the fully qualified class names of the
+ * services that the bundle requires (used for informational purposes only).
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @deprecated As of 1.2.
+ */
+ public static final String IMPORT_SERVICE = "Import-Service";
+
+ /**
+ * Manifest header identifying the bundle's vendor.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_VENDOR = "Bundle-Vendor";
+
+ /**
+ * Manifest header identifying the bundle's version.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_VERSION = "Bundle-Version";
+
+ /**
+ * Manifest header identifying the bundle's documentation URL, from which
+ * further information about the bundle may be obtained.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_DOCURL = "Bundle-DocURL";
+
+ /**
+ * Manifest header identifying the contact address where problems with the
+ * bundle may be reported; for example, an email address.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_CONTACTADDRESS = "Bundle-ContactAddress";
+
+ /**
+ * Manifest header attribute identifying the bundle's activator class.
+ *
+ * <p>
+ * If present, this header specifies the name of the bundle resource class
+ * that implements the <code>BundleActivator</code> interface and whose
+ * <code>start</code> and <code>stop</code> methods are called by the
+ * Framework when the bundle is started and stopped, respectively.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_ACTIVATOR = "Bundle-Activator";
+
+ /**
+ * Manifest header identifying the location from which a new bundle version
+ * is obtained during a bundle update operation.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ */
+ public static final String BUNDLE_UPDATELOCATION = "Bundle-UpdateLocation";
+
+ /**
+ * Manifest header attribute identifying the version of a package specified
+ * in the Export-Package or Import-Package manifest header.
+ *
+ * @deprecated As of 1.3. This has been replaced by
+ * {@link #VERSION_ATTRIBUTE}.
+ */
+ public static final String PACKAGE_SPECIFICATION_VERSION = "specification-version";
+
+ /**
+ * Manifest header attribute identifying the processor required to run
+ * native bundle code specified in the Bundle-NativeCode manifest header).
+ *
+ * <p>
+ * The attribute value is encoded in the Bundle-NativeCode manifest header
+ * like:
+ *
+ * <pre>
+ * Bundle-NativeCode: http.so ; processor=x86 ...
+ * </pre>
+ *
+ * @see #BUNDLE_NATIVECODE
+ */
+ public static final String BUNDLE_NATIVECODE_PROCESSOR = "processor";
+
+ /**
+ * Manifest header attribute identifying the operating system required to
+ * run native bundle code specified in the Bundle-NativeCode manifest
+ * header).
+ * <p>
+ * The attribute value is encoded in the Bundle-NativeCode manifest header
+ * like:
+ *
+ * <pre>
+ * Bundle-NativeCode: http.so ; osname=Linux ...
+ * </pre>
+ *
+ * @see #BUNDLE_NATIVECODE
+ */
+ public static final String BUNDLE_NATIVECODE_OSNAME = "osname";
+
+ /**
+ * Manifest header attribute identifying the operating system version
+ * required to run native bundle code specified in the Bundle-NativeCode
+ * manifest header).
+ * <p>
+ * The attribute value is encoded in the Bundle-NativeCode manifest header
+ * like:
+ *
+ * <pre>
+ * Bundle-NativeCode: http.so ; osversion="2.34" ...
+ * </pre>
+ *
+ * @see #BUNDLE_NATIVECODE
+ */
+ public static final String BUNDLE_NATIVECODE_OSVERSION = "osversion";
+
+ /**
+ * Manifest header attribute identifying the language in which the native
+ * bundle code is written specified in the Bundle-NativeCode manifest
+ * header. See ISO 639 for possible values.
+ * <p>
+ * The attribute value is encoded in the Bundle-NativeCode manifest header
+ * like:
+ *
+ * <pre>
+ * Bundle-NativeCode: http.so ; language=nl_be ...
+ * </pre>
+ *
+ * @see #BUNDLE_NATIVECODE
+ */
+ public static final String BUNDLE_NATIVECODE_LANGUAGE = "language";
+
+ /**
+ * Manifest header identifying the required execution environment for the
+ * bundle. The service platform may run this bundle if any of the execution
+ * environments named in this header matches one of the execution
+ * environments it implements.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @since 1.2
+ */
+ public static final String BUNDLE_REQUIREDEXECUTIONENVIRONMENT = "Bundle-RequiredExecutionEnvironment";
+
+ /**
+ * Manifest header identifying the bundle's symbolic name.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @since 1.3
+ */
+ public final static String BUNDLE_SYMBOLICNAME = "Bundle-SymbolicName";
+
+ /**
+ * Manifest header directive identifying whether a bundle is a singleton.
+ * The default value is <code>false</code>.
+ *
+ * <p>
+ * The directive value is encoded in the Bundle-SymbolicName manifest header
+ * like:
+ *
+ * <pre>
+ * Bundle-SymbolicName: com.acme.module.test; singleton:=true
+ * </pre>
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @see #BUNDLE_SYMBOLICNAME
+ * @since 1.3
+ */
+ public final static String SINGLETON_DIRECTIVE = "singleton";
+
+ /**
+ * Manifest header directive identifying if and when a fragment may attach
+ * to a host bundle. The default value is
+ * {@link #FRAGMENT_ATTACHMENT_ALWAYS always}.
+ *
+ * <p>
+ * The directive value is encoded in the Bundle-SymbolicName manifest header
+ * like:
+ *
+ * <pre>
+ * Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="never"
+ * </pre>
+ *
+ * @see #BUNDLE_SYMBOLICNAME
+ * @see #FRAGMENT_ATTACHMENT_ALWAYS
+ * @see #FRAGMENT_ATTACHMENT_RESOLVETIME
+ * @see #FRAGMENT_ATTACHMENT_NEVER
+ * @since 1.3
+ */
+ public final static String FRAGMENT_ATTACHMENT_DIRECTIVE = "fragment-attachment";
+
+ /**
+ * Manifest header directive value identifying a fragment attachment type of
+ * always. A fragment attachment type of always indicates that fragments are
+ * allowed to attach to the host bundle at any time (while the host is
+ * resolved or during the process of resolving the host bundle).
+ *
+ * <p>
+ * The directive value is encoded in the Bundle-SymbolicName manifest header
+ * like:
+ *
+ * <pre>
+ * Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="always"
+ * </pre>
+ *
+ * @see #FRAGMENT_ATTACHMENT_DIRECTIVE
+ * @since 1.3
+ */
+ public final static String FRAGMENT_ATTACHMENT_ALWAYS = "always";
+
+ /**
+ * Manifest header directive value identifying a fragment attachment type of
+ * resolve-time. A fragment attachment type of resolve-time indicates that
+ * fragments are allowed to attach to the host bundle only during the
+ * process of resolving the host bundle.
+ *
+ * <p>
+ * The directive value is encoded in the Bundle-SymbolicName manifest header
+ * like:
+ *
+ * <pre>
+ * Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="resolve-time"
+ * </pre>
+ *
+ * @see #FRAGMENT_ATTACHMENT_DIRECTIVE
+ * @since 1.3
+ */
+ public final static String FRAGMENT_ATTACHMENT_RESOLVETIME = "resolve-time";
+
+ /**
+ * Manifest header directive value identifying a fragment attachment type of
+ * never. A fragment attachment type of never indicates that no fragments
+ * are allowed to attach to the host bundle at any time.
+ *
+ * <p>
+ * The directive value is encoded in the Bundle-SymbolicName manifest header
+ * like:
+ *
+ * <pre>
+ * Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="never"
+ * </pre>
+ *
+ * @see #FRAGMENT_ATTACHMENT_DIRECTIVE
+ * @since 1.3
+ */
+ public final static String FRAGMENT_ATTACHMENT_NEVER = "never";
+
+ /**
+ * Manifest header identifying the base name of the bundle's localization
+ * entries.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @see #BUNDLE_LOCALIZATION_DEFAULT_BASENAME
+ * @since 1.3
+ */
+ public final static String BUNDLE_LOCALIZATION = "Bundle-Localization";
+
+ /**
+ * Default value for the <code>Bundle-Localization</code> manifest header.
+ *
+ * @see #BUNDLE_LOCALIZATION
+ * @since 1.3
+ */
+ public final static String BUNDLE_LOCALIZATION_DEFAULT_BASENAME = "OSGI-INF/l10n/bundle";
+
+ /**
+ * Manifest header identifying the symbolic names of other bundles required
+ * by the bundle.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @since 1.3
+ */
+ public final static String REQUIRE_BUNDLE = "Require-Bundle";
+
+ /**
+ * Manifest header attribute identifying a range of versions for a bundle
+ * specified in the <code>Require-Bundle</code> or
+ * <code>Fragment-Host</code> manifest headers. The default value is
+ * <code>0.0.0</code>.
+ *
+ * <p>
+ * The attribute value is encoded in the Require-Bundle manifest header
+ * like:
+ *
+ * <pre>
+ * Require-Bundle: com.acme.module.test; bundle-version="1.1"
+ * Require-Bundle: com.acme.module.test; bundle-version="[1.0,2.0)"
+ * </pre>
+ *
+ * <p>
+ * The bundle-version attribute value uses a mathematical interval notation
+ * to specify a range of bundle versions. A bundle-version attribute value
+ * specified as a single version means a version range that includes any
+ * bundle version greater than or equal to the specified version.
+ *
+ * @see #REQUIRE_BUNDLE
+ * @since 1.3
+ */
+ public static final String BUNDLE_VERSION_ATTRIBUTE = "bundle-version";
+
+ /**
+ * Manifest header identifying the symbolic name of another bundle for which
+ * that the bundle is a fragment.
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @since 1.3
+ */
+ public final static String FRAGMENT_HOST = "Fragment-Host";
+
+ /**
+ * Manifest header attribute is used for selection by filtering based upon
+ * system properties.
+ *
+ * <p>
+ * The attribute value is encoded in manifest headers like:
+ *
+ * <pre>
+ * Bundle-NativeCode: libgtk.so; selection-filter="(ws=gtk)"; ...
+ * </pre>
+ *
+ * @see #BUNDLE_NATIVECODE
+ * @since 1.3
+ */
+ public final static String SELECTION_FILTER_ATTRIBUTE = "selection-filter";
+
+ /**
+ * Manifest header identifying the bundle manifest version. A bundle
+ * manifest may express the version of the syntax in which it is written by
+ * specifying a bundle manifest version. Bundles exploiting OSGi Release 4,
+ * or later, syntax must specify a bundle manifest version.
+ * <p>
+ * The bundle manifest version defined by OSGi Release 4 or, more
+ * specifically, by version 1.3 of the OSGi Core Specification is "2".
+ *
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @since 1.3
+ */
+ public final static String BUNDLE_MANIFESTVERSION = "Bundle-ManifestVersion";
+
+ /**
+ * Manifest header attribute identifying the version of a package specified
+ * in the Export-Package or Import-Package manifest header.
+ *
+ * <p>
+ * The attribute value is encoded in the Export-Package or Import-Package
+ * manifest header like:
+ *
+ * <pre>
+ * Import-Package: org.osgi.framework; version="1.1"
+ * </pre>
+ *
+ * @see #EXPORT_PACKAGE
+ * @see #IMPORT_PACKAGE
+ * @since 1.3
+ */
+ public final static String VERSION_ATTRIBUTE = "version";
+
+ /**
+ * Manifest header attribute identifying the symbolic name of a bundle that
+ * exports a package specified in the Import-Package manifest header.
+ *
+ * <p>
+ * The attribute value is encoded in the Import-Package manifest header
+ * like:
+ *
+ * <pre>
+ * Import-Package: org.osgi.framework; bundle-symbolic-name="com.acme.module.test"
+ * </pre>
+ *
+ * @see #IMPORT_PACKAGE
+ * @since 1.3
+ */
+ public final static String BUNDLE_SYMBOLICNAME_ATTRIBUTE = "bundle-symbolic-name";
+
+ /**
+ * Manifest header directive identifying the resolution type in the
+ * Import-Package or Require-Bundle manifest header. The default value is
+ * {@link #RESOLUTION_MANDATORY mandatory}.
+ *
+ * <p>
+ * The directive value is encoded in the Import-Package or Require-Bundle
+ * manifest header like:
+ *
+ * <pre>
+ * Import-Package: org.osgi.framework; resolution:="optional"
+ * Require-Bundle: com.acme.module.test; resolution:="optional"
+ * </pre>
+ *
+ * @see #IMPORT_PACKAGE
+ * @see #REQUIRE_BUNDLE
+ * @see #RESOLUTION_MANDATORY
+ * @see #RESOLUTION_OPTIONAL
+ * @since 1.3
+ */
+ public final static String RESOLUTION_DIRECTIVE = "resolution";
+
+ /**
+ * Manifest header directive value identifying a mandatory resolution type.
+ * A mandatory resolution type indicates that the import package or require
+ * bundle must be resolved when the bundle is resolved. If such an import or
+ * require bundle cannot be resolved, the module fails to resolve.
+ *
+ * <p>
+ * The directive value is encoded in the Import-Package or Require-Bundle
+ * manifest header like:
+ *
+ * <pre>
+ * Import-Package: org.osgi.framework; resolution:="manditory"
+ * Require-Bundle: com.acme.module.test; resolution:="manditory"
+ * </pre>
+ *
+ * @see #RESOLUTION_DIRECTIVE
+ * @since 1.3
+ */
+ public final static String RESOLUTION_MANDATORY = "mandatory";
+
+ /**
+ * Manifest header directive value identifying an optional resolution type.
+ * An optional resolution type indicates that the import or require bundle
+ * is optional and the bundle may be resolved without the import or require
+ * bundle being resolved. If the import or require bundle is not resolved
+ * when the bundle is resolved, the import or require bundle may not be
+ * resolved before the bundle is refreshed.
+ *
+ * <p>
+ * The directive value is encoded in the Import-Package or Require-Bundle
+ * manifest header like:
+ *
+ * <pre>
+ * Import-Package: org.osgi.framework; resolution:="optional"
+ * Require-Bundle: com.acme.module.test; resolution:="optional"
+ * </pre>
+ *
+ * @see #RESOLUTION_DIRECTIVE
+ * @since 1.3
+ */
+ public final static String RESOLUTION_OPTIONAL = "optional";
+
+ /**
+ * Manifest header directive identifying a list of packages that an exported
+ * package uses.
+ *
+ * <p>
+ * The directive value is encoded in the Export-Package manifest header
+ * like:
+ *
+ * <pre>
+ * Export-Package: org.osgi.util.tracker; uses:="org.osgi.framework"
+ * </pre>
+ *
+ * @see #EXPORT_PACKAGE
+ * @since 1.3
+ */
+ public final static String USES_DIRECTIVE = "uses";
+
+ /**
+ * Manifest header directive identifying a list of classes to include in the
+ * exported package.
+ *
+ * <p>
+ * This directive is used by the Export-Package manifest header to identify
+ * a list of classes of the specified package which must be allowed to be
+ * exported. The directive value is encoded in the Export-Package manifest
+ * header like:
+ *
+ * <pre>
+ * Export-Package: org.osgi.framework; include:="MyClass*"
+ * </pre>
+ *
+ * <p>
+ * This directive is also used by the Bundle-ActivationPolicy manifest
+ * header to identify the packages from which class loads will trigger lazy
+ * activation. The directive value is encoded in the Bundle-ActivationPolicy
+ * manifest header like:
+ *
+ * <pre>
+ * Bundle-ActivationPolicy: lazy; include:="org.osgi.framework"
+ * </pre>
+ *
+ * @see #EXPORT_PACKAGE
+ * @see #BUNDLE_ACTIVATIONPOLICY
+ * @since 1.3
+ */
+ public final static String INCLUDE_DIRECTIVE = "include";
+
+ /**
+ * Manifest header directive identifying a list of classes to exclude in the
+ * exported package..
+ * <p>
+ * This directive is used by the Export-Package manifest header to identify
+ * a list of classes of the specified package which must not be allowed to
+ * be exported. The directive value is encoded in the Export-Package
+ * manifest header like:
+ *
+ * <pre>
+ * Export-Package: org.osgi.framework; exclude:="*Impl"
+ * </pre>
+ *
+ * <p>
+ * This directive is also used by the Bundle-ActivationPolicy manifest
+ * header to identify the packages from which class loads will not trigger
+ * lazy activation. The directive value is encoded in the
+ * Bundle-ActivationPolicy manifest header like:
+ *
+ * <pre>
+ * Bundle-ActivationPolicy: lazy; exclude:="org.osgi.framework"
+ * </pre>
+ *
+ * @see #EXPORT_PACKAGE
+ * @see #BUNDLE_ACTIVATIONPOLICY
+ * @since 1.3
+ */
+ public final static String EXCLUDE_DIRECTIVE = "exclude";
+
+ /**
+ * Manifest header directive identifying names of matching attributes which
+ * must be specified by matching Import-Package statements in the
+ * Export-Package manifest header.
+ *
+ * <p>
+ * The directive value is encoded in the Export-Package manifest header
+ * like:
+ *
+ * <pre>
+ * Export-Package: org.osgi.framework; mandatory:="bundle-symbolic-name"
+ * </pre>
+ *
+ * @see #EXPORT_PACKAGE
+ * @since 1.3
+ */
+ public final static String MANDATORY_DIRECTIVE = "mandatory";
+
+ /**
+ * Manifest header directive identifying the visibility of a required bundle
+ * in the Require-Bundle manifest header. The default value is
+ * {@link #VISIBILITY_PRIVATE private}.
+ *
+ * <p>
+ * The directive value is encoded in the Require-Bundle manifest header
+ * like:
+ *
+ * <pre>
+ * Require-Bundle: com.acme.module.test; visibility:="reexport"
+ * </pre>
+ *
+ * @see #REQUIRE_BUNDLE
+ * @see #VISIBILITY_PRIVATE
+ * @see #VISIBILITY_REEXPORT
+ * @since 1.3
+ */
+ public final static String VISIBILITY_DIRECTIVE = "visibility";
+
+ /**
+ * Manifest header directive value identifying a private visibility type. A
+ * private visibility type indicates that any packages that are exported by
+ * the required bundle are not made visible on the export signature of the
+ * requiring bundle.
+ *
+ * <p>
+ * The directive value is encoded in the Require-Bundle manifest header
+ * like:
+ *
+ * <pre>
+ * Require-Bundle: com.acme.module.test; visibility:="private"
+ * </pre>
+ *
+ * @see #VISIBILITY_DIRECTIVE
+ * @since 1.3
+ */
+ public final static String VISIBILITY_PRIVATE = "private";
+
+ /**
+ * Manifest header directive value identifying a reexport visibility type. A
+ * reexport visibility type indicates any packages that are exported by the
+ * required bundle are re-exported by the requiring bundle. Any arbitrary
+ * arbitrary matching attributes with which they were exported by the
+ * required bundle are deleted.
+ *
+ * <p>
+ * The directive value is encoded in the Require-Bundle manifest header
+ * like:
+ *
+ * <pre>
+ * Require-Bundle: com.acme.module.test; visibility:="reexport"
+ * </pre>
+ *
+ * @see #VISIBILITY_DIRECTIVE
+ * @since 1.3
+ */
+ public final static String VISIBILITY_REEXPORT = "reexport";
+
+ /**
+ * Manifest header directive identifying the type of the extension fragment.
+ *
+ * <p>
+ * The directive value is encoded in the Fragment-Host manifest header like:
+ *
+ * <pre>
+ * Fragment-Host: system.bundle; extension:="framework"
+ * </pre>
+ *
+ * @see #FRAGMENT_HOST
+ * @see #EXTENSION_FRAMEWORK
+ * @see #EXTENSION_BOOTCLASSPATH
+ * @since 1.3
+ */
+ public final static String EXTENSION_DIRECTIVE = "extension";
+
+ /**
+ * Manifest header directive value identifying the type of extension
+ * fragment. An extension fragment type of framework indicates that the
+ * extension fragment is to be loaded by the framework's class loader.
+ *
+ * <p>
+ * The directive value is encoded in the Fragment-Host manifest header like:
+ *
+ * <pre>
+ * Fragment-Host: system.bundle; extension:="framework"
+ * </pre>
+ *
+ * @see #EXTENSION_DIRECTIVE
+ * @since 1.3
+ */
+ public final static String EXTENSION_FRAMEWORK = "framework";
+
+ /**
+ * Manifest header directive value identifying the type of extension
+ * fragment. An extension fragment type of bootclasspath indicates that the
+ * extension fragment is to be loaded by the boot class loader.
+ *
+ * <p>
+ * The directive value is encoded in the Fragment-Host manifest header like:
+ *
+ * <pre>
+ * Fragment-Host: system.bundle; extension:="bootclasspath"
+ * </pre>
+ *
+ * @see #EXTENSION_DIRECTIVE
+ * @since 1.3
+ */
+ public final static String EXTENSION_BOOTCLASSPATH = "bootclasspath";
+
+ /**
+ * Manifest header identifying the bundle's activation policy.
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @since 1.4
+ * @see #ACTIVATION_LAZY
+ * @see #INCLUDE_DIRECTIVE
+ * @see #EXCLUDE_DIRECTIVE
+ */
+ public final static String BUNDLE_ACTIVATIONPOLICY = "Bundle-ActivationPolicy";
+
+ /**
+ * Bundle activation policy declaring the bundle must be activated when the
+ * first class load is made from the bundle.
+ * <p>
+ * A bundle with the lazy activation policy that is started with the
+ * {@link Bundle#START_ACTIVATION_POLICY START_ACTIVATION_POLICY} option
+ * will wait in the {@link Bundle#STARTING STARTING} state until the first
+ * class load from the bundle occurs. The bundle will then be activated
+ * before the class is returned to the requester.
+ * <p>
+ * The activation policy value is specified as in the
+ * Bundle-ActivationPolicy manifest header like:
+ *
+ * <pre>
+ * Bundle-ActivationPolicy: lazy
+ * </pre>
+ *
+ * @see #BUNDLE_ACTIVATIONPOLICY
+ * @see Bundle#start(int)
+ * @see Bundle#START_ACTIVATION_POLICY
+ * @since 1.4
+ */
+ public final static String ACTIVATION_LAZY = "lazy";
+
+ /**
+ * Framework environment property identifying the Framework version.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_VERSION = "org.osgi.framework.version";
+
+ /**
+ * Framework environment property identifying the Framework implementation
+ * vendor.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_VENDOR = "org.osgi.framework.vendor";
+
+ /**
+ * Framework environment property identifying the Framework implementation
+ * language (see ISO 639 for possible values).
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_LANGUAGE = "org.osgi.framework.language";
+
+ /**
+ * Framework environment property identifying the Framework host-computer's
+ * operating system.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_OS_NAME = "org.osgi.framework.os.name";
+
+ /**
+ * Framework environment property identifying the Framework host-computer's
+ * operating system version number.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_OS_VERSION = "org.osgi.framework.os.version";
+
+ /**
+ * Framework environment property identifying the Framework host-computer's
+ * processor name.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_PROCESSOR = "org.osgi.framework.processor";
+
+ /**
+ * Framework environment property identifying execution environments
+ * provided by the Framework.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.2
+ */
+ public static final String FRAMEWORK_EXECUTIONENVIRONMENT = "org.osgi.framework.executionenvironment";
+
+ /**
+ * Framework environment property identifying packages for which the
+ * Framework must delegate class loading to the parent class loader of the
+ * bundle.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @see #FRAMEWORK_BUNDLE_PARENT
+ * @since 1.3
+ */
+ public static final String FRAMEWORK_BOOTDELEGATION = "org.osgi.framework.bootdelegation";
+
+ /**
+ * Framework environment property identifying packages which the system
+ * bundle must export.
+ *
+ * <p>
+ * If this property is not specified then the framework must calculate a
+ * reasonable default value for the current execution environment.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.3
+ */
+ public static final String FRAMEWORK_SYSTEMPACKAGES = "org.osgi.framework.system.packages";
+
+ /**
+ * Framework environment property identifying extra packages which the
+ * system bundle must export from the current execution environment.
+ *
+ * <p>
+ * This property is useful for configuring extra system packages in addition
+ * to the system packages calculated by the framework.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @see #FRAMEWORK_SYSTEMPACKAGES
+ * @since 1.5
+ */
+ public static final String FRAMEWORK_SYSTEMPACKAGES_EXTRA = "org.osgi.framework.system.packages.extra";
+
+ /**
+ * Framework environment property identifying whether the Framework supports
+ * framework extension bundles.
+ *
+ * <p>
+ * As of version 1.4, the value of this property must be <code>true</code>.
+ * The Framework must support framework extension bundles.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.3
+ */
+ public static final String SUPPORTS_FRAMEWORK_EXTENSION = "org.osgi.supports.framework.extension";
+
+ /**
+ * Framework environment property identifying whether the Framework supports
+ * bootclasspath extension bundles.
+ *
+ * <p>
+ * If the value of this property is <code>true</code>, then the Framework
+ * supports bootclasspath extension bundles. The default value is
+ * <code>false</code>.
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.3
+ */
+ public static final String SUPPORTS_BOOTCLASSPATH_EXTENSION = "org.osgi.supports.bootclasspath.extension";
+
+ /**
+ * Framework environment property identifying whether the Framework supports
+ * fragment bundles.
+ *
+ * <p>
+ * As of version 1.4, the value of this property must be <code>true</code>.
+ * The Framework must support fragment bundles.
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.3
+ */
+ public static final String SUPPORTS_FRAMEWORK_FRAGMENT = "org.osgi.supports.framework.fragment";
+
+ /**
+ * Framework environment property identifying whether the Framework supports
+ * the {@link #REQUIRE_BUNDLE Require-Bundle} manifest header.
+ *
+ * <p>
+ * As of version 1.4, the value of this property must be <code>true</code>.
+ * The Framework must support the <code>Require-Bundle</code> manifest
+ * header.
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.3
+ */
+ public static final String SUPPORTS_FRAMEWORK_REQUIREBUNDLE = "org.osgi.supports.framework.requirebundle";
+
+ /**
+ * Specifies the type of security manager the framework must use. If not
+ * specified then the framework will not set the VM security manager.
+ *
+ * @see #FRAMEWORK_SECURITY_OSGI
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_SECURITY = "org.osgi.framework.security";
+
+ /**
+ * Specifies that a security manager that supports all security aspects of
+ * the OSGi core specification including postponed conditions must be
+ * installed.
+ *
+ * <p>
+ * If this value is specified and there is a security manager already
+ * installed, then a <code>SecurityException</code> must be thrown when the
+ * Framework is initialized.
+ *
+ * @see #FRAMEWORK_SECURITY
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_SECURITY_OSGI = "osgi";
+
+ /**
+ * Specified the persistent storage area used by the framework. The value of
+ * this property must be a valid file path in the file system to a
+ * directory. If the specified directory does not exist then the framework
+ * will create the directory. If the specified path exists but is not a
+ * directory or if the framework fails to create the storage directory, then
+ * framework initialization must fail. The framework is free to use this
+ * directory as it sees fit. This area can not be shared with anything else.
+ * <p>
+ * If this property is not set, the framework should use a reasonable
+ * platform default for the persistent storage area.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_STORAGE = "org.osgi.framework.storage";
+
+ /**
+ * Specifies if and when the persistent storage area for the framework
+ * should be cleaned. If this property is not set, then the framework
+ * storage area must not be cleaned.
+ *
+ * @see #FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_STORAGE_CLEAN = "org.osgi.framework.storage.clean";
+
+ /**
+ * Specifies that the framework storage area must be cleaned before the
+ * framework is initialized for the first time. Subsequent inits, starts or
+ * updates of the framework will not result in cleaning the framework
+ * storage area.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT = "onFirstInit";
+
+ /**
+ * Specifies a comma separated list of additional library file extensions
+ * that must be used when a bundle's class loader is searching for native
+ * libraries. If this property is not set, then only the library name
+ * returned by <code>System.mapLibraryName(String)</code> will be used to
+ * search. This is needed for certain operating systems which allow more
+ * than one extension for a library. For example, AIX allows library
+ * extensions of <code>.a</code> and <code>.so</code>, but
+ * <code>System.mapLibraryName(String)</code> will only return names with
+ * the <code>.a</code> extension.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_LIBRARY_EXTENSIONS = "org.osgi.framework.library.extensions";
+
+ /**
+ * Specifies an optional OS specific command to set file permissions on
+ * extracted native code. On some operating systems, it is required that
+ * native libraries be set to executable. This optional property allows you
+ * to specify the command. For example, on a UNIX style OS, this property
+ * could have the following value.
+ *
+ * <pre>
+ * chmod +rx ${abspath}
+ * </pre>
+ *
+ * The <code>${abspath}</code> is used by the framework to substitute the
+ * actual absolute file path.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_EXECPERMISSION = "org.osgi.framework.command.execpermission";
+
+ /**
+ * Specifies the trust repositories used by the framework. The value is a
+ * <code>java.io.File.pathSeparator</code> separated list of valid file
+ * paths to files that contain key stores of type <code>JKS</code>. The
+ * framework will use the key stores as trust repositories to authenticate
+ * certificates of trusted signers. The key stores are only used as
+ * read-only trust repositories to access public keys. No passwords are
+ * required to access the key stores' public keys.
+ * <p>
+ * Note that framework implementations are allowed to use other trust
+ * repositories in addition to the trust repositories specified by this
+ * property. How these other trust repositories are configured and populated
+ * is implementation specific.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_TRUST_REPOSITORIES = "org.osgi.framework.trust.repositories";
+
+ /**
+ * Specifies the current windowing system. The framework should provide a
+ * reasonable default if this is not set.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_WINDOWSYSTEM = "org.osgi.framework.windowsystem";
+
+ /**
+ * Specifies the beginning start level of the framework.
+ *
+ * @see "Core Specification, section 8.2.3."
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_BEGINNING_STARTLEVEL = "org.osgi.framework.startlevel.beginning";
+
+ /**
+ * Specifies the parent class loader type for all bundle class loaders.
+ * Default value is {@link #FRAMEWORK_BUNDLE_PARENT_BOOT boot}.
+ *
+ * @see #FRAMEWORK_BUNDLE_PARENT_BOOT
+ * @see #FRAMEWORK_BUNDLE_PARENT_EXT
+ * @see #FRAMEWORK_BUNDLE_PARENT_APP
+ * @see #FRAMEWORK_BUNDLE_PARENT_FRAMEWORK
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_BUNDLE_PARENT = "org.osgi.framework.bundle.parent";
+
+ /**
+ * Specifies to use of the boot class loader as the parent class loader for
+ * all bundle class loaders.
+ *
+ * @since 1.5
+ * @see #FRAMEWORK_BUNDLE_PARENT
+ */
+ public final static String FRAMEWORK_BUNDLE_PARENT_BOOT = "boot";
+
+ /**
+ * Specifies to use the extension class loader as the parent class loader
+ * for all bundle class loaders.
+ *
+ * @since 1.5
+ * @see #FRAMEWORK_BUNDLE_PARENT
+ */
+ public final static String FRAMEWORK_BUNDLE_PARENT_EXT = "ext";
+
+ /**
+ * Specifies to use the application class loader as the parent class loader
+ * for all bundle class loaders. Depending on how the framework is
+ * launched, this may refer to the same class loader as
+ * {@link #FRAMEWORK_BUNDLE_PARENT_FRAMEWORK}.
+ *
+ * @since 1.5
+ * @see #FRAMEWORK_BUNDLE_PARENT
+ */
+ public final static String FRAMEWORK_BUNDLE_PARENT_APP = "app";
+
+ /**
+ * Specifies to use the framework class loader as the parent class loader
+ * for all bundle class loaders. The framework class loader is the class
+ * loader used to load the framework implementation. Depending on how the
+ * framework is launched, this may refer to the same class loader as
+ * {@link #FRAMEWORK_BUNDLE_PARENT_APP}.
+ *
+ * @since 1.5
+ * @see #FRAMEWORK_BUNDLE_PARENT
+ */
+ public final static String FRAMEWORK_BUNDLE_PARENT_FRAMEWORK = "framework";
+
+ /*
+ * Service properties.
+ */
+
+ /**
+ * Service property identifying all of the class names under which a service
+ * was registered in the Framework. The value of this property must be of
+ * type <code>String[]</code>.
+ *
+ * <p>
+ * This property is set by the Framework when a service is registered.
+ */
+ public static final String OBJECTCLASS = "objectClass";
+
+ /**
+ * Service property identifying a service's registration number. The value
+ * of this property must be of type <code>Long</code>.
+ *
+ * <p>
+ * The value of this property is assigned by the Framework when a service is
+ * registered. The Framework assigns a unique value that is larger than all
+ * previously assigned values since the Framework was started. These values
+ * are NOT persistent across restarts of the Framework.
+ */
+ public static final String SERVICE_ID = "service.id";
+
+ /**
+ * Service property identifying a service's persistent identifier.
+ *
+ * <p>
+ * This property may be supplied in the <code>properties</code>
+ * <code>Dictionary</code> object passed to the
+ * <code>BundleContext.registerService</code> method. The value of this
+ * property must be of type <code>String</code>, <code>String[]</code>, or
+ * <code>Collection</code> of <code>String</code>.
+ *
+ * <p>
+ * A service's persistent identifier uniquely identifies the service and
+ * persists across multiple Framework invocations.
+ *
+ * <p>
+ * By convention, every bundle has its own unique namespace, starting with
+ * the bundle's identifier (see {@link Bundle#getBundleId}) and followed by
+ * a dot (.). A bundle may use this as the prefix of the persistent
+ * identifiers for the services it registers.
+ */
+ public static final String SERVICE_PID = "service.pid";
+
+ /**
+ * Service property identifying a service's ranking number.
+ *
+ * <p>
+ * This property may be supplied in the <code>properties
+ * Dictionary</code> object passed to the
+ * <code>BundleContext.registerService</code> method. The value of this
+ * property must be of type <code>Integer</code>.
+ *
+ * <p>
+ * The service ranking is used by the Framework to determine the <i>natural
+ * order</i> of services, see {@link ServiceReference#compareTo(Object)},
+ * and the <i>default</i> service to be returned from a call to the
+ * {@link BundleContext#getServiceReference} method.
+ *
+ * <p>
+ * The default ranking is zero (0). A service with a ranking of
+ * <code>Integer.MAX_VALUE</code> is very likely to be returned as the
+ * default service, whereas a service with a ranking of
+ * <code>Integer.MIN_VALUE</code> is very unlikely to be returned.
+ *
+ * <p>
+ * If the supplied property value is not of type <code>Integer</code>, it is
+ * deemed to have a ranking value of zero.
+ */
+ public static final String SERVICE_RANKING = "service.ranking";
+
+ /**
+ * Service property identifying a service's vendor.
+ *
+ * <p>
+ * This property may be supplied in the properties <code>Dictionary</code>
+ * object passed to the <code>BundleContext.registerService</code> method.
+ */
+ public static final String SERVICE_VENDOR = "service.vendor";
+
+ /**
+ * Service property identifying a service's description.
+ *
+ * <p>
+ * This property may be supplied in the properties <code>Dictionary</code>
+ * object passed to the <code>BundleContext.registerService</code> method.
+ */
+ public static final String SERVICE_DESCRIPTION = "service.description";
+}
diff --git a/framework/src/main/java/org/osgi/framework/Filter.java b/framework/src/main/java/org/osgi/framework/Filter.java
new file mode 100644
index 0000000..81c3e5b
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/Filter.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.osgi.framework;
+
+import java.util.Dictionary;
+
+/**
+ * An RFC 1960-based Filter.
+ * <p>
+ * <code>Filter</code>s can be created by calling
+ * {@link BundleContext#createFilter} or {@link FrameworkUtil#createFilter} with
+ * a filter string.
+ * <p>
+ * A <code>Filter</code> can be used numerous times to determine if the match
+ * argument matches the filter string that was used to create the
+ * <code>Filter</code>.
+ * <p>
+ * Some examples of LDAP filters are:
+ *
+ * <pre>
+ * "(cn=Babs Jensen)"
+ * "(!(cn=Tim Howes))"
+ * "(&(" + Constants.OBJECTCLASS + "=Person)(|(sn=Jensen)(cn=Babs J*)))"
+ * "(o=univ*of*mich*)"
+ * </pre>
+ *
+ * @since 1.1
+ * @see "Core Specification, section 5.5, for a description of the filter string syntax."
+ * @ThreadSafe
+ * @version $Revision: 6860 $
+ */
+public interface Filter {
+ /**
+ * Filter using a service's properties.
+ * <p>
+ * This <code>Filter</code> is executed using the keys and values of the
+ * referenced service's properties. The keys are case insensitively matched
+ * with this <code>Filter</code>.
+ *
+ * @param reference The reference to the service whose properties are used
+ * in the match.
+ * @return <code>true</code> if the service's properties match this
+ * <code>Filter</code>; <code>false</code> otherwise.
+ */
+ public boolean match(ServiceReference reference);
+
+ /**
+ * Filter using a <code>Dictionary</code>. This <code>Filter</code> is
+ * executed using the specified <code>Dictionary</code>'s keys and values.
+ * The keys are case insensitively matched with this <code>Filter</code>.
+ *
+ * @param dictionary The <code>Dictionary</code> whose keys are used in the
+ * match.
+ * @return <code>true</code> if the <code>Dictionary</code>'s keys and
+ * values match this filter; <code>false</code> otherwise.
+ * @throws IllegalArgumentException If <code>dictionary</code> contains case
+ * variants of the same key name.
+ */
+ public boolean match(Dictionary dictionary);
+
+ /**
+ * Returns this <code>Filter</code>'s filter string.
+ * <p>
+ * The filter string is normalized by removing whitespace which does not
+ * affect the meaning of the filter.
+ *
+ * @return This <code>Filter</code>'s filter string.
+ */
+ public String toString();
+
+ /**
+ * Compares this <code>Filter</code> to another <code>Filter</code>.
+ *
+ * <p>
+ * This method returns the result of calling
+ * <code>this.toString().equals(obj.toString())</code>.
+ *
+ * @param obj The object to compare against this <code>Filter</code>.
+ * @return If the other object is a <code>Filter</code> object, then returns
+ * the result of calling
+ * <code>this.toString().equals(obj.toString())</code>;
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj);
+
+ /**
+ * Returns the hashCode for this <code>Filter</code>.
+ *
+ * <p>
+ * This method returns the result of calling
+ * <code>this.toString().hashCode()</code>.
+ *
+ * @return The hashCode of this <code>Filter</code>.
+ */
+ public int hashCode();
+
+ /**
+ * Filter with case sensitivity using a <code>Dictionary</code>. This
+ * <code>Filter</code> is executed using the specified
+ * <code>Dictionary</code>'s keys and values. The keys are case sensitively
+ * matched with this <code>Filter</code>.
+ *
+ * @param dictionary The <code>Dictionary</code> whose keys are used in the
+ * match.
+ * @return <code>true</code> if the <code>Dictionary</code>'s keys and
+ * values match this filter; <code>false</code> otherwise.
+ * @since 1.3
+ */
+ public boolean matchCase(Dictionary dictionary);
+}
diff --git a/framework/src/main/java/org/osgi/framework/FrameworkEvent.java b/framework/src/main/java/org/osgi/framework/FrameworkEvent.java
new file mode 100644
index 0000000..747b249
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/FrameworkEvent.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.util.EventObject;
+
+/**
+ * A general event from the Framework.
+ *
+ * <p>
+ * <code>FrameworkEvent</code> objects are delivered to
+ * <code>FrameworkListener</code>s when a general event occurs within the OSGi
+ * environment. A type code is used to identify the event type for future
+ * extendability.
+ *
+ * <p>
+ * OSGi Alliance reserves the right to extend the set of event types.
+ *
+ * @Immutable
+ * @see FrameworkListener
+ * @version $Revision: 6542 $
+ */
+
+public class FrameworkEvent extends EventObject {
+ static final long serialVersionUID = 207051004521261705L;
+ /**
+ * Bundle related to the event.
+ */
+ private final Bundle bundle;
+
+ /**
+ * Exception related to the event.
+ */
+ private final Throwable throwable;
+
+ /**
+ * Type of event.
+ */
+ private final int type;
+
+ /**
+ * The Framework has started.
+ *
+ * <p>
+ * This event is fired when the Framework has started after all installed
+ * bundles that are marked to be started have been started and the Framework
+ * has reached the initial start level. The source of this event is the
+ * System Bundle.
+ *
+ * @see "The Start Level Service"
+ */
+ public final static int STARTED = 0x00000001;
+
+ /**
+ * An error has occurred.
+ *
+ * <p>
+ * There was an error associated with a bundle.
+ */
+ public final static int ERROR = 0x00000002;
+
+ /**
+ * A PackageAdmin.refreshPackage operation has completed.
+ *
+ * <p>
+ * This event is fired when the Framework has completed the refresh packages
+ * operation initiated by a call to the PackageAdmin.refreshPackages method.
+ * The source of this event is the System Bundle.
+ *
+ * @since 1.2
+ * @see "<code>PackageAdmin.refreshPackages</code>"
+ */
+ public final static int PACKAGES_REFRESHED = 0x00000004;
+
+ /**
+ * A StartLevel.setStartLevel operation has completed.
+ *
+ * <p>
+ * This event is fired when the Framework has completed changing the active
+ * start level initiated by a call to the StartLevel.setStartLevel method.
+ * The source of this event is the System Bundle.
+ *
+ * @since 1.2
+ * @see "The Start Level Service"
+ */
+ public final static int STARTLEVEL_CHANGED = 0x00000008;
+
+ /**
+ * A warning has occurred.
+ *
+ * <p>
+ * There was a warning associated with a bundle.
+ *
+ * @since 1.3
+ */
+ public final static int WARNING = 0x00000010;
+
+ /**
+ * An informational event has occurred.
+ *
+ * <p>
+ * There was an informational event associated with a bundle.
+ *
+ * @since 1.3
+ */
+ public final static int INFO = 0x00000020;
+
+ /**
+ * The Framework has stopped.
+ *
+ * <p>
+ * This event is fired when the Framework has been stopped because of a stop
+ * operation on the system bundle. The source of this event is the System
+ * Bundle.
+ *
+ * @since 1.5
+ */
+ public final static int STOPPED = 0x00000040;
+
+ /**
+ * The Framework has stopped during update.
+ *
+ * <p>
+ * This event is fired when the Framework has been stopped because of an
+ * update operation on the system bundle. The Framework will be restarted
+ * after this event is fired. The source of this event is the System Bundle.
+ *
+ * @since 1.5
+ */
+ public final static int STOPPED_UPDATE = 0x00000080;
+
+ /**
+ * The Framework has stopped and the boot class path has changed.
+ *
+ * <p>
+ * This event is fired when the Framework has been stopped because of a stop
+ * operation on the system bundle and a bootclasspath extension bundle has
+ * been installed or updated. The source of this event is the System Bundle.
+ *
+ * @since 1.5
+ */
+ public final static int STOPPED_BOOTCLASSPATH_MODIFIED = 0x00000100;
+
+ /**
+ * The Framework did not stop before the wait timeout expired.
+ *
+ * <p>
+ * This event is fired when the Framework did not stop before the wait
+ * timeout expired. The source of this event is the System Bundle.
+ *
+ * @since 1.5
+ */
+ public final static int WAIT_TIMEDOUT = 0x00000200;
+
+ /**
+ * Creates a Framework event.
+ *
+ * @param type The event type.
+ * @param source The event source object. This may not be <code>null</code>.
+ * @deprecated As of 1.2. This constructor is deprecated in favor of using
+ * the other constructor with the System Bundle as the event
+ * source.
+ */
+ public FrameworkEvent(int type, Object source) {
+ super(source);
+ this.type = type;
+ this.bundle = null;
+ this.throwable = null;
+ }
+
+ /**
+ * Creates a Framework event regarding the specified bundle.
+ *
+ * @param type The event type.
+ * @param bundle The event source.
+ * @param throwable The related exception. This argument may be
+ * <code>null</code> if there is no related exception.
+ */
+ public FrameworkEvent(int type, Bundle bundle, Throwable throwable) {
+ super(bundle);
+ this.type = type;
+ this.bundle = bundle;
+ this.throwable = throwable;
+ }
+
+ /**
+ * Returns the exception related to this event.
+ *
+ * @return The related exception or <code>null</code> if none.
+ */
+ public Throwable getThrowable() {
+ return throwable;
+ }
+
+ /**
+ * Returns the bundle associated with the event. This bundle is also the
+ * source of the event.
+ *
+ * @return The bundle associated with the event.
+ */
+ public Bundle getBundle() {
+ return bundle;
+ }
+
+ /**
+ * Returns the type of framework event.
+ * <p>
+ * The type values are:
+ * <ul>
+ * <li>{@link #STARTED}
+ * <li>{@link #ERROR}
+ * <li>{@link #WARNING}
+ * <li>{@link #INFO}
+ * <li>{@link #PACKAGES_REFRESHED}
+ * <li>{@link #STARTLEVEL_CHANGED}
+ * <li>{@link #STOPPED}
+ * <li>{@link #STOPPED_BOOTCLASSPATH_MODIFIED}
+ * <li>{@link #STOPPED_UPDATE}
+ * <li>{@link #WAIT_TIMEDOUT}
+ * </ul>
+ *
+ * @return The type of state change.
+ */
+
+ public int getType() {
+ return type;
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/FrameworkListener.java b/framework/src/main/java/org/osgi/framework/FrameworkListener.java
new file mode 100644
index 0000000..c96c490
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/FrameworkListener.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.util.EventListener;
+
+/**
+ * A <code>FrameworkEvent</code> listener. <code>FrameworkListener</code> is
+ * a listener interface that may be implemented by a bundle developer. When a
+ * <code>FrameworkEvent</code> is fired, it is asynchronously delivered to a
+ * <code>FrameworkListener</code>. The Framework delivers
+ * <code>FrameworkEvent</code> objects to a <code>FrameworkListener</code>
+ * in order and must not concurrently call a <code>FrameworkListener</code>.
+ *
+ * <p>
+ * A <code>FrameworkListener</code> object is registered with the Framework
+ * using the {@link BundleContext#addFrameworkListener} method.
+ * <code>FrameworkListener</code> objects are called with a
+ * <code>FrameworkEvent</code> objects when the Framework starts and when
+ * asynchronous errors occur.
+ *
+ * @see FrameworkEvent
+ * @NotThreadSafe
+ * @version $Revision: 5673 $
+ */
+
+public interface FrameworkListener extends EventListener {
+
+ /**
+ * Receives notification of a general <code>FrameworkEvent</code> object.
+ *
+ * @param event The <code>FrameworkEvent</code> object.
+ */
+ public void frameworkEvent(FrameworkEvent event);
+}
diff --git a/framework/src/main/java/org/osgi/framework/FrameworkUtil.java b/framework/src/main/java/org/osgi/framework/FrameworkUtil.java
new file mode 100644
index 0000000..4a53bd3
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/FrameworkUtil.java
@@ -0,0 +1,692 @@
+/*
+ * Copyright (c) OSGi Alliance (2005, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Framework Utility class.
+ *
+ * <p>
+ * This class contains utility methods which access Framework functions that may
+ * be useful to bundles.
+ *
+ * @since 1.3
+ * @ThreadSafe
+ * @version $Revision: 7761 $
+ */
+public class FrameworkUtil {
+ /**
+ * FrameworkUtil objects may not be constructed.
+ */
+ private FrameworkUtil() {
+ // private empty constructor to prevent construction
+ }
+
+ /**
+ * Creates a <code>Filter</code> object. This <code>Filter</code> object may
+ * be used to match a <code>ServiceReference</code> object or a
+ * <code>Dictionary</code> object.
+ *
+ * <p>
+ * If the filter cannot be parsed, an {@link InvalidSyntaxException} will be
+ * thrown with a human readable message where the filter became unparsable.
+ *
+ * <p>
+ * This method returns a Filter implementation which may not perform as well
+ * as the framework implementation-specific Filter implementation returned
+ * by {@link BundleContext#createFilter(String)}.
+ *
+ * @param filter The filter string.
+ * @return A <code>Filter</code> object encapsulating the filter string.
+ * @throws InvalidSyntaxException If <code>filter</code> contains an invalid
+ * filter string that cannot be parsed.
+ * @throws NullPointerException If <code>filter</code> is null.
+ *
+ * @see Filter
+ */
+ public static Filter createFilter(String filter)
+ throws InvalidSyntaxException {
+ return new org.apache.felix.framework.FilterImpl(filter);
+ }
+
+ /**
+ * Match a Distinguished Name (DN) chain against a pattern. DNs can be
+ * matched using wildcards. A wildcard ('*' \u002A) replaces all
+ * possible values. Due to the structure of the DN, the comparison is more
+ * complicated than string-based wildcard matching.
+ * <p>
+ * A wildcard can stand for zero or more DNs in a chain, a number of
+ * relative distinguished names (RDNs) within a DN, or the value of a single
+ * RDN. The DNs in the chain and the matching pattern are canonicalized
+ * before processing. This means, among other things, that spaces must be
+ * ignored, except in values.
+ * <p>
+ * The format of a wildcard match pattern is:
+ *
+ * <pre>
+ * matchPattern ::= dn-match ( ';' dn-match ) *
+ * dn-match ::= ( '*' | rdn-match ) ( ',' rdn-match ) * | '-'
+ * rdn-match ::= name '=' value-match
+ * value-match ::= '*' | value-star
+ * value-star ::= < value, requires escaped '*' and '-' >
+ * </pre>
+ * <p>
+ * The most simple case is a single wildcard; it must match any DN. A
+ * wildcard can also replace the first list of RDNs of a DN. The first RDNs
+ * are the least significant. Such lists of matched RDNs can be empty.
+ * <p>
+ * For example, a match pattern with a wildcard that matches all all DNs
+ * that end with RDNs of o=ACME and c=US would look like this:
+ *
+ * <pre>
+ * *, o=ACME, c=US
+ * </pre>
+ *
+ * This match pattern would match the following DNs:
+ *
+ * <pre>
+ * cn = Bugs Bunny, o = ACME, c = US
+ * ou = Carrots, cn=Daffy Duck, o=ACME, c=US
+ * street = 9C\, Avenue St. Drézéry, o=ACME, c=US
+ * dc=www, dc=acme, dc=com, o=ACME, c=US
+ * o=ACME, c=US
+ * </pre>
+ *
+ * The following DNs would not match:
+ *
+ * <pre>
+ * street = 9C\, Avenue St. Drézéry, o=ACME, c=FR
+ * dc=www, dc=acme, dc=com, c=US
+ * </pre>
+ *
+ * If a wildcard is used for a value of an RDN, the value must be exactly *.
+ * The wildcard must match any value, and no substring matching must be
+ * done. For example:
+ *
+ * <pre>
+ * cn=*,o=ACME,c=*
+ * </pre>
+ *
+ * This match pattern with wildcard must match the following DNs:
+ *
+ * <pre>
+ * cn=Bugs Bunny,o=ACME,c=US
+ * cn = Daffy Duck , o = ACME , c = US
+ * cn=Road Runner, o=ACME, c=NL
+ * </pre>
+ *
+ * But not:
+ *
+ * <pre>
+ * o=ACME, c=NL
+ * dc=acme.com, cn=Bugs Bunny, o=ACME, c=US
+ * </pre>
+ *
+ * <p>
+ * A match pattern may contain a chain of DN match patterns. The
+ * semicolon(';' \u003B) must be used to separate DN match patterns in a
+ * chain. Wildcards can also be used to match against a complete DN within a
+ * chain.
+ * <p>
+ * The following example matches a certificate signed by Tweety Inc. in the
+ * US.
+ * </p>
+ *
+ * <pre>
+ * * ; ou=S & V, o=Tweety Inc., c=US
+ * </pre>
+ * <p>
+ * The wildcard ('*') matches zero or one DN in the chain, however,
+ * sometimes it is necessary to match a longer chain. The minus sign ('-'
+ * \u002D) represents zero or more DNs, whereas the asterisk only
+ * represents a single DN. For example, to match a DN where the Tweety Inc.
+ * is in the DN chain, use the following expression:
+ * </p>
+ *
+ * <pre>
+ * - ; *, o=Tweety Inc., c=US
+ * </pre>
+ *
+ * @param matchPattern The pattern against which to match the DN chain.
+ * @param dnChain The DN chain to match against the specified pattern. Each
+ * element of the chain must be of type <code>String</code> and use
+ * the format defined in RFC 2253.
+ * @return <code>true</code> If the pattern matches the DN chain; otherwise
+ * <code>false</code> is returned.
+ * @throws IllegalArgumentException If the specified match pattern or DN
+ * chain is invalid.
+ * @since 1.5
+ */
+ public static boolean matchDistinguishedNameChain(String matchPattern,
+ List /* <String> */dnChain) {
+ return DNChainMatching.match(matchPattern, dnChain);
+ }
+
+ /**
+ * Return a <code>Bundle</code> for the specified bundle class. The returned
+ * <code>Bundle</code> is the bundle associated with the bundle class loader
+ * which defined the specified class.
+ *
+ * @param classFromBundle A class defined by a bundle class loader.
+ * @return A <code>Bundle</code> for the specified bundle class or
+ * <code>null</code> if the specified class was not defined by a
+ * bundle class loader.
+ * @since 1.5
+ */
+ public static Bundle getBundle(final Class classFromBundle) {
+ // We use doPriv since the caller may not have permission
+ // to call getClassLoader.
+ Object cl = AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return classFromBundle.getClassLoader();
+ }
+ });
+
+ if (cl instanceof BundleReference) {
+ return ((BundleReference) cl).getBundle();
+ }
+ return null;
+ }
+
+ /**
+ * This class contains a method to match a distinguished name (DN) chain
+ * against and DN chain pattern.
+ * <p>
+ * The format of DNs are given in RFC 2253. We represent a signature chain
+ * for an X.509 certificate as a semicolon separated list of DNs. This is
+ * what we refer to as the DN chain. Each DN is made up of relative
+ * distinguished names (RDN) which in turn are made up of key value pairs.
+ * For example:
+ *
+ * <pre>
+ * cn=ben+ou=research,o=ACME,c=us;ou=Super CA,c=CA
+ * </pre>
+ *
+ * is made up of two DNs: "<code>cn=ben+ou=research,o=ACME,c=us</code>
+ * " and " <code>ou=Super CA,c=CA</code>
+ * ". The first DN is made of of three RDNs: "
+ * <code>cn=ben+ou=research</code>" and "<code>o=ACME</code>" and "
+ * <code>c=us</code>". The first RDN has two name value pairs: "
+ * <code>cn=ben</code>" and "<code>ou=research</code>".
+ * <p>
+ * A chain pattern makes use of wildcards ('*' or '-') to match against DNs,
+ * and wildcards ('*') to match againts DN prefixes, and value. If a DN in a
+ * match pattern chain is made up of a wildcard ("*"), that wildcard will
+ * match zero or one DNs in the chain. If a DN in a match pattern chain is
+ * made up of a wildcard ("-"), that wildcard will match zero or more DNs in
+ * the chain. If the first RDN of a DN is the wildcard ("*"), that DN will
+ * match any other DN with the same suffix (the DN with the wildcard RDN
+ * removed). If a value of a name/value pair is a wildcard ("*"), the value
+ * will match any value for that name.
+ */
+ private static class DNChainMatching {
+ private static final String MINUS_WILDCARD = "-";
+ private static final String STAR_WILDCARD = "*";
+
+ /**
+ * Check the name/value pairs of the rdn against the pattern.
+ *
+ * @param rdn List of name value pairs for a given RDN.
+ * @param rdnPattern List of name value pattern pairs.
+ * @return true if the list of name value pairs match the pattern.
+ */
+ private static boolean rdnmatch(List rdn, List rdnPattern) {
+ if (rdn.size() != rdnPattern.size()) {
+ return false;
+ }
+ for (int i = 0; i < rdn.size(); i++) {
+ String rdnNameValue = (String) rdn.get(i);
+ String patNameValue = (String) rdnPattern.get(i);
+ int rdnNameEnd = rdnNameValue.indexOf('=');
+ int patNameEnd = patNameValue.indexOf('=');
+ if (rdnNameEnd != patNameEnd
+ || !rdnNameValue.regionMatches(0, patNameValue, 0,
+ rdnNameEnd)) {
+ return false;
+ }
+ String patValue = patNameValue.substring(patNameEnd);
+ String rdnValue = rdnNameValue.substring(rdnNameEnd);
+ if (!rdnValue.equals(patValue) && !patValue.equals("=*")
+ && !patValue.equals("=#16012a")) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean dnmatch(List dn, List dnPattern) {
+ int dnStart = 0;
+ int patStart = 0;
+ int patLen = dnPattern.size();
+ if (patLen == 0) {
+ return false;
+ }
+ if (dnPattern.get(0).equals(STAR_WILDCARD)) {
+ patStart = 1;
+ patLen--;
+ }
+ if (dn.size() < patLen) {
+ return false;
+ }
+ else {
+ if (dn.size() > patLen) {
+ if (!dnPattern.get(0).equals(STAR_WILDCARD)) {
+ // If the number of rdns do not match we must have a
+ // prefix map
+ return false;
+ }
+ // The rdnPattern and rdn must have the same number of
+ // elements
+ dnStart = dn.size() - patLen;
+ }
+ }
+ for (int i = 0; i < patLen; i++) {
+ if (!rdnmatch((List) dn.get(i + dnStart), (List) dnPattern
+ .get(i + patStart))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Parses a distinguished name chain pattern and returns a List where
+ * each element represents a distinguished name (DN) in the chain of
+ * DNs. Each element will be either a String, if the element represents
+ * a wildcard ("*" or "-"), or a List representing an RDN. Each element
+ * in the RDN List will be a String, if the element represents a
+ * wildcard ("*"), or a List of Strings, each String representing a
+ * name/value pair in the RDN.
+ *
+ * @param dnChain
+ * @return a list of DNs.
+ * @throws IllegalArgumentException
+ */
+ private static List parseDNchainPattern(String dnChain) {
+ if (dnChain == null) {
+ throw new IllegalArgumentException(
+ "The DN chain must not be null.");
+ }
+ List parsed = new ArrayList();
+ int startIndex = 0;
+ startIndex = skipSpaces(dnChain, startIndex);
+ while (startIndex < dnChain.length()) {
+ int endIndex = startIndex;
+ boolean inQuote = false;
+ out: while (endIndex < dnChain.length()) {
+ char c = dnChain.charAt(endIndex);
+ switch (c) {
+ case '"' :
+ inQuote = !inQuote;
+ break;
+ case '\\' :
+ endIndex++; // skip the escaped char
+ break;
+ case ';' :
+ if (!inQuote)
+ break out;
+ }
+ endIndex++;
+ }
+ if (endIndex > dnChain.length()) {
+ throw new IllegalArgumentException("unterminated escape");
+ }
+ parsed.add(dnChain.substring(startIndex, endIndex));
+ startIndex = endIndex + 1;
+ startIndex = skipSpaces(dnChain, startIndex);
+ }
+ return parseDNchain(parsed);
+ }
+
+ private static List parseDNchain(List chain) {
+ if (chain == null) {
+ throw new IllegalArgumentException("DN chain must not be null.");
+ }
+ chain = new ArrayList(chain);
+ // Now we parse is a list of strings, lets make List of rdn out
+ // of them
+ for (int i = 0; i < chain.size(); i++) {
+ String dn = (String) chain.get(i);
+ if (dn.equals(STAR_WILDCARD) || dn.equals(MINUS_WILDCARD)) {
+ continue;
+ }
+ List rdns = new ArrayList();
+ if (dn.charAt(0) == '*') {
+ if (dn.charAt(1) != ',') {
+ throw new IllegalArgumentException(
+ "invalid wildcard prefix");
+ }
+ rdns.add(STAR_WILDCARD);
+ dn = new X500Principal(dn.substring(2))
+ .getName(X500Principal.CANONICAL);
+ }
+ else {
+ dn = new X500Principal(dn).getName(X500Principal.CANONICAL);
+ }
+ // Now dn is a nice CANONICAL DN
+ parseDN(dn, rdns);
+ chain.set(i, rdns);
+ }
+ if (chain.size() == 0) {
+ throw new IllegalArgumentException("empty DN chain");
+ }
+ return chain;
+ }
+
+ /**
+ * Increment startIndex until the end of dnChain is hit or until it is
+ * the index of a non-space character.
+ */
+ private static int skipSpaces(String dnChain, int startIndex) {
+ while (startIndex < dnChain.length()
+ && dnChain.charAt(startIndex) == ' ') {
+ startIndex++;
+ }
+ return startIndex;
+ }
+
+ /**
+ * Takes a distinguished name in canonical form and fills in the
+ * rdnArray with the extracted RDNs.
+ *
+ * @param dn the distinguished name in canonical form.
+ * @param rdn the list to fill in with RDNs extracted from the dn
+ * @throws IllegalArgumentException if a formatting error is found.
+ */
+ private static void parseDN(String dn, List rdn) {
+ int startIndex = 0;
+ char c = '\0';
+ List nameValues = new ArrayList();
+ while (startIndex < dn.length()) {
+ int endIndex;
+ for (endIndex = startIndex; endIndex < dn.length(); endIndex++) {
+ c = dn.charAt(endIndex);
+ if (c == ',' || c == '+') {
+ break;
+ }
+ if (c == '\\') {
+ endIndex++; // skip the escaped char
+ }
+ }
+ if (endIndex > dn.length()) {
+ throw new IllegalArgumentException("unterminated escape "
+ + dn);
+ }
+ nameValues.add(dn.substring(startIndex, endIndex));
+ if (c != '+') {
+ rdn.add(nameValues);
+ if (endIndex != dn.length()) {
+ nameValues = new ArrayList();
+ }
+ else {
+ nameValues = null;
+ }
+ }
+ startIndex = endIndex + 1;
+ }
+ if (nameValues != null) {
+ throw new IllegalArgumentException("improperly terminated DN "
+ + dn);
+ }
+ }
+
+ /**
+ * This method will return an 'index' which points to a non-wildcard DN
+ * or the end-of-list.
+ */
+ private static int skipWildCards(List dnChainPattern,
+ int dnChainPatternIndex) {
+ int i;
+ for (i = dnChainPatternIndex; i < dnChainPattern.size(); i++) {
+ Object dnPattern = dnChainPattern.get(i);
+ if (dnPattern instanceof String) {
+ if (!dnPattern.equals(STAR_WILDCARD)
+ && !dnPattern.equals(MINUS_WILDCARD)) {
+ throw new IllegalArgumentException(
+ "expected wildcard in DN pattern");
+ }
+ // otherwise continue skipping over wild cards
+ }
+ else {
+ if (dnPattern instanceof List) {
+ // if its a list then we have our 'non-wildcard' DN
+ break;
+ }
+ else {
+ // unknown member of the DNChainPattern
+ throw new IllegalArgumentException(
+ "expected String or List in DN Pattern");
+ }
+ }
+ }
+ // i either points to end-of-list, or to the first
+ // non-wildcard pattern after dnChainPatternIndex
+ return i;
+ }
+
+ /**
+ * recursively attempt to match the DNChain, and the DNChainPattern
+ * where DNChain is of the format: "DN;DN;DN;" and DNChainPattern is of
+ * the format: "DNPattern;*;DNPattern" (or combinations of this)
+ */
+ private static boolean dnChainMatch(List dnChain, int dnChainIndex,
+ List dnChainPattern, int dnChainPatternIndex)
+ throws IllegalArgumentException {
+ if (dnChainIndex >= dnChain.size()) {
+ return false;
+ }
+ if (dnChainPatternIndex >= dnChainPattern.size()) {
+ return false;
+ }
+ // check to see what the pattern starts with
+ Object dnPattern = dnChainPattern.get(dnChainPatternIndex);
+ if (dnPattern instanceof String) {
+ if (!dnPattern.equals(STAR_WILDCARD)
+ && !dnPattern.equals(MINUS_WILDCARD)) {
+ throw new IllegalArgumentException(
+ "expected wildcard in DN pattern");
+ }
+ // here we are processing a wild card as the first DN
+ // skip all wildcard DN's
+ if (dnPattern.equals(MINUS_WILDCARD)) {
+ dnChainPatternIndex = skipWildCards(dnChainPattern,
+ dnChainPatternIndex);
+ }
+ else {
+ dnChainPatternIndex++; // only skip the '*' wildcard
+ }
+ if (dnChainPatternIndex >= dnChainPattern.size()) {
+ // return true iff the wild card is '-' or if we are at the
+ // end of the chain
+ return dnPattern.equals(MINUS_WILDCARD) ? true : dnChain
+ .size() - 1 == dnChainIndex;
+ }
+ //
+ // we will now recursively call to see if the rest of the
+ // DNChainPattern matches increasingly smaller portions of the
+ // rest of the DNChain
+ //
+ if (dnPattern.equals(STAR_WILDCARD)) {
+ // '*' option: only wildcard on 0 or 1
+ return dnChainMatch(dnChain, dnChainIndex, dnChainPattern,
+ dnChainPatternIndex)
+ || dnChainMatch(dnChain, dnChainIndex + 1,
+ dnChainPattern, dnChainPatternIndex);
+ }
+ for (int i = dnChainIndex; i < dnChain.size(); i++) {
+ // '-' option: wildcard 0 or more
+ if (dnChainMatch(dnChain, i, dnChainPattern,
+ dnChainPatternIndex)) {
+ return true;
+ }
+ }
+ // if we are here, then we didn't find a match.. fall through to
+ // failure
+ }
+ else {
+ if (dnPattern instanceof List) {
+ // here we have to do a deeper check for each DN in the
+ // pattern until we hit a wild card
+ do {
+ if (!dnmatch((List) dnChain.get(dnChainIndex),
+ (List) dnPattern)) {
+ return false;
+ }
+ // go to the next set of DN's in both chains
+ dnChainIndex++;
+ dnChainPatternIndex++;
+ // if we finished the pattern then it all matched
+ if ((dnChainIndex >= dnChain.size())
+ && (dnChainPatternIndex >= dnChainPattern
+ .size())) {
+ return true;
+ }
+ // if the DN Chain is finished, but the pattern isn't
+ // finished then if the rest of the pattern is not
+ // wildcard then we are done
+ if (dnChainIndex >= dnChain.size()) {
+ dnChainPatternIndex = skipWildCards(dnChainPattern,
+ dnChainPatternIndex);
+ // return TRUE iff the pattern index moved past the
+ // list-size (implying that the rest of the pattern
+ // is all wildcards)
+ return dnChainPatternIndex >= dnChainPattern.size();
+ }
+ // if the pattern finished, but the chain continues then
+ // we have a mis-match
+ if (dnChainPatternIndex >= dnChainPattern.size()) {
+ return false;
+ }
+ // get the next DN Pattern
+ dnPattern = dnChainPattern.get(dnChainPatternIndex);
+ if (dnPattern instanceof String) {
+ if (!dnPattern.equals(STAR_WILDCARD)
+ && !dnPattern.equals(MINUS_WILDCARD)) {
+ throw new IllegalArgumentException(
+ "expected wildcard in DN pattern");
+ }
+ // if the next DN is a 'wildcard', then we will
+ // recurse
+ return dnChainMatch(dnChain, dnChainIndex,
+ dnChainPattern, dnChainPatternIndex);
+ }
+ else {
+ if (!(dnPattern instanceof List)) {
+ throw new IllegalArgumentException(
+ "expected String or List in DN Pattern");
+ }
+ }
+ // if we are here, then we will just continue to the
+ // match the next set of DN's from the DNChain, and the
+ // DNChainPattern since both are lists
+ } while (true);
+ // should never reach here?
+ }
+ else {
+ throw new IllegalArgumentException(
+ "expected String or List in DN Pattern");
+ }
+ }
+ // if we get here, the the default return is 'mis-match'
+ return false;
+ }
+
+ /**
+ * Matches a distinguished name chain against a pattern of a
+ * distinguished name chain.
+ *
+ * @param dnChain
+ * @param pattern the pattern of distinguished name (DN) chains to match
+ * against the dnChain. Wildcards ("*" or "-") can be used in
+ * three cases:
+ * <ol>
+ * <li>As a DN. In this case, the DN will consist of just the "*"
+ * or "-". When "*" is used it will match zero or one DNs. When
+ * "-" is used it will match zero or more DNs. For example,
+ * "cn=me,c=US;*;cn=you" will match
+ * "cn=me,c=US";cn=you" and "cn=me,c=US;cn=her;cn=you". The
+ * pattern "cn=me,c=US;-;cn=you" will match "cn=me,c=US";cn=you"
+ * and "cn=me,c=US;cn=her;cn=him;cn=you".
+ * <li>As a DN prefix. In this case, the DN must start with "*,".
+ * The wild card will match zero or more RDNs at the start of a
+ * DN. For example, "*,cn=me,c=US;cn=you" will match
+ * "cn=me,c=US";cn=you" and
+ * "ou=my org unit,o=my org,cn=me,c=US;cn=you"</li>
+ * <li>As a value. In this case the value of a name value pair in
+ * an RDN will be a "*". The wildcard will match any value for
+ * the given name. For example, "cn=*,c=US;cn=you" will match
+ * "cn=me,c=US";cn=you" and "cn=her,c=US;cn=you", but it will not
+ * match "ou=my org unit,c=US;cn=you". If the wildcard does not
+ * occur by itself in the value, it will not be used as a
+ * wildcard. In other words, "cn=m*,c=US;cn=you" represents the
+ * common name of "m*" not any common name starting with "m".</li>
+ * </ol>
+ * @return true if dnChain matches the pattern.
+ * @throws IllegalArgumentException
+ */
+ static boolean match(String pattern, List/* <String> */dnChain) {
+ List parsedDNChain;
+ List parsedDNPattern;
+ try {
+ parsedDNChain = parseDNchain(dnChain);
+ }
+ catch (RuntimeException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "Invalid DN chain: " + toString(dnChain));
+ iae.initCause(e);
+ throw iae;
+ }
+ try {
+ parsedDNPattern = parseDNchainPattern(pattern);
+ }
+ catch (RuntimeException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "Invalid match pattern: " + pattern);
+ iae.initCause(e);
+ throw iae;
+ }
+ return dnChainMatch(parsedDNChain, 0, parsedDNPattern, 0);
+ }
+
+ private static String toString(List dnChain) {
+ if (dnChain == null) {
+ return null;
+ }
+ StringBuffer sb = new StringBuffer();
+ for (Iterator iChain = dnChain.iterator(); iChain.hasNext();) {
+ sb.append(iChain.next());
+ if (iChain.hasNext()) {
+ sb.append("; ");
+ }
+ }
+ return sb.toString();
+ }
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/InvalidSyntaxException.java b/framework/src/main/java/org/osgi/framework/InvalidSyntaxException.java
new file mode 100644
index 0000000..f67fd43
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/InvalidSyntaxException.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * A Framework exception used to indicate that a filter string has an invalid
+ * syntax.
+ *
+ * <p>
+ * An <code>InvalidSyntaxException</code> object indicates that a filter
+ * string parameter has an invalid syntax and cannot be parsed. See
+ * {@link Filter} for a description of the filter string syntax.
+ *
+ * <p>
+ * This exception conforms to the general purpose exception chaining mechanism.
+ *
+ * @version $Revision: 6083 $
+ */
+
+public class InvalidSyntaxException extends Exception {
+ static final long serialVersionUID = -4295194420816491875L;
+ /**
+ * The invalid filter string.
+ */
+ private final String filter;
+
+ /**
+ * Creates an exception of type <code>InvalidSyntaxException</code>.
+ *
+ * <p>
+ * This method creates an <code>InvalidSyntaxException</code> object with
+ * the specified message and the filter string which generated the
+ * exception.
+ *
+ * @param msg The message.
+ * @param filter The invalid filter string.
+ */
+ public InvalidSyntaxException(String msg, String filter) {
+ super(msg);
+ this.filter = filter;
+ }
+
+ /**
+ * Creates an exception of type <code>InvalidSyntaxException</code>.
+ *
+ * <p>
+ * This method creates an <code>InvalidSyntaxException</code> object with
+ * the specified message and the filter string which generated the
+ * exception.
+ *
+ * @param msg The message.
+ * @param filter The invalid filter string.
+ * @param cause The cause of this exception.
+ * @since 1.3
+ */
+ public InvalidSyntaxException(String msg, String filter, Throwable cause) {
+ super(msg, cause);
+ this.filter = filter;
+ }
+
+ /**
+ * Returns the filter string that generated the
+ * <code>InvalidSyntaxException</code> object.
+ *
+ * @return The invalid filter string.
+ * @see BundleContext#getServiceReferences
+ * @see BundleContext#addServiceListener(ServiceListener,String)
+ */
+ public String getFilter() {
+ return filter;
+ }
+
+ /**
+ * Returns the cause of this exception or <code>null</code> if no cause was
+ * set.
+ *
+ * @return The cause of this exception or <code>null</code> if no cause was
+ * set.
+ * @since 1.3
+ */
+ public Throwable getCause() {
+ return super.getCause();
+ }
+
+ /**
+ * Initializes the cause of this exception to the specified value.
+ *
+ * @param cause The cause of this exception.
+ * @return This exception.
+ * @throws IllegalArgumentException If the specified cause is this
+ * exception.
+ * @throws IllegalStateException If the cause of this exception has already
+ * been set.
+ * @since 1.3
+ */
+ public Throwable initCause(Throwable cause) {
+ return super.initCause(cause);
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/PackagePermission.java b/framework/src/main/java/org/osgi/framework/PackagePermission.java
new file mode 100644
index 0000000..da2f540
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/PackagePermission.java
@@ -0,0 +1,811 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.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.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A bundle's authority to import or export a package.
+ *
+ * <p>
+ * A package is a dot-separated string that defines a fully qualified Java
+ * package.
+ * <p>
+ * For example:
+ *
+ * <pre>
+ * org.osgi.service.http
+ * </pre>
+ *
+ * <p>
+ * <code>PackagePermission</code> has three actions: <code>exportonly</code>,
+ * <code>import</code> and <code>export</code>. The <code>export</code> action,
+ * which is deprecated, implies the <code>import</code> action.
+ *
+ * @ThreadSafe
+ * @version $Revision: 7189 $
+ */
+
+public final class PackagePermission extends BasicPermission {
+ static final long serialVersionUID = -5107705877071099135L;
+
+ /**
+ * The action string <code>export</code>. The <code>export</code> action
+ * implies the <code>import</code> action.
+ *
+ * @deprecated Since 1.5. Use <code>exportonly</code> instead.
+ */
+ public final static String EXPORT = "export";
+
+ /**
+ * The action string <code>exportonly</code>. The <code>exportonly</code>
+ * action does not imply the <code>import</code> action.
+ *
+ * @since 1.5
+ */
+ public final static String EXPORTONLY = "exportonly";
+
+ /**
+ * The action string <code>import</code>.
+ */
+ public final static String IMPORT = "import";
+
+ private final static int ACTION_EXPORT = 0x00000001;
+ private final static int ACTION_IMPORT = 0x00000002;
+ private final static int ACTION_ALL = ACTION_EXPORT
+ | ACTION_IMPORT;
+ final static int ACTION_NONE = 0;
+
+ /**
+ * The actions mask.
+ */
+ transient int action_mask;
+
+ /**
+ * The actions in canonical form.
+ *
+ * @serial
+ */
+ private volatile String actions = null;
+
+ /**
+ * The bundle used by this PackagePermission.
+ */
+ transient final Bundle bundle;
+
+ /**
+ * If this PackagePermission was constructed with a filter, this holds a
+ * Filter matching object used to evaluate the filter in implies.
+ */
+ transient Filter filter;
+
+ /**
+ * This dictionary holds the properties of the permission, used to match a
+ * filter in implies. This is not initialized until necessary, and then
+ * cached in this object.
+ */
+ private transient volatile Dictionary properties;
+
+ /**
+ * Creates a new <code>PackagePermission</code> object.
+ *
+ * <p>
+ * The name is specified as a normal Java package name: a dot-separated
+ * string. Wildcards may be used.
+ *
+ * <pre>
+ * name ::= <package name> | <package name ending in ".*"> | *
+ * </pre>
+ *
+ * Examples:
+ *
+ * <pre>
+ * org.osgi.service.http
+ * javax.servlet.*
+ * *
+ * </pre>
+ *
+ * For the <code>import</code> action, the name can also be a filter
+ * expression. The filter gives access to the following attributes:
+ * <ul>
+ * <li>signer - A Distinguished Name chain used to sign the exporting
+ * bundle. Wildcards in a DN are not matched according to the filter string
+ * rules, but according to the rules defined for a DN chain.</li>
+ * <li>location - The location of the exporting bundle.</li>
+ * <li>id - The bundle ID of the exporting bundle.</li>
+ * <li>name - The symbolic name of the exporting bundle.</li>
+ * <li>package.name - The name of the requested package.</li>
+ * </ul>
+ * Filter attribute names are processed in a case sensitive manner.
+ *
+ * <p>
+ * Package Permissions are granted over all possible versions of a package.
+ *
+ * A bundle that needs to export a package must have the appropriate
+ * <code>PackagePermission</code> for that package; similarly, a bundle that
+ * needs to import a package must have the appropriate
+ * <code>PackagePermssion</code> for that package.
+ * <p>
+ * Permission is granted for both classes and resources.
+ *
+ * @param name Package name or filter expression. A filter expression can
+ * only be specified if the specified action is <code>import</code>.
+ * @param actions <code>exportonly</code>,<code>import</code> (canonical
+ * order).
+ * @throws IllegalArgumentException If the specified name is a filter
+ * expression and either the specified action is not
+ * <code>import</code> or the filter has an invalid syntax.
+ */
+ public PackagePermission(String name, String actions) {
+ this(name, parseActions(actions));
+ if ((filter != null)
+ && ((action_mask & ACTION_ALL) != ACTION_IMPORT)) {
+ throw new IllegalArgumentException(
+ "invalid action string for filter expression");
+ }
+ }
+
+ /**
+ * Creates a new requested <code>PackagePermission</code> object to be used
+ * by code that must perform <code>checkPermission</code> for the
+ * <code>import</code> action. <code>PackagePermission</code> objects
+ * created with this constructor cannot be added to a
+ * <code>PackagePermission</code> permission collection.
+ *
+ * @param name The name of the requested package to import.
+ * @param exportingBundle The bundle exporting the requested package.
+ * @param actions The action <code>import</code>.
+ * @throws IllegalArgumentException If the specified action is not
+ * <code>import</code> or the name is a filter expression.
+ * @since 1.5
+ */
+ public PackagePermission(String name, Bundle exportingBundle, String actions) {
+ super(name);
+ setTransients(name, parseActions(actions));
+ this.bundle = exportingBundle;
+ if (exportingBundle == null) {
+ throw new IllegalArgumentException("bundle must not be null");
+ }
+ if (filter != null) {
+ throw new IllegalArgumentException("invalid name");
+ }
+ if ((action_mask & ACTION_ALL) != ACTION_IMPORT) {
+ throw new IllegalArgumentException("invalid action string");
+ }
+ }
+
+ /**
+ * Package private constructor used by PackagePermissionCollection.
+ *
+ * @param name package name
+ * @param mask action mask
+ */
+ PackagePermission(String name, int mask) {
+ super(name);
+ setTransients(name, mask);
+ this.bundle = null;
+ }
+
+ /**
+ * Called by constructors and when deserialized.
+ *
+ * @param mask action mask
+ */
+ private void setTransients(String name, int mask) {
+ if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
+ throw new IllegalArgumentException("invalid action string");
+ }
+ action_mask = mask;
+ filter = parseFilter(name);
+ }
+
+ /**
+ * 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 >= 5 && (a[i - 5] == 'i' || a[i - 5] == 'I')
+ && (a[i - 4] == 'm' || a[i - 4] == 'M')
+ && (a[i - 3] == 'p' || a[i - 3] == 'P')
+ && (a[i - 2] == 'o' || a[i - 2] == 'O')
+ && (a[i - 1] == 'r' || a[i - 1] == 'R')
+ && (a[i] == 't' || a[i] == 'T')) {
+ matchlen = 6;
+ mask |= ACTION_IMPORT;
+
+ }
+ else
+ if (i >= 5 && (a[i - 5] == 'e' || a[i - 5] == 'E')
+ && (a[i - 4] == 'x' || a[i - 4] == 'X')
+ && (a[i - 3] == 'p' || a[i - 3] == 'P')
+ && (a[i - 2] == 'o' || a[i - 2] == 'O')
+ && (a[i - 1] == 'r' || a[i - 1] == 'R')
+ && (a[i] == 't' || a[i] == 'T')) {
+ matchlen = 6;
+ mask |= ACTION_EXPORT | ACTION_IMPORT;
+
+ }
+ else {
+ if (i >= 9 && (a[i - 9] == 'e' || a[i - 9] == 'E')
+ && (a[i - 8] == 'x' || a[i - 8] == 'X')
+ && (a[i - 7] == 'p' || a[i - 7] == 'P')
+ && (a[i - 6] == 'o' || a[i - 6] == 'O')
+ && (a[i - 5] == 'r' || a[i - 5] == 'R')
+ && (a[i - 4] == 't' || a[i - 4] == 'T')
+ && (a[i - 3] == 'o' || a[i - 3] == 'O')
+ && (a[i - 2] == 'n' || a[i - 2] == 'N')
+ && (a[i - 1] == 'l' || a[i - 1] == 'L')
+ && (a[i] == 'y' || a[i] == 'Y')) {
+ matchlen = 10;
+ mask |= ACTION_EXPORT;
+
+ }
+ else {
+ // parse error
+ throw new IllegalArgumentException(
+ "invalid permission: " + actions);
+ }
+ }
+
+ // make sure we didn't just match the tail of a word
+ // like "ackbarfimport". Also, skip to the comma.
+ seencomma = false;
+ while (i >= matchlen && !seencomma) {
+ switch (a[i - matchlen]) {
+ case ',' :
+ seencomma = true;
+ /* FALLTHROUGH */
+ case ' ' :
+ case '\r' :
+ case '\n' :
+ case '\f' :
+ case '\t' :
+ break;
+ default :
+ throw new IllegalArgumentException(
+ "invalid permission: " + actions);
+ }
+ i--;
+ }
+
+ // point i at the location of the comma minus one (or -1).
+ i -= matchlen;
+ }
+
+ if (seencomma) {
+ throw new IllegalArgumentException("invalid permission: " + actions);
+ }
+
+ return mask;
+ }
+
+ /**
+ * Parse filter string into a Filter object.
+ *
+ * @param filterString The filter string to parse.
+ * @return a Filter for this bundle. If the specified filterString is not a
+ * filter expression, then <code>null</code> is returned.
+ * @throws IllegalArgumentException If the filter syntax is invalid.
+ */
+ private static Filter parseFilter(String filterString) {
+ filterString = filterString.trim();
+ if (filterString.charAt(0) != '(') {
+ return null;
+ }
+
+ try {
+ return FrameworkUtil.createFilter(filterString);
+ }
+ catch (InvalidSyntaxException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "invalid filter");
+ iae.initCause(e);
+ throw iae;
+ }
+ }
+
+ /**
+ * Determines if the specified permission is implied by this object.
+ *
+ * <p>
+ * This method checks that the package name of the target is implied by the
+ * package name of this object. The list of <code>PackagePermission</code>
+ * actions must either match or allow for the list of the target object to
+ * imply the target <code>PackagePermission</code> action.
+ * <p>
+ * The permission to export a package implies the permission to import the
+ * named package.
+ *
+ * <pre>
+ * x.y.*,"export" -> x.y.z,"export" is true
+ * *,"import" -> x.y, "import" is true
+ * *,"export" -> x.y, "import" is true
+ * x.y,"export" -> x.y.z, "export" is false
+ * </pre>
+ *
+ * @param p The requested permission.
+ * @return <code>true</code> if the specified permission is implied by this
+ * object; <code>false</code> otherwise.
+ */
+ public boolean implies(Permission p) {
+ if (!(p instanceof PackagePermission)) {
+ return false;
+ }
+ PackagePermission requested = (PackagePermission) p;
+ if (bundle != null) {
+ return false;
+ }
+ // if requested permission has a filter, then it is an invalid argument
+ if (requested.filter != null) {
+ return false;
+ }
+ return implies0(requested, ACTION_NONE);
+ }
+
+ /**
+ * Internal implies method. Used by the implies and the permission
+ * collection implies methods.
+ *
+ * @param requested The requested PackagePermission which has already be
+ * validated as a proper argument. The requested PackagePermission
+ * must not have a filter expression.
+ * @param effective The effective actions with which to start.
+ * @return <code>true</code> if the specified permission is implied by this
+ * object; <code>false</code> otherwise.
+ */
+ boolean implies0(PackagePermission requested, int effective) {
+ /* check actions first - much faster */
+ effective |= action_mask;
+ final int desired = requested.action_mask;
+ if ((effective & desired) != desired) {
+ return false;
+ }
+ /* Get filter if any */
+ Filter f = filter;
+ if (f == null) {
+ return super.implies(requested);
+ }
+ return f.matchCase(requested.getProperties());
+ }
+
+ /**
+ * Returns the canonical string representation of the
+ * <code>PackagePermission</code> actions.
+ *
+ * <p>
+ * Always returns present <code>PackagePermission</code> actions in the
+ * following order: <code>EXPORTONLY</code>,<code>IMPORT</code>.
+ *
+ * @return Canonical string representation of the
+ * <code>PackagePermission</code> actions.
+ */
+ public String getActions() {
+ String result = actions;
+ if (result == null) {
+ StringBuffer sb = new StringBuffer();
+ boolean comma = false;
+
+ int mask = action_mask;
+ if ((mask & ACTION_EXPORT) == ACTION_EXPORT) {
+ sb.append(EXPORTONLY);
+ comma = true;
+ }
+
+ if ((mask & ACTION_IMPORT) == ACTION_IMPORT) {
+ if (comma)
+ sb.append(',');
+ sb.append(IMPORT);
+ }
+
+ actions = result = sb.toString();
+ }
+ return result;
+ }
+
+ /**
+ * Returns a new <code>PermissionCollection</code> object suitable for
+ * storing <code>PackagePermission</code> objects.
+ *
+ * @return A new <code>PermissionCollection</code> object.
+ */
+ public PermissionCollection newPermissionCollection() {
+ return new PackagePermissionCollection();
+ }
+
+ /**
+ * Determines the equality of two <code>PackagePermission</code> objects.
+ *
+ * This method checks that specified package has the same package name and
+ * <code>PackagePermission</code> actions as this
+ * <code>PackagePermission</code> object.
+ *
+ * @param obj The object to test for equality with this
+ * <code>PackagePermission</code> object.
+ * @return <code>true</code> if <code>obj</code> is a
+ * <code>PackagePermission</code>, and has the same package name and
+ * actions as this <code>PackagePermission</code> object;
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (!(obj instanceof PackagePermission)) {
+ return false;
+ }
+
+ PackagePermission pp = (PackagePermission) obj;
+
+ return (action_mask == pp.action_mask)
+ && getName().equals(pp.getName())
+ && ((bundle == pp.bundle) || ((bundle != null) && bundle
+ .equals(pp.bundle)));
+ }
+
+ /**
+ * Returns the hash code value for this object.
+ *
+ * @return A hash code value for this object.
+ */
+ public int hashCode() {
+ int h = 31 * 17 + getName().hashCode();
+ h = 31 * h + getActions().hashCode();
+ if (bundle != null) {
+ h = 31 * h + bundle.hashCode();
+ }
+ return h;
+ }
+
+ /**
+ * WriteObject is called to save the state of this permission object to a
+ * stream. The actions are serialized, and the superclass takes care of the
+ * name.
+ */
+ private synchronized void writeObject(java.io.ObjectOutputStream s)
+ throws IOException {
+ if (bundle != null) {
+ throw new NotSerializableException("cannot serialize");
+ }
+ // Write out the actions. The superclass takes care of the name
+ // call getActions to make sure actions field is initialized
+ if (actions == null)
+ getActions();
+ s.defaultWriteObject();
+ }
+
+ /**
+ * readObject is called to restore the state of this permission from a
+ * stream.
+ */
+ private synchronized void readObject(java.io.ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ // Read in the action, then initialize the rest
+ s.defaultReadObject();
+ setTransients(getName(), parseActions(actions));
+ }
+
+ /**
+ * Called by <code><@link PackagePermission#implies(Permission)></code>.
+ *
+ * @return a dictionary of properties for this permission.
+ */
+ private Dictionary getProperties() {
+ Dictionary result = properties;
+ if (result != null) {
+ return result;
+ }
+ final Dictionary dict = new Hashtable(5);
+ if (filter == null) {
+ dict.put("package.name", getName());
+ }
+ if (bundle != null) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ dict.put("id", new Long(bundle.getBundleId()));
+ dict.put("location", bundle.getLocation());
+ String name = bundle.getSymbolicName();
+ if (name != null) {
+ dict.put("name", name);
+ }
+ SignerProperty signer = new SignerProperty(bundle);
+ if (signer.isBundleSigned()) {
+ dict.put("signer", signer);
+ }
+ return null;
+ }
+ });
+ }
+ return properties = dict;
+ }
+}
+
+/**
+ * Stores a set of <code>PackagePermission</code> permissions.
+ *
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ */
+
+final class PackagePermissionCollection extends PermissionCollection {
+ static final long serialVersionUID = -3350758995234427603L;
+ /**
+ * Table of permissions with names.
+ *
+ * @GuardedBy this
+ */
+ private transient Map permissions;
+
+ /**
+ * Boolean saying if "*" is in the collection.
+ *
+ * @serial
+ * @GuardedBy this
+ */
+ private boolean all_allowed;
+
+ /**
+ * Table of permissions with filter expressions.
+ *
+ * @serial
+ * @GuardedBy this
+ */
+ private Map filterPermissions;
+
+ /**
+ * Create an empty PackagePermissions object.
+ */
+ public PackagePermissionCollection() {
+ permissions = new HashMap();
+ all_allowed = false;
+ }
+
+ /**
+ * Adds a permission to this permission collection.
+ *
+ * @param permission The <code>PackagePermission</code> object to add.
+ * @throws IllegalArgumentException If the specified permission is not a
+ * <code>PackagePermission</code> instance or was constructed with a
+ * Bundle object.
+ * @throws SecurityException If this
+ * <code>PackagePermissionCollection</code> object has been marked
+ * read-only.
+ */
+ public void add(final Permission permission) {
+ if (!(permission instanceof PackagePermission)) {
+ throw new IllegalArgumentException("invalid permission: "
+ + permission);
+ }
+ if (isReadOnly()) {
+ throw new SecurityException("attempt to add a Permission to a "
+ + "readonly PermissionCollection");
+ }
+
+ final PackagePermission pp = (PackagePermission) permission;
+ if (pp.bundle != null) {
+ throw new IllegalArgumentException("cannot add to collection: "
+ + pp);
+ }
+
+ final String name = pp.getName();
+ final Filter f = pp.filter;
+ synchronized (this) {
+ /* select the bucket for the permission */
+ Map pc;
+ if (f != null) {
+ pc = filterPermissions;
+ if (pc == null) {
+ filterPermissions = pc = new HashMap();
+ }
+ }
+ else {
+ pc = permissions;
+ }
+
+ final PackagePermission existing = (PackagePermission) pc.get(name);
+ if (existing != null) {
+ final int oldMask = existing.action_mask;
+ final int newMask = pp.action_mask;
+ if (oldMask != newMask) {
+ pc
+ .put(name, new PackagePermission(name, oldMask
+ | newMask));
+
+ }
+ }
+ else {
+ pc.put(name, pp);
+ }
+
+ if (!all_allowed) {
+ if (name.equals("*")) {
+ all_allowed = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Determines if the specified permissions implies the permissions expressed
+ * in <code>permission</code>.
+ *
+ * @param permission The Permission object to compare with this
+ * <code>PackagePermission</code> object.
+ * @return <code>true</code> if <code>permission</code> is a proper subset
+ * of a permission in the set; <code>false</code> otherwise.
+ */
+ public boolean implies(final Permission permission) {
+ if (!(permission instanceof PackagePermission)) {
+ return false;
+ }
+ final PackagePermission requested = (PackagePermission) permission;
+ /* if requested permission has a filter, then it is an invalid argument */
+ if (requested.filter != null) {
+ return false;
+ }
+ String requestedName = requested.getName();
+ final int desired = requested.action_mask;
+ int effective = PackagePermission.ACTION_NONE;
+
+ Collection perms;
+ synchronized (this) {
+ Map pc = permissions;
+ PackagePermission pp;
+ /* short circuit if the "*" Permission was added */
+ if (all_allowed) {
+ pp = (PackagePermission) pc.get("*");
+ if (pp != null) {
+ effective |= pp.action_mask;
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ }
+ /*
+ * strategy: Check for full match first. Then work our way up the
+ * name looking for matches on a.b.*
+ */
+ pp = (PackagePermission) pc.get(requestedName);
+ if (pp != null) {
+ /* we have a direct hit! */
+ effective |= pp.action_mask;
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ /* work our way up the tree... */
+ int last;
+ int offset = requestedName.length() - 1;
+ while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+ requestedName = requestedName.substring(0, last + 1) + "*";
+ pp = (PackagePermission) pc.get(requestedName);
+ if (pp != null) {
+ effective |= pp.action_mask;
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ offset = last - 1;
+ }
+ /*
+ * we don't have to check for "*" as it was already checked before
+ * we were called.
+ */
+ pc = filterPermissions;
+ if (pc == null) {
+ return false;
+ }
+ perms = pc.values();
+ }
+ /* iterate one by one over filteredPermissions */
+ for (Iterator iter = perms.iterator(); iter.hasNext();) {
+ if (((PackagePermission) iter.next())
+ .implies0(requested, effective)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an enumeration of all <code>PackagePermission</code> objects in
+ * the container.
+ *
+ * @return Enumeration of all <code>PackagePermission</code> objects.
+ */
+ public synchronized Enumeration elements() {
+ List all = new ArrayList(permissions.values());
+ Map pc = filterPermissions;
+ if (pc != null) {
+ all.addAll(pc.values());
+ }
+ return Collections.enumeration(all);
+ }
+
+ /* serialization logic */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("permissions", Hashtable.class),
+ new ObjectStreamField("all_allowed", Boolean.TYPE),
+ new ObjectStreamField("filterPermissions", HashMap.class) };
+
+ private synchronized void writeObject(ObjectOutputStream out)
+ throws IOException {
+ Hashtable hashtable = new Hashtable(permissions);
+ ObjectOutputStream.PutField pfields = out.putFields();
+ pfields.put("permissions", hashtable);
+ pfields.put("all_allowed", all_allowed);
+ pfields.put("filterPermissions", filterPermissions);
+ out.writeFields();
+ }
+
+ private synchronized void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ ObjectInputStream.GetField gfields = in.readFields();
+ Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+ permissions = new HashMap(hashtable);
+ all_allowed = gfields.get("all_allowed", false);
+ filterPermissions = (HashMap) gfields.get("filterPermissions", null);
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/ServiceEvent.java b/framework/src/main/java/org/osgi/framework/ServiceEvent.java
new file mode 100644
index 0000000..b7c9928
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/ServiceEvent.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.util.Dictionary;
+import java.util.EventObject;
+
+/**
+ * An event from the Framework describing a service lifecycle change.
+ * <p>
+ * <code>ServiceEvent</code> objects are delivered to
+ * <code>ServiceListener</code>s and <code>AllServiceListener</code>s when a
+ * change occurs in this service's lifecycle. A type code is used to identify
+ * the event type for future extendability.
+ *
+ * <p>
+ * OSGi Alliance reserves the right to extend the set of types.
+ *
+ * @Immutable
+ * @see ServiceListener
+ * @see AllServiceListener
+ * @version $Revision: 6542 $
+ */
+
+public class ServiceEvent extends EventObject {
+ static final long serialVersionUID = 8792901483909409299L;
+ /**
+ * Reference to the service that had a change occur in its lifecycle.
+ */
+ private final ServiceReference reference;
+
+ /**
+ * Type of service lifecycle change.
+ */
+ private final int type;
+
+ /**
+ * This service has been registered.
+ * <p>
+ * This event is synchronously delivered <strong>after</strong> the service
+ * has been registered with the Framework.
+ *
+ * @see BundleContext#registerService(String[],Object,Dictionary)
+ */
+ public final static int REGISTERED = 0x00000001;
+
+ /**
+ * The properties of a registered service have been modified.
+ * <p>
+ * This event is synchronously delivered <strong>after</strong> the service
+ * properties have been modified.
+ *
+ * @see ServiceRegistration#setProperties
+ */
+ public final static int MODIFIED = 0x00000002;
+
+ /**
+ * This service is in the process of being unregistered.
+ * <p>
+ * This event is synchronously delivered <strong>before</strong> the service
+ * has completed unregistering.
+ *
+ * <p>
+ * If a bundle is using a service that is <code>UNREGISTERING</code>, the
+ * bundle should release its use of the service when it receives this event.
+ * If the bundle does not release its use of the service when it receives
+ * this event, the Framework will automatically release the bundle's use of
+ * the service while completing the service unregistration operation.
+ *
+ * @see ServiceRegistration#unregister
+ * @see BundleContext#ungetService
+ */
+ public final static int UNREGISTERING = 0x00000004;
+
+ /**
+ * The properties of a registered service have been modified and the new
+ * properties no longer match the listener's filter.
+ * <p>
+ * This event is synchronously delivered <strong>after</strong> the service
+ * properties have been modified. This event is only delivered to listeners
+ * which were added with a non-<code>null</code> filter where the filter
+ * matched the service properties prior to the modification but the filter
+ * does not match the modified service properties.
+ *
+ * @see ServiceRegistration#setProperties
+ * @since 1.5
+ */
+ public final static int MODIFIED_ENDMATCH = 0x00000008;
+
+ /**
+ * Creates a new service event object.
+ *
+ * @param type The event type.
+ * @param reference A <code>ServiceReference</code> object to the service
+ * that had a lifecycle change.
+ */
+ public ServiceEvent(int type, ServiceReference reference) {
+ super(reference);
+ this.reference = reference;
+ this.type = type;
+ }
+
+ /**
+ * Returns a reference to the service that had a change occur in its
+ * lifecycle.
+ * <p>
+ * This reference is the source of the event.
+ *
+ * @return Reference to the service that had a lifecycle change.
+ */
+ public ServiceReference getServiceReference() {
+ return reference;
+ }
+
+ /**
+ * Returns the type of event. The event type values are:
+ * <ul>
+ * <li>{@link #REGISTERED} </li>
+ * <li>{@link #MODIFIED} </li>
+ * <li>{@link #MODIFIED_ENDMATCH} </li>
+ * <li>{@link #UNREGISTERING} </li>
+ * </ul>
+ *
+ * @return Type of service lifecycle change.
+ */
+
+ public int getType() {
+ return type;
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/ServiceException.java b/framework/src/main/java/org/osgi/framework/ServiceException.java
new file mode 100644
index 0000000..4cf04a0
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/ServiceException.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) OSGi Alliance (2007, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * A service exception used to indicate that a service problem occurred.
+ *
+ * <p>
+ * A <code>ServiceException</code> object is created by the Framework or
+ * service implementation to denote an exception condition in the service. A
+ * type code is used to identify the exception type for future extendability.
+ * Service implementations may also create subclasses of
+ * <code>ServiceException</code>. When subclassing, the subclass should set
+ * the type to {@link #SUBCLASSED} to indicate that
+ * <code>ServiceException</code> has been subclassed.
+ *
+ * <p>
+ * This exception conforms to the general purpose exception chaining mechanism.
+ *
+ * @version $Revision: 6518 $
+ * @since 1.5
+ */
+
+public class ServiceException extends RuntimeException {
+ static final long serialVersionUID = 3038963223712959631L;
+
+ /**
+ * Type of service exception.
+ */
+ private final int type;
+
+ /**
+ * No exception type is unspecified.
+ */
+ public static final int UNSPECIFIED = 0;
+ /**
+ * The service has been unregistered.
+ */
+ public static final int UNREGISTERED = 1;
+ /**
+ * The service factory produced an invalid service object.
+ */
+ public static final int FACTORY_ERROR = 2;
+ /**
+ * The service factory threw an exception.
+ */
+ public static final int FACTORY_EXCEPTION = 3;
+ /**
+ * The exception is a subclass of ServiceException. The subclass should be
+ * examined for the type of the exception.
+ */
+ public static final int SUBCLASSED = 4;
+ /**
+ * An error occurred invoking a remote service.
+ */
+ public static final int REMOTE = 5;
+
+ /**
+ * Creates a <code>ServiceException</code> with the specified message and
+ * exception cause.
+ *
+ * @param msg The associated message.
+ * @param cause The cause of this exception.
+ */
+ public ServiceException(String msg, Throwable cause) {
+ this(msg, UNSPECIFIED, cause);
+ }
+
+ /**
+ * Creates a <code>ServiceException</code> with the specified message.
+ *
+ * @param msg The message.
+ */
+ public ServiceException(String msg) {
+ this(msg, UNSPECIFIED);
+ }
+
+ /**
+ * Creates a <code>ServiceException</code> with the specified message,
+ * type and exception cause.
+ *
+ * @param msg The associated message.
+ * @param type The type for this exception.
+ * @param cause The cause of this exception.
+ */
+ public ServiceException(String msg, int type, Throwable cause) {
+ super(msg, cause);
+ this.type = type;
+ }
+
+ /**
+ * Creates a <code>ServiceException</code> with the specified message and
+ * type.
+ *
+ * @param msg The message.
+ * @param type The type for this exception.
+ */
+ public ServiceException(String msg, int type) {
+ super(msg);
+ this.type = type;
+ }
+
+ /**
+ * Returns the type for this exception or <code>UNSPECIFIED</code> if the
+ * type was unspecified or unknown.
+ *
+ * @return The type of this exception.
+ */
+ public int getType() {
+ return type;
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/ServiceFactory.java b/framework/src/main/java/org/osgi/framework/ServiceFactory.java
new file mode 100644
index 0000000..c8f6bf3
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/ServiceFactory.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * Allows services to provide customized service objects in the OSGi
+ * environment.
+ *
+ * <p>
+ * When registering a service, a <code>ServiceFactory</code> object can be
+ * used instead of a service object, so that the bundle developer can gain
+ * control of the specific service object granted to a bundle that is using the
+ * service.
+ *
+ * <p>
+ * When this happens, the
+ * <code>BundleContext.getService(ServiceReference)</code> method calls the
+ * <code>ServiceFactory.getService</code> method to create a service object
+ * specifically for the requesting bundle. The service object returned by the
+ * <code>ServiceFactory</code> is cached by the Framework until the bundle
+ * releases its use of the service.
+ *
+ * <p>
+ * When the bundle's use count for the service equals zero (including the bundle
+ * stopping or the service being unregistered), the
+ * <code>ServiceFactory.ungetService</code> method is called.
+ *
+ * <p>
+ * <code>ServiceFactory</code> objects are only used by the Framework and are
+ * not made available to other bundles in the OSGi environment. The Framework
+ * may concurrently call a <code>ServiceFactory</code>.
+ *
+ * @see BundleContext#getService
+ * @ThreadSafe
+ * @version $Revision: 5967 $
+ */
+
+public interface ServiceFactory {
+ /**
+ * Creates a new service object.
+ *
+ * <p>
+ * The Framework invokes this method the first time the specified
+ * <code>bundle</code> requests a service object using the
+ * <code>BundleContext.getService(ServiceReference)</code> method. The
+ * service factory can then return a specific service object for each
+ * bundle.
+ *
+ * <p>
+ * The Framework caches the value returned (unless it is <code>null</code>),
+ * and will return the same service object on any future call to
+ * <code>BundleContext.getService</code> for the same bundle. This means the
+ * Framework must not allow this method to be concurrently called for the
+ * same bundle.
+ *
+ * <p>
+ * The Framework will check if the returned service object is an instance of
+ * all the classes named when the service was registered. If not, then
+ * <code>null</code> is returned to the bundle.
+ *
+ * @param bundle The bundle using the service.
+ * @param registration The <code>ServiceRegistration</code> object for the
+ * service.
+ * @return A service object that <strong>must</strong> be an instance of all
+ * the classes named when the service was registered.
+ * @see BundleContext#getService
+ */
+ public Object getService(Bundle bundle, ServiceRegistration registration);
+
+ /**
+ * Releases a service object.
+ *
+ * <p>
+ * The Framework invokes this method when a service has been released by a
+ * bundle. The service object may then be destroyed.
+ *
+ * @param bundle The bundle releasing the service.
+ * @param registration The <code>ServiceRegistration</code> object for the
+ * service.
+ * @param service The service object returned by a previous call to the
+ * <code>ServiceFactory.getService</code> method.
+ * @see BundleContext#ungetService
+ */
+ public void ungetService(Bundle bundle, ServiceRegistration registration,
+ Object service);
+}
diff --git a/framework/src/main/java/org/osgi/framework/ServiceListener.java b/framework/src/main/java/org/osgi/framework/ServiceListener.java
new file mode 100644
index 0000000..ec08560
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/ServiceListener.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.util.EventListener;
+
+/**
+ * A <code>ServiceEvent</code> listener. <code>ServiceListener</code> is a
+ * listener interface that may be implemented by a bundle developer. When a
+ * <code>ServiceEvent</code> is fired, it is synchronously delivered to a
+ * <code>ServiceListener</code>. The Framework may deliver
+ * <code>ServiceEvent</code> objects to a <code>ServiceListener</code> out
+ * of order and may concurrently call and/or reenter a
+ * <code>ServiceListener</code>.
+ *
+ * <p>
+ * A <code>ServiceListener</code> object is registered with the Framework
+ * using the <code>BundleContext.addServiceListener</code> method.
+ * <code>ServiceListener</code> objects are called with a
+ * <code>ServiceEvent</code> object when a service is registered, modified, or
+ * is in the process of unregistering.
+ *
+ * <p>
+ * <code>ServiceEvent</code> object delivery to <code>ServiceListener</code>
+ * objects is filtered by the filter specified when the listener was registered.
+ * If the Java Runtime Environment supports permissions, then additional
+ * filtering is done. <code>ServiceEvent</code> objects are only delivered to
+ * the listener if the bundle which defines the listener object's class has the
+ * appropriate <code>ServicePermission</code> to get the service using at
+ * least one of the named classes under which the service was registered.
+ *
+ * <p>
+ * <code>ServiceEvent</code> object delivery to <code>ServiceListener</code>
+ * objects is further filtered according to package sources as defined in
+ * {@link ServiceReference#isAssignableTo(Bundle, String)}.
+ *
+ * @see ServiceEvent
+ * @see ServicePermission
+ * @ThreadSafe
+ * @version $Revision: 5673 $
+ */
+
+public interface ServiceListener extends EventListener {
+ /**
+ * Receives notification that a service has had a lifecycle change.
+ *
+ * @param event The <code>ServiceEvent</code> object.
+ */
+ public void serviceChanged(ServiceEvent event);
+}
diff --git a/framework/src/main/java/org/osgi/framework/ServicePermission.java b/framework/src/main/java/org/osgi/framework/ServicePermission.java
new file mode 100644
index 0000000..d2f3c31
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/ServicePermission.java
@@ -0,0 +1,932 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.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.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A bundle's authority to register or get a service.
+ * <ul>
+ * <li>The <code>register</code> action allows a bundle to register a service on
+ * the specified names.
+ * <li>The <code>get</code> action allows a bundle to detect a service and get
+ * it.
+ * </ul>
+ * Permission to get a service is required in order to detect events regarding
+ * the service. Untrusted bundles should not be able to detect the presence of
+ * certain services unless they have the appropriate
+ * <code>ServicePermission</code> to get the specific service.
+ *
+ * @ThreadSafe
+ * @version $Revision: 7189 $
+ */
+
+public final class ServicePermission extends BasicPermission {
+ static final long serialVersionUID = -7662148639076511574L;
+ /**
+ * The action string <code>get</code>.
+ */
+ public final static String GET = "get";
+ /**
+ * The action string <code>register</code>.
+ */
+ public final static String REGISTER = "register";
+
+ private final static int ACTION_GET = 0x00000001;
+ private final static int ACTION_REGISTER = 0x00000002;
+ private final static int ACTION_ALL = ACTION_GET
+ | ACTION_REGISTER;
+ final static int ACTION_NONE = 0;
+
+ /**
+ * The actions mask.
+ */
+ transient int action_mask;
+
+ /**
+ * The actions in canonical form.
+ *
+ * @serial
+ */
+ private volatile String actions = null;
+
+ /**
+ * The service used by this ServicePermission. Must be null if not
+ * constructed with a service.
+ */
+ transient final ServiceReference service;
+
+ /**
+ * The object classes for this ServicePermission. Must be null if not
+ * constructed with a service.
+ */
+ transient final String[] objectClass;
+
+ /**
+ * If this ServicePermission was constructed with a filter, this holds a
+ * Filter matching object used to evaluate the filter in implies.
+ */
+ transient Filter filter;
+
+ /**
+ * This dictionary holds the properties of the permission, used to match a
+ * filter in implies. This is not initialized until necessary, and then
+ * cached in this object.
+ */
+ private transient volatile Dictionary properties;
+
+ /**
+ * True if constructed with a name and the name is "*" or ends with ".*".
+ */
+ private transient boolean wildcard;
+
+ /**
+ * If constructed with a name and the name ends with ".*", this contains the
+ * name without the final "*".
+ */
+ private transient String prefix;
+
+ /**
+ * Create a new ServicePermission.
+ *
+ * <p>
+ * The name of the service is specified as a fully qualified class name.
+ * Wildcards may be used.
+ *
+ * <pre>
+ * name ::= <class name> | <class name ending in ".*"> | *
+ * </pre>
+ *
+ * Examples:
+ *
+ * <pre>
+ * org.osgi.service.http.HttpService
+ * org.osgi.service.http.*
+ * *
+ * </pre>
+ *
+ * For the <code>get</code> action, the name can also be a filter
+ * expression. The filter gives access to the service properties as well as
+ * the following attributes:
+ * <ul>
+ * <li>signer - A Distinguished Name chain used to sign the bundle
+ * publishing the service. Wildcards in a DN are not matched according to
+ * the filter string rules, but according to the rules defined for a DN
+ * chain.</li>
+ * <li>location - The location of the bundle publishing the service.</li>
+ * <li>id - The bundle ID of the bundle publishing the service.</li>
+ * <li>name - The symbolic name of the bundle publishing the service.</li>
+ * </ul>
+ * Since the above attribute names may conflict with service property names
+ * used by a service, you can prefix an attribute name with '@' in the
+ * filter expression to match against the service property and not one of
+ * the above attributes. Filter attribute names are processed in a case
+ * sensitive manner unless the attribute references a service property.
+ * Service properties names are case insensitive.
+ *
+ * <p>
+ * There are two possible actions: <code>get</code> and
+ * <code>register</code>. The <code>get</code> permission allows the owner
+ * of this permission to obtain a service with this name. The
+ * <code>register</code> permission allows the bundle to register a service
+ * under that name.
+ *
+ * @param name The service class name
+ * @param actions <code>get</code>,<code>register</code> (canonical order)
+ * @throws IllegalArgumentException If the specified name is a filter
+ * expression and either the specified action is not
+ * <code>get</code> or the filter has an invalid syntax.
+ */
+ public ServicePermission(String name, String actions) {
+ this(name, parseActions(actions));
+ if ((filter != null)
+ && ((action_mask & ACTION_ALL) != ACTION_GET)) {
+ throw new IllegalArgumentException(
+ "invalid action string for filter expression");
+ }
+ }
+
+ /**
+ * Creates a new requested <code>ServicePermission</code> object to be used
+ * by code that must perform <code>checkPermission</code> for the
+ * <code>get</code> action. <code>ServicePermission</code> objects created
+ * with this constructor cannot be added to a <code>ServicePermission</code>
+ * permission collection.
+ *
+ * @param reference The requested service.
+ * @param actions The action <code>get</code>.
+ * @throws IllegalArgumentException If the specified action is not
+ * <code>get</code> or reference is <code>null</code>.
+ * @since 1.5
+ */
+ public ServicePermission(ServiceReference reference, String actions) {
+ super(createName(reference));
+ setTransients(null, parseActions(actions));
+ this.service = reference;
+ this.objectClass = (String[]) reference
+ .getProperty(Constants.OBJECTCLASS);
+ if ((action_mask & ACTION_ALL) != ACTION_GET) {
+ throw new IllegalArgumentException("invalid action string");
+ }
+ }
+
+ /**
+ * Create a permission name from a ServiceReference
+ *
+ * @param reference ServiceReference to use to create permission name.
+ * @return permission name.
+ */
+ private static String createName(ServiceReference reference) {
+ if (reference == null) {
+ throw new IllegalArgumentException("reference must not be null");
+ }
+ StringBuffer sb = new StringBuffer("(service.id=");
+ sb.append(reference.getProperty(Constants.SERVICE_ID));
+ sb.append(")");
+ return sb.toString();
+ }
+
+ /**
+ * Package private constructor used by ServicePermissionCollection.
+ *
+ * @param name class name
+ * @param mask action mask
+ */
+ ServicePermission(String name, int mask) {
+ super(name);
+ setTransients(parseFilter(name), mask);
+ this.service = null;
+ this.objectClass = null;
+ }
+
+ /**
+ * Called by constructors and when deserialized.
+ *
+ * @param mask action mask
+ */
+ private void setTransients(Filter f, int mask) {
+ if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
+ throw new IllegalArgumentException("invalid action string");
+ }
+ action_mask = mask;
+ filter = f;
+ if (f == null) {
+ String name = getName();
+ int l = name.length();
+ /* if "*" or endsWith ".*" */
+ wildcard = ((name.charAt(l - 1) == '*') && ((l == 1) || (name
+ .charAt(l - 2) == '.')));
+ if (wildcard && (l > 1)) {
+ prefix = name.substring(0, l - 1);
+ }
+ }
+ }
+
+ /**
+ * 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 >= 2 && (a[i - 2] == 'g' || a[i - 2] == 'G')
+ && (a[i - 1] == 'e' || a[i - 1] == 'E')
+ && (a[i] == 't' || a[i] == 'T')) {
+ matchlen = 3;
+ mask |= ACTION_GET;
+
+ }
+ else
+ if (i >= 7 && (a[i - 7] == 'r' || a[i - 7] == 'R')
+ && (a[i - 6] == 'e' || a[i - 6] == 'E')
+ && (a[i - 5] == 'g' || a[i - 5] == 'G')
+ && (a[i - 4] == 'i' || a[i - 4] == 'I')
+ && (a[i - 3] == 's' || a[i - 3] == 'S')
+ && (a[i - 2] == 't' || a[i - 2] == 'T')
+ && (a[i - 1] == 'e' || a[i - 1] == 'E')
+ && (a[i] == 'r' || a[i] == 'R')) {
+ matchlen = 8;
+ mask |= ACTION_REGISTER;
+
+ }
+ else {
+ // parse error
+ throw new IllegalArgumentException("invalid permission: "
+ + actions);
+ }
+
+ // make sure we didn't just match the tail of a word
+ // like "ackbarfregister". Also, skip to the comma.
+ seencomma = false;
+ while (i >= matchlen && !seencomma) {
+ switch (a[i - matchlen]) {
+ case ',' :
+ seencomma = true;
+ /* FALLTHROUGH */
+ case ' ' :
+ case '\r' :
+ case '\n' :
+ case '\f' :
+ case '\t' :
+ break;
+ default :
+ throw new IllegalArgumentException(
+ "invalid permission: " + actions);
+ }
+ i--;
+ }
+
+ // point i at the location of the comma minus one (or -1).
+ i -= matchlen;
+ }
+
+ if (seencomma) {
+ throw new IllegalArgumentException("invalid permission: " + actions);
+ }
+
+ return mask;
+ }
+
+ /**
+ * Parse filter string into a Filter object.
+ *
+ * @param filterString The filter string to parse.
+ * @return a Filter for this bundle. If the specified filterString is not a
+ * filter expression, then <code>null</code> is returned.
+ * @throws IllegalArgumentException If the filter syntax is invalid.
+ */
+ private static Filter parseFilter(String filterString) {
+ filterString = filterString.trim();
+ if (filterString.charAt(0) != '(') {
+ return null;
+ }
+
+ try {
+ return FrameworkUtil.createFilter(filterString);
+ }
+ catch (InvalidSyntaxException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "invalid filter");
+ iae.initCause(e);
+ throw iae;
+ }
+ }
+
+ /**
+ * Determines if a <code>ServicePermission</code> object "implies" the
+ * specified permission.
+ *
+ * @param p The target permission to check.
+ * @return <code>true</code> if the specified permission is implied by this
+ * object; <code>false</code> otherwise.
+ */
+ public boolean implies(Permission p) {
+ if (!(p instanceof ServicePermission)) {
+ return false;
+ }
+ ServicePermission requested = (ServicePermission) p;
+ if (service != null) {
+ return false;
+ }
+ // if requested permission has a filter, then it is an invalid argument
+ if (requested.filter != null) {
+ return false;
+ }
+ return implies0(requested, ACTION_NONE);
+ }
+
+ /**
+ * Internal implies method. Used by the implies and the permission
+ * collection implies methods.
+ *
+ * @param requested The requested ServicePermission which has already be
+ * validated as a proper argument. The requested ServicePermission
+ * must not have a filter expression.
+ * @param effective The effective actions with which to start.
+ * @return <code>true</code> if the specified permission is implied by this
+ * object; <code>false</code> otherwise.
+ */
+ boolean implies0(ServicePermission requested, int effective) {
+ /* check actions first - much faster */
+ effective |= action_mask;
+ final int desired = requested.action_mask;
+ if ((effective & desired) != desired) {
+ return false;
+ }
+ /* we have name of "*" */
+ if (wildcard && (prefix == null)) {
+ return true;
+ }
+ /* if we have a filter */
+ Filter f = filter;
+ if (f != null) {
+ return f.matchCase(requested.getProperties());
+ }
+ /* if requested permission not created with ServiceReference */
+ String[] requestedNames = requested.objectClass;
+ if (requestedNames == null) {
+ return super.implies(requested);
+ }
+ /* requested permission created with ServiceReference */
+ if (wildcard) {
+ int pl = prefix.length();
+ for (int i = 0, l = requestedNames.length; i < l; i++) {
+ String requestedName = requestedNames[i];
+ if ((requestedName.length() > pl)
+ && requestedName.startsWith(prefix)) {
+ return true;
+ }
+ }
+ }
+ else {
+ String name = getName();
+ for (int i = 0, l = requestedNames.length; i < l; i++) {
+ if (requestedNames[i].equals(name)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the canonical string representation of the actions. Always
+ * returns present actions in the following order: <code>get</code>,
+ * <code>register</code>.
+ *
+ * @return The canonical string representation of the actions.
+ */
+ public String getActions() {
+ String result = actions;
+ if (result == null) {
+ StringBuffer sb = new StringBuffer();
+ boolean comma = false;
+
+ int mask = action_mask;
+ if ((mask & ACTION_GET) == ACTION_GET) {
+ sb.append(GET);
+ comma = true;
+ }
+
+ if ((mask & ACTION_REGISTER) == ACTION_REGISTER) {
+ if (comma)
+ sb.append(',');
+ sb.append(REGISTER);
+ }
+
+ actions = result = sb.toString();
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a new <code>PermissionCollection</code> object for storing
+ * <code>ServicePermission<code> objects.
+ *
+ * @return A new <code>PermissionCollection</code> object suitable for storing
+ * <code>ServicePermission</code> objects.
+ */
+ public PermissionCollection newPermissionCollection() {
+ return new ServicePermissionCollection();
+ }
+
+ /**
+ * Determines the equality of two ServicePermission objects.
+ *
+ * Checks that specified object has the same class name and action as this
+ * <code>ServicePermission</code>.
+ *
+ * @param obj The object to test for equality.
+ * @return true if obj is a <code>ServicePermission</code>, and has the same
+ * class name and actions as this <code>ServicePermission</code>
+ * object; <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (!(obj instanceof ServicePermission)) {
+ return false;
+ }
+
+ ServicePermission sp = (ServicePermission) obj;
+
+ return (action_mask == sp.action_mask)
+ && getName().equals(sp.getName())
+ && ((service == sp.service) || ((service != null) && (service
+ .compareTo(sp.service) == 0)));
+ }
+
+ /**
+ * 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 (service != null) {
+ h = 31 * h + service.hashCode();
+ }
+ return h;
+ }
+
+ /**
+ * WriteObject is called to save the state of this permission to a stream.
+ * The actions are serialized, and the superclass takes care of the name.
+ */
+ private synchronized void writeObject(java.io.ObjectOutputStream s)
+ throws IOException {
+ if (service != null) {
+ throw new NotSerializableException("cannot serialize");
+ }
+ // Write out the actions. The superclass takes care of the name
+ // call getActions to make sure actions field is initialized
+ if (actions == null)
+ 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 action, then initialize the rest
+ s.defaultReadObject();
+ setTransients(parseFilter(getName()), parseActions(actions));
+ }
+ /**
+ * Called by <code><@link ServicePermission#implies(Permission)></code>.
+ *
+ * @return a dictionary of properties for this permission.
+ */
+ private Dictionary getProperties() {
+ Dictionary result = properties;
+ if (result != null) {
+ return result;
+ }
+ if (service == null) {
+ result = new Hashtable(1);
+ if (filter == null) {
+ result.put(Constants.OBJECTCLASS, new String[] {getName()});
+ }
+ return properties = result;
+ }
+ final Map props = new HashMap(4);
+ final Bundle bundle = service.getBundle();
+ if (bundle != null) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ props.put("id", new Long(bundle.getBundleId()));
+ props.put("location", bundle.getLocation());
+ String name = bundle.getSymbolicName();
+ if (name != null) {
+ props.put("name", name);
+ }
+ SignerProperty signer = new SignerProperty(bundle);
+ if (signer.isBundleSigned()) {
+ props.put("signer", signer);
+ }
+ return null;
+ }
+ });
+ }
+ return properties = new Properties(props, service);
+ }
+
+ private static class Properties extends Dictionary {
+ private final Map properties;
+ private final ServiceReference service;
+
+ Properties(Map properties, ServiceReference service) {
+ this.properties = properties;
+ this.service = service;
+ }
+
+ public Object get(Object k) {
+ if (!(k instanceof String)) {
+ return null;
+ }
+ String key = (String) k;
+ if (key.charAt(0) == '@') {
+ return service.getProperty(key.substring(1));
+ }
+ Object value = properties.get(key);
+ if (value != null) { // fall back to service properties
+ return value;
+ }
+ return service.getProperty(key);
+ }
+
+ public int size() {
+ return properties.size() + service.getPropertyKeys().length;
+ }
+
+ public boolean isEmpty() {
+ // we can return false because this must never be empty
+ return false;
+ }
+
+ public Enumeration keys() {
+ Collection pk = properties.keySet();
+ String spk[] = service.getPropertyKeys();
+ List all = new ArrayList(pk.size() + spk.length);
+ all.addAll(pk);
+ add:
+ for (int i = 0, length = spk.length; i < length; i++) {
+ String key = spk[i];
+ for (Iterator iter = pk.iterator(); iter.hasNext();) {
+ if (key.equalsIgnoreCase((String) iter.next())) {
+ continue add;
+ }
+ }
+ all.add(key);
+ }
+ return Collections.enumeration(all);
+ }
+
+ public Enumeration elements() {
+ Collection pk = properties.keySet();
+ String spk[] = service.getPropertyKeys();
+ List all = new ArrayList(pk.size() + spk.length);
+ all.addAll(properties.values());
+ add:
+ for (int i = 0, length = spk.length; i < length; i++) {
+ String key = spk[i];
+ for (Iterator iter = pk.iterator(); iter.hasNext();) {
+ if (key.equalsIgnoreCase((String) iter.next())) {
+ continue add;
+ }
+ }
+ all.add(service.getProperty(key));
+ }
+ return Collections.enumeration(all);
+ }
+
+ public Object put(Object key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
+
+/**
+ * Stores a set of ServicePermission permissions.
+ *
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ */
+final class ServicePermissionCollection extends PermissionCollection {
+ static final long serialVersionUID = 662615640374640621L;
+ /**
+ * Table of permissions.
+ *
+ * @GuardedBy this
+ */
+ private transient Map permissions;
+
+ /**
+ * Boolean saying if "*" is in the collection.
+ *
+ * @serial
+ * @GuardedBy this
+ */
+ private boolean all_allowed;
+
+ /**
+ * Table of permissions with filter expressions.
+ *
+ * @serial
+ * @GuardedBy this
+ */
+ private Map filterPermissions;
+
+ /**
+ * Creates an empty ServicePermissions object.
+ */
+ public ServicePermissionCollection() {
+ permissions = new HashMap();
+ all_allowed = false;
+ }
+
+ /**
+ * Adds a permission to this permission collection.
+ *
+ * @param permission The Permission object to add.
+ * @throws IllegalArgumentException If the specified permission is not a
+ * ServicePermission object.
+ * @throws SecurityException If this
+ * <code>ServicePermissionCollection</code> object has been marked
+ * read-only.
+ */
+ public void add(final Permission permission) {
+ if (!(permission instanceof ServicePermission)) {
+ throw new IllegalArgumentException("invalid permission: "
+ + permission);
+ }
+ if (isReadOnly()) {
+ throw new SecurityException("attempt to add a Permission to a "
+ + "readonly PermissionCollection");
+ }
+
+ final ServicePermission sp = (ServicePermission) permission;
+ if (sp.service != null) {
+ throw new IllegalArgumentException("cannot add to collection: "
+ + sp);
+ }
+
+ final String name = sp.getName();
+ final Filter f = sp.filter;
+ synchronized (this) {
+ /* select the bucket for the permission */
+ Map pc;
+ if (f != null) {
+ pc = filterPermissions;
+ if (pc == null) {
+ filterPermissions = pc = new HashMap();
+ }
+ }
+ else {
+ pc = permissions;
+ }
+ final ServicePermission existing = (ServicePermission) pc.get(name);
+
+ if (existing != null) {
+ final int oldMask = existing.action_mask;
+ final int newMask = sp.action_mask;
+ if (oldMask != newMask) {
+ pc
+ .put(name, new ServicePermission(name, oldMask
+ | newMask));
+ }
+ }
+ else {
+ pc.put(name, sp);
+ }
+
+ if (!all_allowed) {
+ if (name.equals("*")) {
+ all_allowed = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Determines if a set of permissions implies the permissions expressed in
+ * <code>permission</code>.
+ *
+ * @param permission The Permission object to compare.
+ * @return <code>true</code> if <code>permission</code> is a proper
+ * subset of a permission in the set; <code>false</code>
+ * otherwise.
+ */
+ public boolean implies(final Permission permission) {
+ if (!(permission instanceof ServicePermission)) {
+ return false;
+ }
+ final ServicePermission requested = (ServicePermission) permission;
+ /* if requested permission has a filter, then it is an invalid argument */
+ if (requested.filter != null) {
+ return false;
+ }
+
+ int effective = ServicePermission.ACTION_NONE;
+ Collection perms;
+ synchronized (this) {
+ final int desired = requested.action_mask;
+ /* short circuit if the "*" Permission was added */
+ if (all_allowed) {
+ ServicePermission sp = (ServicePermission) permissions.get("*");
+ if (sp != null) {
+ effective |= sp.action_mask;
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ }
+
+ String[] requestedNames = requested.objectClass;
+ /* if requested permission not created with ServiceReference */
+ if (requestedNames == null) {
+ effective |= effective(requested.getName(), desired, effective);
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ /* requested permission created with ServiceReference */
+ else {
+ for (int i = 0, l = requestedNames.length; i < l; i++) {
+ if ((effective(requestedNames[i], desired, effective) & desired) == desired) {
+ return true;
+ }
+ }
+ }
+ Map pc = filterPermissions;
+ if (pc == null) {
+ return false;
+ }
+ perms = pc.values();
+ }
+
+ /* iterate one by one over filteredPermissions */
+ for (Iterator iter = perms.iterator(); iter.hasNext();) {
+ if (((ServicePermission) iter.next())
+ .implies0(requested, effective)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Consult permissions map to compute the effective permission for the
+ * requested permission name.
+ *
+ * @param requestedName The requested service name.
+ * @param desired The desired actions.
+ * @param effective The effective actions.
+ * @return The new effective actions.
+ */
+ private int effective(String requestedName, final int desired,
+ int effective) {
+ final Map pc = permissions;
+ ServicePermission sp = (ServicePermission) pc.get(requestedName);
+ // strategy:
+ // Check for full match first. Then work our way up the
+ // name looking for matches on a.b.*
+ if (sp != null) {
+ // we have a direct hit!
+ effective |= sp.action_mask;
+ if ((effective & desired) == desired) {
+ return effective;
+ }
+ }
+ // work our way up the tree...
+ int last;
+ int offset = requestedName.length() - 1;
+ while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+ requestedName = requestedName.substring(0, last + 1) + "*";
+ sp = (ServicePermission) pc.get(requestedName);
+ if (sp != null) {
+ effective |= sp.action_mask;
+ if ((effective & desired) == desired) {
+ return effective;
+ }
+ }
+ offset = last - 1;
+ }
+ /*
+ * we don't have to check for "*" as it was already checked before we
+ * were called.
+ */
+ return effective;
+ }
+
+ /**
+ * Returns an enumeration of all the <code>ServicePermission</code>
+ * objects in the container.
+ *
+ * @return Enumeration of all the ServicePermission objects.
+ */
+ public synchronized Enumeration elements() {
+ List all = new ArrayList(permissions.values());
+ Map pc = filterPermissions;
+ if (pc != null) {
+ all.addAll(pc.values());
+ }
+ return Collections.enumeration(all);
+ }
+
+ /* serialization logic */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("permissions", Hashtable.class),
+ new ObjectStreamField("all_allowed", Boolean.TYPE),
+ new ObjectStreamField("filterPermissions", HashMap.class) };
+
+ private synchronized void writeObject(ObjectOutputStream out)
+ throws IOException {
+ Hashtable hashtable = new Hashtable(permissions);
+ ObjectOutputStream.PutField pfields = out.putFields();
+ pfields.put("permissions", hashtable);
+ pfields.put("all_allowed", all_allowed);
+ pfields.put("filterPermissions", filterPermissions);
+ out.writeFields();
+ }
+
+ private synchronized void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ ObjectInputStream.GetField gfields = in.readFields();
+ Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+ permissions = new HashMap(hashtable);
+ all_allowed = gfields.get("all_allowed", false);
+ filterPermissions = (HashMap) gfields.get("filterPermissions", null);
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/ServiceReference.java b/framework/src/main/java/org/osgi/framework/ServiceReference.java
new file mode 100644
index 0000000..a6dd9bd
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/ServiceReference.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.util.Dictionary;
+
+/**
+ * A reference to a service.
+ *
+ * <p>
+ * The Framework returns <code>ServiceReference</code> objects from the
+ * <code>BundleContext.getServiceReference</code> and
+ * <code>BundleContext.getServiceReferences</code> methods.
+ * <p>
+ * A <code>ServiceReference</code> object may be shared between bundles and
+ * can be used to examine the properties of the service and to get the service
+ * object.
+ * <p>
+ * Every service registered in the Framework has a unique
+ * <code>ServiceRegistration</code> object and may have multiple, distinct
+ * <code>ServiceReference</code> objects referring to it.
+ * <code>ServiceReference</code> objects associated with a
+ * <code>ServiceRegistration</code> object have the same <code>hashCode</code>
+ * and are considered equal (more specifically, their <code>equals()</code>
+ * method will return <code>true</code> when compared).
+ * <p>
+ * If the same service object is registered multiple times,
+ * <code>ServiceReference</code> objects associated with different
+ * <code>ServiceRegistration</code> objects are not equal.
+ *
+ * @see BundleContext#getServiceReference
+ * @see BundleContext#getServiceReferences
+ * @see BundleContext#getService
+ * @ThreadSafe
+ * @version $Revision: 6374 $
+ */
+
+public interface ServiceReference extends Comparable {
+ /**
+ * Returns the property value to which the specified property key is mapped
+ * in the properties <code>Dictionary</code> object of the service
+ * referenced by this <code>ServiceReference</code> object.
+ *
+ * <p>
+ * Property keys are case-insensitive.
+ *
+ * <p>
+ * This method must continue to return property values after the service has
+ * been unregistered. This is so references to unregistered services (for
+ * example, <code>ServiceReference</code> objects stored in the log) can
+ * still be interrogated.
+ *
+ * @param key The property key.
+ * @return The property value to which the key is mapped; <code>null</code>
+ * if there is no property named after the key.
+ */
+ public Object getProperty(String key);
+
+ /**
+ * Returns an array of the keys in the properties <code>Dictionary</code>
+ * object of the service referenced by this <code>ServiceReference</code>
+ * object.
+ *
+ * <p>
+ * This method will continue to return the keys after the service has been
+ * unregistered. This is so references to unregistered services (for
+ * example, <code>ServiceReference</code> objects stored in the log) can
+ * still be interrogated.
+ *
+ * <p>
+ * This method is <i>case-preserving </i>; this means that every key in the
+ * returned array must have the same case as the corresponding key in the
+ * properties <code>Dictionary</code> that was passed to the
+ * {@link BundleContext#registerService(String[],Object,Dictionary)} or
+ * {@link ServiceRegistration#setProperties} methods.
+ *
+ * @return An array of property keys.
+ */
+ public String[] getPropertyKeys();
+
+ /**
+ * Returns the bundle that registered the service referenced by this
+ * <code>ServiceReference</code> object.
+ *
+ * <p>
+ * This method must return <code>null</code> when the service has been
+ * unregistered. This can be used to determine if the service has been
+ * unregistered.
+ *
+ * @return The bundle that registered the service referenced by this
+ * <code>ServiceReference</code> object; <code>null</code> if that
+ * service has already been unregistered.
+ * @see BundleContext#registerService(String[],Object,Dictionary)
+ */
+ public Bundle getBundle();
+
+ /**
+ * Returns the bundles that are using the service referenced by this
+ * <code>ServiceReference</code> object. Specifically, this method returns
+ * the bundles whose usage count for that service is greater than zero.
+ *
+ * @return An array of bundles whose usage count for the service referenced
+ * by this <code>ServiceReference</code> object is greater than
+ * zero; <code>null</code> if no bundles are currently using that
+ * service.
+ *
+ * @since 1.1
+ */
+ public Bundle[] getUsingBundles();
+
+ /**
+ * Tests if the bundle that registered the service referenced by this
+ * <code>ServiceReference</code> and the specified bundle use the same
+ * source for the package of the specified class name.
+ * <p>
+ * This method performs the following checks:
+ * <ol>
+ * <li>Get the package name from the specified class name.</li>
+ * <li>For the bundle that registered the service referenced by this
+ * <code>ServiceReference</code> (registrant bundle); find the source for
+ * the package. If no source is found then return <code>true</code> if the
+ * registrant bundle is equal to the specified bundle; otherwise return
+ * <code>false</code>.</li>
+ * <li>If the package source of the registrant bundle is equal to the
+ * package source of the specified bundle then return <code>true</code>;
+ * otherwise return <code>false</code>.</li>
+ * </ol>
+ *
+ * @param bundle The <code>Bundle</code> object to check.
+ * @param className The class name to check.
+ * @return <code>true</code> if the bundle which registered the service
+ * referenced by this <code>ServiceReference</code> and the
+ * specified bundle use the same source for the package of the
+ * specified class name. Otherwise <code>false</code> is returned.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+ * not created by the same framework instance as this
+ * <code>ServiceReference</code>.
+ * @since 1.3
+ */
+ public boolean isAssignableTo(Bundle bundle, String className);
+
+ /**
+ * Compares this <code>ServiceReference</code> with the specified
+ * <code>ServiceReference</code> for order.
+ *
+ * <p>
+ * If this <code>ServiceReference</code> and the specified
+ * <code>ServiceReference</code> have the same {@link Constants#SERVICE_ID
+ * service id} they are equal. This <code>ServiceReference</code> is less
+ * than the specified <code>ServiceReference</code> if it has a lower
+ * {@link Constants#SERVICE_RANKING service ranking} and greater if it has a
+ * higher service ranking. Otherwise, if this <code>ServiceReference</code>
+ * and the specified <code>ServiceReference</code> have the same
+ * {@link Constants#SERVICE_RANKING service ranking}, this
+ * <code>ServiceReference</code> is less than the specified
+ * <code>ServiceReference</code> if it has a higher
+ * {@link Constants#SERVICE_ID service id} and greater if it has a lower
+ * service id.
+ *
+ * @param reference The <code>ServiceReference</code> to be compared.
+ * @return Returns a negative integer, zero, or a positive integer if this
+ * <code>ServiceReference</code> is less than, equal to, or greater
+ * than the specified <code>ServiceReference</code>.
+ * @throws IllegalArgumentException If the specified
+ * <code>ServiceReference</code> was not created by the same
+ * framework instance as this <code>ServiceReference</code>.
+ * @since 1.4
+ */
+ public int compareTo(Object reference);
+}
diff --git a/framework/src/main/java/org/osgi/framework/ServiceRegistration.java b/framework/src/main/java/org/osgi/framework/ServiceRegistration.java
new file mode 100644
index 0000000..9186cf7
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/ServiceRegistration.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.util.Dictionary;
+
+/**
+ * A registered service.
+ *
+ * <p>
+ * The Framework returns a <code>ServiceRegistration</code> object when a
+ * <code>BundleContext.registerService</code> method invocation is successful.
+ * The <code>ServiceRegistration</code> object is for the private use of the
+ * registering bundle and should not be shared with other bundles.
+ * <p>
+ * The <code>ServiceRegistration</code> object may be used to update the
+ * properties of the service or to unregister the service.
+ *
+ * @see BundleContext#registerService(String[],Object,Dictionary)
+ * @ThreadSafe
+ * @version $Revision: 6361 $
+ */
+
+public interface ServiceRegistration {
+ /**
+ * Returns a <code>ServiceReference</code> object for a service being
+ * registered.
+ * <p>
+ * The <code>ServiceReference</code> object may be shared with other
+ * bundles.
+ *
+ * @throws IllegalStateException If this
+ * <code>ServiceRegistration</code> object has already been
+ * unregistered.
+ * @return <code>ServiceReference</code> object.
+ */
+ public ServiceReference getReference();
+
+ /**
+ * Updates the properties associated with a service.
+ *
+ * <p>
+ * The {@link Constants#OBJECTCLASS} and {@link Constants#SERVICE_ID} keys
+ * cannot be modified by this method. These values are set by the Framework
+ * when the service is registered in the OSGi environment.
+ *
+ * <p>
+ * The following steps are required to modify service properties:
+ * <ol>
+ * <li>The service's properties are replaced with the provided properties.
+ * <li>A service event of type {@link ServiceEvent#MODIFIED} is fired.
+ * </ol>
+ *
+ * @param properties The properties for this service. See {@link Constants}
+ * for a list of standard service property keys. Changes should not
+ * be made to this object after calling this method. To update the
+ * service's properties this method should be called again.
+ *
+ * @throws IllegalStateException If this <code>ServiceRegistration</code>
+ * object has already been unregistered.
+ * @throws IllegalArgumentException If <code>properties</code> contains
+ * case variants of the same key name.
+ */
+ public void setProperties(Dictionary properties);
+
+ /**
+ * Unregisters a service. Remove a <code>ServiceRegistration</code> object
+ * from the Framework service registry. All <code>ServiceReference</code>
+ * objects associated with this <code>ServiceRegistration</code> object
+ * can no longer be used to interact with the service once unregistration is
+ * complete.
+ *
+ * <p>
+ * The following steps are required to unregister a service:
+ * <ol>
+ * <li>The service is removed from the Framework service registry so that
+ * it can no longer be obtained.
+ * <li>A service event of type {@link ServiceEvent#UNREGISTERING} is fired
+ * so that bundles using this service can release their use of the service.
+ * Once delivery of the service event is complete, the
+ * <code>ServiceReference</code> objects for the service may no longer be
+ * used to get a service object for the service.
+ * <li>For each bundle whose use count for this service is greater than
+ * zero: <br>
+ * The bundle's use count for this service is set to zero. <br>
+ * If the service was registered with a {@link ServiceFactory} object, the
+ * <code>ServiceFactory.ungetService</code> method is called to release
+ * the service object for the bundle.
+ * </ol>
+ *
+ * @throws IllegalStateException If this
+ * <code>ServiceRegistration</code> object has already been
+ * unregistered.
+ * @see BundleContext#ungetService
+ * @see ServiceFactory#ungetService
+ */
+ public void unregister();
+}
diff --git a/framework/src/main/java/org/osgi/framework/SignerProperty.java b/framework/src/main/java/org/osgi/framework/SignerProperty.java
new file mode 100644
index 0000000..2ba0389
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/SignerProperty.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Package private class used by permissions for filter matching on signer key
+ * during filter expression evaluation in the permission implies method.
+ *
+ * @Immutable
+ * @version $Revision: 6479 $
+ */
+class SignerProperty {
+ private final Bundle bundle;
+ private final String pattern;
+
+ /**
+ * String constructor used by the filter matching algorithm to construct a
+ * SignerProperty from the attribute value in a filter expression.
+ *
+ * @param pattern Attribute value in the filter expression.
+ */
+ public SignerProperty(String pattern) {
+ this.pattern = pattern;
+ this.bundle = null;
+ }
+
+ /**
+ * Used by the permission implies method to build the properties for a
+ * filter match.
+ *
+ * @param bundle The bundle whose signers are to be matched.
+ */
+ SignerProperty(Bundle bundle) {
+ this.bundle = bundle;
+ this.pattern = null;
+ }
+
+ /**
+ * Used by the filter matching algorithm. This methods does NOT satisfy the
+ * normal equals contract. Since the class is only used in filter expression
+ * evaluations, it only needs to support comparing an instance created with
+ * a Bundle to an instance created with a pattern string from the filter
+ * expression.
+ *
+ * @param o SignerProperty to compare against.
+ * @return true if the DN name chain matches the pattern.
+ */
+ public boolean equals(Object o) {
+ if (!(o instanceof SignerProperty))
+ return false;
+ SignerProperty other = (SignerProperty) o;
+ Bundle matchBundle = bundle != null ? bundle : other.bundle;
+ String matchPattern = bundle != null ? other.pattern : pattern;
+ Map/* <X509Certificate, List<X509Certificate>> */signers = matchBundle
+ .getSignerCertificates(Bundle.SIGNERS_TRUSTED);
+ for (Iterator iSigners = signers.values().iterator(); iSigners
+ .hasNext();) {
+ List/* <X509Certificate> */signerCerts = (List) iSigners.next();
+ List/* <String> */dnChain = new ArrayList(signerCerts.size());
+ for (Iterator iCerts = signerCerts.iterator(); iCerts.hasNext();) {
+ dnChain.add(((X509Certificate) iCerts.next()).getSubjectDN()
+ .getName());
+ }
+ if (FrameworkUtil
+ .matchDistinguishedNameChain(matchPattern, dnChain)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Since the equals method does not obey the general equals contract, this
+ * method cannot generate hash codes which obey the equals contract.
+ */
+ public int hashCode() {
+ return 31;
+ }
+
+ /**
+ * Check if the bundle is signed.
+ *
+ * @return true if constructed with a bundle that is signed.
+ */
+ boolean isBundleSigned() {
+ if (bundle == null) {
+ return false;
+ }
+ Map/* <X509Certificate, List<X509Certificate>> */signers = bundle
+ .getSignerCertificates(Bundle.SIGNERS_TRUSTED);
+ return !signers.isEmpty();
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/SynchronousBundleListener.java b/framework/src/main/java/org/osgi/framework/SynchronousBundleListener.java
new file mode 100644
index 0000000..9104f04
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/SynchronousBundleListener.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) OSGi Alliance (2001, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * A synchronous <code>BundleEvent</code> listener.
+ * <code>SynchronousBundleListener</code> is a listener interface that may be
+ * implemented by a bundle developer. When a <code>BundleEvent</code> is
+ * fired, it is synchronously delivered to a
+ * <code>SynchronousBundleListener</code>. The Framework may deliver
+ * <code>BundleEvent</code> objects to a
+ * <code>SynchronousBundleListener</code> out of order and may concurrently
+ * call and/or reenter a <code>SynchronousBundleListener</code>.
+ * <p>
+ * A <code>SynchronousBundleListener</code> object is registered with the
+ * Framework using the {@link BundleContext#addBundleListener} method.
+ * <code>SynchronousBundleListener</code> objects are called with a
+ * <code>BundleEvent</code> object when a bundle has been installed, resolved,
+ * starting, started, stopping, stopped, updated, unresolved, or uninstalled.
+ * <p>
+ * Unlike normal <code>BundleListener</code> objects,
+ * <code>SynchronousBundleListener</code>s are synchronously called during
+ * bundle lifecycle processing. The bundle lifecycle processing will not proceed
+ * until all <code>SynchronousBundleListener</code>s have completed.
+ * <code>SynchronousBundleListener</code> objects will be called prior to
+ * <code>BundleListener</code> objects.
+ * <p>
+ * <code>AdminPermission[bundle,LISTENER]</code> is required to add or remove
+ * a <code>SynchronousBundleListener</code> object.
+ *
+ * @since 1.1
+ * @see BundleEvent
+ * @ThreadSafe
+ * @version $Revision: 5673 $
+ */
+
+public interface SynchronousBundleListener extends BundleListener {
+ // This is a marker interface
+}
diff --git a/framework/src/main/java/org/osgi/framework/Version.java b/framework/src/main/java/org/osgi/framework/Version.java
new file mode 100644
index 0000000..7317495
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/Version.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+/**
+ * Version identifier for bundles and packages.
+ *
+ * <p>
+ * Version identifiers have four components.
+ * <ol>
+ * <li>Major version. A non-negative integer.</li>
+ * <li>Minor version. A non-negative integer.</li>
+ * <li>Micro version. A non-negative integer.</li>
+ * <li>Qualifier. A text string. See <code>Version(String)</code> for the
+ * format of the qualifier string.</li>
+ * </ol>
+ *
+ * <p>
+ * <code>Version</code> objects are immutable.
+ *
+ * @since 1.3
+ * @Immutable
+ * @version $Revision: 6860 $
+ */
+
+public class Version implements Comparable {
+ private final int major;
+ private final int minor;
+ private final int micro;
+ private final String qualifier;
+ private static final String SEPARATOR = "."; //$NON-NLS-1$
+
+ /**
+ * The empty version "0.0.0".
+ */
+ public static final Version emptyVersion = new Version(0, 0, 0);
+
+ /**
+ * Creates a version identifier from the specified numerical components.
+ *
+ * <p>
+ * The qualifier is set to the empty string.
+ *
+ * @param major Major component of the version identifier.
+ * @param minor Minor component of the version identifier.
+ * @param micro Micro component of the version identifier.
+ * @throws IllegalArgumentException If the numerical components are
+ * negative.
+ */
+ public Version(int major, int minor, int micro) {
+ this(major, minor, micro, null);
+ }
+
+ /**
+ * Creates a version identifier from the specified components.
+ *
+ * @param major Major component of the version identifier.
+ * @param minor Minor component of the version identifier.
+ * @param micro Micro component of the version identifier.
+ * @param qualifier Qualifier component of the version identifier. If
+ * <code>null</code> is specified, then the qualifier will be set to
+ * the empty string.
+ * @throws IllegalArgumentException If the numerical components are negative
+ * or the qualifier string is invalid.
+ */
+ public Version(int major, int minor, int micro, String qualifier) {
+ if (qualifier == null) {
+ qualifier = ""; //$NON-NLS-1$
+ }
+
+ this.major = major;
+ this.minor = minor;
+ this.micro = micro;
+ this.qualifier = qualifier;
+ validate();
+ }
+
+ /**
+ * Created a version identifier from the specified string.
+ *
+ * <p>
+ * Here is the grammar for version strings.
+ *
+ * <pre>
+ * version ::= major('.'minor('.'micro('.'qualifier)?)?)?
+ * major ::= digit+
+ * minor ::= digit+
+ * micro ::= digit+
+ * qualifier ::= (alpha|digit|'_'|'-')+
+ * digit ::= [0..9]
+ * alpha ::= [a..zA..Z]
+ * </pre>
+ *
+ * There must be no whitespace in version.
+ *
+ * @param version String representation of the version identifier.
+ * @throws IllegalArgumentException If <code>version</code> is improperly
+ * formatted.
+ */
+ public Version(String version) {
+ int maj = 0;
+ int min = 0;
+ int mic = 0;
+ String qual = ""; //$NON-NLS-1$
+
+ try {
+ StringTokenizer st = new StringTokenizer(version, SEPARATOR, true);
+ maj = Integer.parseInt(st.nextToken());
+
+ if (st.hasMoreTokens()) {
+ st.nextToken(); // consume delimiter
+ min = Integer.parseInt(st.nextToken());
+
+ if (st.hasMoreTokens()) {
+ st.nextToken(); // consume delimiter
+ mic = Integer.parseInt(st.nextToken());
+
+ if (st.hasMoreTokens()) {
+ st.nextToken(); // consume delimiter
+ qual = st.nextToken();
+
+ if (st.hasMoreTokens()) {
+ throw new IllegalArgumentException("invalid format"); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+ catch (NoSuchElementException e) {
+ throw new IllegalArgumentException("invalid format"); //$NON-NLS-1$
+ }
+
+ major = maj;
+ minor = min;
+ micro = mic;
+ qualifier = qual;
+ validate();
+ }
+
+ /**
+ * Called by the Version constructors to validate the version components.
+ *
+ * @throws IllegalArgumentException If the numerical components are negative
+ * or the qualifier string is invalid.
+ */
+ private void validate() {
+ if (major < 0) {
+ throw new IllegalArgumentException("negative major"); //$NON-NLS-1$
+ }
+ if (minor < 0) {
+ throw new IllegalArgumentException("negative minor"); //$NON-NLS-1$
+ }
+ if (micro < 0) {
+ throw new IllegalArgumentException("negative micro"); //$NON-NLS-1$
+ }
+ char[] chars = qualifier.toCharArray();
+ for (int i = 0, length = chars.length; i < length; i++) {
+ char ch = chars[i];
+ if (('A' <= ch) && (ch <= 'Z')) {
+ continue;
+ }
+ if (('a' <= ch) && (ch <= 'z')) {
+ continue;
+ }
+ if (('0' <= ch) && (ch <= '9')) {
+ continue;
+ }
+ if ((ch == '_') || (ch == '-')) {
+ continue;
+ }
+ throw new IllegalArgumentException(
+ "invalid qualifier: " + qualifier); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Parses a version identifier from the specified string.
+ *
+ * <p>
+ * See <code>Version(String)</code> for the format of the version string.
+ *
+ * @param version String representation of the version identifier. Leading
+ * and trailing whitespace will be ignored.
+ * @return A <code>Version</code> object representing the version
+ * identifier. If <code>version</code> is <code>null</code> or
+ * the empty string then <code>emptyVersion</code> will be
+ * returned.
+ * @throws IllegalArgumentException If <code>version</code> is improperly
+ * formatted.
+ */
+ public static Version parseVersion(String version) {
+ if (version == null) {
+ return emptyVersion;
+ }
+
+ version = version.trim();
+ if (version.length() == 0) {
+ return emptyVersion;
+ }
+
+ return new Version(version);
+ }
+
+ /**
+ * Returns the major component of this version identifier.
+ *
+ * @return The major component.
+ */
+ public int getMajor() {
+ return major;
+ }
+
+ /**
+ * Returns the minor component of this version identifier.
+ *
+ * @return The minor component.
+ */
+ public int getMinor() {
+ return minor;
+ }
+
+ /**
+ * Returns the micro component of this version identifier.
+ *
+ * @return The micro component.
+ */
+ public int getMicro() {
+ return micro;
+ }
+
+ /**
+ * Returns the qualifier component of this version identifier.
+ *
+ * @return The qualifier component.
+ */
+ public String getQualifier() {
+ return qualifier;
+ }
+
+ /**
+ * Returns the string representation of this version identifier.
+ *
+ * <p>
+ * The format of the version string will be <code>major.minor.micro</code>
+ * if qualifier is the empty string or
+ * <code>major.minor.micro.qualifier</code> otherwise.
+ *
+ * @return The string representation of this version identifier.
+ */
+ public String toString() {
+ int q = qualifier.length();
+ StringBuffer result = new StringBuffer(20 + q);
+ result.append(major);
+ result.append(SEPARATOR);
+ result.append(minor);
+ result.append(SEPARATOR);
+ result.append(micro);
+ if (q > 0) {
+ result.append(SEPARATOR);
+ result.append(qualifier);
+ }
+ return result.toString();
+ }
+
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return An integer which is a hash code value for this object.
+ */
+ public int hashCode() {
+ return (major << 24) + (minor << 16) + (micro << 8)
+ + qualifier.hashCode();
+ }
+
+ /**
+ * Compares this <code>Version</code> object to another object.
+ *
+ * <p>
+ * A version is considered to be <b>equal to </b> another version if the
+ * major, minor and micro components are equal and the qualifier component
+ * is equal (using <code>String.equals</code>).
+ *
+ * @param object The <code>Version</code> object to be compared.
+ * @return <code>true</code> if <code>object</code> is a
+ * <code>Version</code> and is equal to this object;
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object object) {
+ if (object == this) { // quicktest
+ return true;
+ }
+
+ if (!(object instanceof Version)) {
+ return false;
+ }
+
+ Version other = (Version) object;
+ return (major == other.major) && (minor == other.minor)
+ && (micro == other.micro) && qualifier.equals(other.qualifier);
+ }
+
+ /**
+ * Compares this <code>Version</code> object to another object.
+ *
+ * <p>
+ * A version is considered to be <b>less than </b> another version if its
+ * major component is less than the other version's major component, or the
+ * major components are equal and its minor component is less than the other
+ * version's minor component, or the major and minor components are equal
+ * and its micro component is less than the other version's micro component,
+ * or the major, minor and micro components are equal and it's qualifier
+ * component is less than the other version's qualifier component (using
+ * <code>String.compareTo</code>).
+ *
+ * <p>
+ * A version is considered to be <b>equal to</b> another version if the
+ * major, minor and micro components are equal and the qualifier component
+ * is equal (using <code>String.compareTo</code>).
+ *
+ * @param object The <code>Version</code> object to be compared.
+ * @return A negative integer, zero, or a positive integer if this object is
+ * less than, equal to, or greater than the specified
+ * <code>Version</code> object.
+ * @throws ClassCastException If the specified object is not a
+ * <code>Version</code>.
+ */
+ public int compareTo(Object object) {
+ if (object == this) { // quicktest
+ return 0;
+ }
+
+ Version other = (Version) object;
+
+ int result = major - other.major;
+ if (result != 0) {
+ return result;
+ }
+
+ result = minor - other.minor;
+ if (result != 0) {
+ return result;
+ }
+
+ result = micro - other.micro;
+ if (result != 0) {
+ return result;
+ }
+
+ return qualifier.compareTo(other.qualifier);
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/hooks/service/EventHook.java b/framework/src/main/java/org/osgi/framework/hooks/service/EventHook.java
new file mode 100644
index 0000000..1249493
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/hooks/service/EventHook.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework.hooks.service;
+
+import java.util.Collection;
+
+import org.osgi.framework.ServiceEvent;
+
+/**
+ * OSGi Framework Service Event Hook Service.
+ *
+ * <p>
+ * Bundles registering this service will be called during framework service
+ * (register, modify, and unregister service) operations.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6967 $
+ */
+
+public interface EventHook {
+ /**
+ * Event hook method. This method is called prior to service event delivery
+ * when a publishing bundle registers, modifies or unregisters a service.
+ * This method can filter the bundles which receive the event.
+ *
+ * @param event The service event to be delivered.
+ * @param contexts A <code>Collection</code> of Bundle Contexts for bundles
+ * which have listeners to which the specified event will be
+ * delivered. The implementation of this method may remove bundle
+ * contexts from the collection to prevent the event from being
+ * delivered to the associated bundles. The collection supports all
+ * the optional <code>Collection</code> operations except
+ * <code>add</code> and <code>addAll</code>. Attempting to add to the
+ * collection will result in an
+ * <code>UnsupportedOperationException</code>. The collection is not
+ * synchronized.
+ */
+ void event(ServiceEvent event,
+ Collection/* <BundleContext> */contexts);
+}
diff --git a/framework/src/main/java/org/osgi/framework/hooks/service/FindHook.java b/framework/src/main/java/org/osgi/framework/hooks/service/FindHook.java
new file mode 100644
index 0000000..0de1f0b
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/hooks/service/FindHook.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework.hooks.service;
+
+import java.util.Collection;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * OSGi Framework Service Find Hook Service.
+ *
+ * <p>
+ * Bundles registering this service will be called during framework service find
+ * (get service references) operations.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6967 $
+ */
+
+public interface FindHook {
+ /**
+ * Find hook method. This method is called during the service find operation
+ * (for example, {@link BundleContext#getServiceReferences(String, String)}
+ * ). This method can filter the result of the find operation.
+ *
+ * @param context The bundle context of the bundle performing the find
+ * operation.
+ * @param name The class name of the services to find or <code>null</code>
+ * to find all services.
+ * @param filter The filter criteria of the services to find or
+ * <code>null</code> for no filter criteria.
+ * @param allServices <code>true</code> if the find operation is the result
+ * of a call to
+ * {@link BundleContext#getAllServiceReferences(String, String)}
+ * @param references A <code>Collection</code> of Service References to be
+ * returned as a result of the find operation. The implementation of
+ * this method may remove service references from the collection to
+ * prevent the references from being returned to the bundle
+ * performing the find operation. The collection supports all the
+ * optional <code>Collection</code> operations except
+ * <code>add</code> and <code>addAll</code>. Attempting to add to the
+ * collection will result in an
+ * <code>UnsupportedOperationException</code>. The collection is not
+ * synchronized.
+ */
+ void find(BundleContext context, String name, String filter,
+ boolean allServices,
+ Collection/* <ServiceReference> */references);
+}
diff --git a/framework/src/main/java/org/osgi/framework/hooks/service/ListenerHook.java b/framework/src/main/java/org/osgi/framework/hooks/service/ListenerHook.java
new file mode 100644
index 0000000..5934c0c
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/hooks/service/ListenerHook.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework.hooks.service;
+
+import java.util.Collection;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * OSGi Framework Service Listener Hook Service.
+ *
+ * <p>
+ * Bundles registering this service will be called during service listener
+ * addition and removal.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6967 $
+ */
+
+public interface ListenerHook {
+ /**
+ * Added listeners hook method. This method is called to provide the hook
+ * implementation with information on newly added service listeners. This
+ * method will be called as service listeners are added while this hook is
+ * registered. Also, immediately after registration of this hook, this
+ * method will be called to provide the current collection of service
+ * listeners which had been added prior to the hook being registered.
+ *
+ * @param listeners A <code>Collection</code> of {@link ListenerInfo}s for
+ * newly added service listeners which are now listening to service
+ * events. Attempting to add to or remove from the collection will
+ * result in an <code>UnsupportedOperationException</code>. The
+ * collection is not synchronized.
+ */
+ void added(Collection/* <ListenerInfo> */listeners);
+
+ /**
+ * Removed listeners hook method. This method is called to provide the hook
+ * implementation with information on newly removed service listeners. This
+ * method will be called as service listeners are removed while this hook is
+ * registered.
+ *
+ * @param listeners A <code>Collection</code> of {@link ListenerInfo}s for
+ * newly removed service listeners which are no longer listening to
+ * service events. Attempting to add to or remove from the collection
+ * will result in an <code>UnsupportedOperationException</code>. The
+ * collection is not synchronized.
+ */
+ void removed(Collection/* <ListenerInfo> */listeners);
+
+ /**
+ * Information about a Service Listener. This interface describes the bundle
+ * which added the Service Listener and the filter with which it was added.
+ *
+ * @ThreadSafe
+ */
+ public interface ListenerInfo {
+ /**
+ * Return the context of the bundle which added the listener.
+ *
+ * @return The context of the bundle which added the listener.
+ */
+ BundleContext getBundleContext();
+
+ /**
+ * Return the filter string with which the listener was added.
+ *
+ * @return The filter string with which the listener was added. This may
+ * be <code>null</code> if the listener was added without a
+ * filter.
+ */
+ String getFilter();
+
+ /**
+ * Return the state of the listener for this addition and removal life
+ * cycle. Initially this method will return <code>false</code>
+ * indicating the listener has been added but has not been removed.
+ * After the listener has been removed, this method must always return
+ * <code>true</code>.
+ *
+ * <p>
+ * There is an extremely rare case in which removed notification to
+ * {@link ListenerHook}s can be made before added notification if two
+ * threads are racing to add and remove the same service listener.
+ * Because {@link ListenerHook}s are called synchronously during service
+ * listener addition and removal, the Framework cannot guarantee
+ * in-order delivery of added and removed notification for a given
+ * service listener. This method can be used to detect this rare
+ * occurrence.
+ *
+ * @return <code>false</code> if the listener has not been been removed,
+ * <code>true</code> otherwise.
+ */
+ boolean isRemoved();
+
+ /**
+ * Compares this <code>ListenerInfo</code> to another
+ * <code>ListenerInfo</code>. Two <code>ListenerInfo</code>s are equals
+ * if they refer to the same listener for a given addition and removal
+ * life cycle. If the same listener is added again, it must have a
+ * different <code>ListenerInfo</code> which is not equal to this
+ * <code>ListenerInfo</code>.
+ *
+ * @param obj The object to compare against this
+ * <code>ListenerInfo</code>.
+ * @return <code>true</code> if the other object is a
+ * <code>ListenerInfo</code> object and both objects refer to
+ * the same listener for a given addition and removal life
+ * cycle.
+ */
+ boolean equals(Object obj);
+
+ /**
+ * Returns the hash code for this <code>ListenerInfo</code>.
+ *
+ * @return The hash code of this <code>ListenerInfo</code>.
+ */
+ int hashCode();
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/hooks/service/package.html b/framework/src/main/java/org/osgi/framework/hooks/service/package.html
new file mode 100644
index 0000000..46d18ac
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/hooks/service/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6211 $ -->
+<BODY>
+<p>Framework Service Hooks Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework.hooks.service;version="[1.0,2.0)"
+</pre>
+</BODY>
+
diff --git a/framework/src/main/java/org/osgi/framework/hooks/service/packageinfo b/framework/src/main/java/org/osgi/framework/hooks/service/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/hooks/service/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/framework/src/main/java/org/osgi/framework/launch/Framework.java b/framework/src/main/java/org/osgi/framework/launch/Framework.java
new file mode 100644
index 0000000..f7618aa
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/launch/Framework.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework.launch;
+
+import java.io.InputStream;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+
+/**
+ * A Framework instance. A Framework is also known as a System Bundle.
+ *
+ * <p>
+ * Framework instances are created using a {@link FrameworkFactory}. The methods
+ * of this interface can be used to manage and control the created framework
+ * instance.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6542 $
+ */
+public interface Framework extends Bundle {
+
+ /**
+ * Initialize this Framework. After calling this method, this Framework
+ * must:
+ * <ul>
+ * <li>Be in the {@link #STARTING} state.</li>
+ * <li>Have a valid Bundle Context.</li>
+ * <li>Be at start level 0.</li>
+ * <li>Have event handling enabled.</li>
+ * <li>Have reified Bundle objects for all installed bundles.</li>
+ * <li>Have registered any framework services. For example,
+ * <code>PackageAdmin</code>, <code>ConditionalPermissionAdmin</code>,
+ * <code>StartLevel</code>.</li>
+ * </ul>
+ *
+ * <p>
+ * This Framework will not actually be started until {@link #start() start}
+ * is called.
+ *
+ * <p>
+ * This method does nothing if called when this Framework is in the
+ * {@link #STARTING}, {@link #ACTIVE} or {@link #STOPPING} states.
+ *
+ * @throws BundleException If this Framework could not be initialized.
+ * @throws SecurityException If the Java Runtime Environment supports
+ * permissions and the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code> or if there is a
+ * security manager already installed and the
+ * {@link Constants#FRAMEWORK_SECURITY} configuration property is
+ * set.
+ *
+ */
+ void init() throws BundleException;
+
+ /**
+ * Wait until this Framework has completely stopped. The <code>stop</code>
+ * and <code>update</code> methods on a Framework performs an asynchronous
+ * stop of the Framework. This method can be used to wait until the
+ * asynchronous stop of this Framework has completed. This method will only
+ * wait if called when this Framework is in the {@link #STARTING},
+ * {@link #ACTIVE}, or {@link #STOPPING} states. Otherwise it will return
+ * immediately.
+ * <p>
+ * A Framework Event is returned to indicate why this Framework has stopped.
+ *
+ * @param timeout Maximum number of milliseconds to wait until this
+ * Framework has completely stopped. A value of zero will wait
+ * indefinitely.
+ * @return A Framework Event indicating the reason this method returned. The
+ * following <code>FrameworkEvent</code> types may be returned by
+ * this method.
+ * <ul>
+ * <li>{@link FrameworkEvent#STOPPED STOPPED} - This Framework has
+ * been stopped. </li>
+ *
+ * <li>{@link FrameworkEvent#STOPPED_UPDATE STOPPED_UPDATE} - This
+ * Framework has been updated which has shutdown and will now
+ * restart.</li>
+ *
+ * <li> {@link FrameworkEvent#STOPPED_BOOTCLASSPATH_MODIFIED
+ * STOPPED_BOOTCLASSPATH_MODIFIED} - This Framework has been stopped
+ * and a bootclasspath extension bundle has been installed or
+ * updated. The VM must be restarted in order for the changed boot
+ * class path to take affect. </li>
+ *
+ * <li>{@link FrameworkEvent#ERROR ERROR} - The Framework
+ * encountered an error while shutting down or an error has occurred
+ * which forced the framework to shutdown. </li>
+ *
+ * <li> {@link FrameworkEvent#WAIT_TIMEDOUT WAIT_TIMEDOUT} - This
+ * method has timed out and returned before this Framework has
+ * stopped.</li>
+ * </ul>
+ * @throws InterruptedException If another thread interrupted the current
+ * thread before or while the current thread was waiting for this
+ * Framework to completely stop. The <i>interrupted status</i> of
+ * the current thread is cleared when this exception is thrown.
+ * @throws IllegalArgumentException If the value of timeout is negative.
+ */
+ FrameworkEvent waitForStop(long timeout) throws InterruptedException;
+
+ /**
+ * Start this Framework.
+ *
+ * <p>
+ * The following steps are taken to start this Framework:
+ * <ol>
+ * <li>If this Framework is not in the {@link #STARTING} state,
+ * {@link #init() initialize} this Framework.</li>
+ * <li>All installed bundles must be started in accordance with each
+ * bundle's persistent <i>autostart setting</i>. This means some bundles
+ * will not be started, some will be started with <i>eager activation</i>
+ * and some will be started with their <i>declared activation</i> policy. If
+ * this Framework implements the optional <i>Start Level Service
+ * Specification</i>, then the start level of this Framework is moved to the
+ * start level specified by the
+ * {@link Constants#FRAMEWORK_BEGINNING_STARTLEVEL beginning start level}
+ * framework property, as described in the <i>Start Level Service
+ * Specification</i>. If this framework property is not specified, then the
+ * start level of this Framework is moved to start level one (1). Any
+ * exceptions that occur during bundle starting must be wrapped in a
+ * {@link BundleException} and then published as a framework event of type
+ * {@link FrameworkEvent#ERROR}</li>
+ * <li>This Framework's state is set to {@link #ACTIVE}.</li>
+ * <li>A framework event of type {@link FrameworkEvent#STARTED} is fired</li>
+ * </ol>
+ *
+ * @throws BundleException If this Framework could not be started.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @see "Start Level Service Specification"
+ */
+ void start() throws BundleException;
+
+ /**
+ * Start this Framework.
+ *
+ * <p>
+ * Calling this method is the same as calling {@link #start()}. There are no
+ * start options for the Framework.
+ *
+ * @param options Ignored. There are no start options for the Framework.
+ * @throws BundleException If this Framework could not be started.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @see #start()
+ */
+ void start(int options) throws BundleException;
+
+ /**
+ * Stop this Framework.
+ *
+ * <p>
+ * The method returns immediately to the caller after initiating the
+ * following steps to be taken on another thread.
+ * <ol>
+ * <li>This Framework's state is set to {@link #STOPPING}.</li>
+ * <li>All installed bundles must be stopped without changing each bundle's
+ * persistent <i>autostart setting</i>. If this Framework implements the
+ * optional <i>Start Level Service Specification</i>, then the start level
+ * of this Framework is moved to start level zero (0), as described in the
+ * <i>Start Level Service Specification</i>. Any exceptions that occur
+ * during bundle stopping must be wrapped in a {@link BundleException} and
+ * then published as a framework event of type {@link FrameworkEvent#ERROR}</li>
+ * <li>Unregister all services registered by this Framework.</li>
+ * <li>Event handling is disabled.</li>
+ * <li>This Framework's state is set to {@link #RESOLVED}.</li>
+ * <li>All resources held by this Framework are released. This includes
+ * threads, bundle class loaders, open files, etc.</li>
+ * <li>Notify all threads that are waiting at {@link #waitForStop(long)
+ * waitForStop} that the stop operation has completed.</li>
+ * </ol>
+ * <p>
+ * After being stopped, this Framework may be discarded, initialized or
+ * started.
+ *
+ * @throws BundleException If stopping this Framework could not be
+ * initiated.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @see "Start Level Service Specification"
+ */
+ void stop() throws BundleException;
+
+ /**
+ * Stop this Framework.
+ *
+ * <p>
+ * Calling this method is the same as calling {@link #stop()}. There are no
+ * stop options for the Framework.
+ *
+ * @param options Ignored. There are no stop options for the Framework.
+ * @throws BundleException If stopping this Framework could not be
+ * initiated.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @see #stop()
+ */
+ void stop(int options) throws BundleException;
+
+ /**
+ * The Framework cannot be uninstalled.
+ *
+ * <p>
+ * This method always throws a BundleException.
+ *
+ * @throws BundleException This Framework cannot be uninstalled.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+ * Runtime Environment supports permissions.
+ */
+ void uninstall() throws BundleException;
+
+ /**
+ * Stop and restart this Framework.
+ *
+ * <p>
+ * The method returns immediately to the caller after initiating the
+ * following steps to be taken on another thread.
+ * <ol>
+ * <li>Perform the steps in the {@link #stop()} method to stop this
+ * Framework.</li>
+ * <li>Perform the steps in the {@link #start()} method to start this
+ * Framework.</li>
+ * </ol>
+ *
+ * @throws BundleException If stopping and restarting this Framework could
+ * not be initiated.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+ * Runtime Environment supports permissions.
+ */
+ void update() throws BundleException;
+
+ /**
+ * Stop and restart this Framework.
+ *
+ * <p>
+ * Calling this method is the same as calling {@link #update()} except that
+ * any provided InputStream is immediately closed.
+ *
+ * @param in Any provided InputStream is immediately closed before returning
+ * from this method and otherwise ignored.
+ * @throws BundleException If stopping and restarting this Framework could
+ * not be initiated.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+ * Runtime Environment supports permissions.
+ */
+ void update(InputStream in) throws BundleException;
+
+ /**
+ * Returns the Framework unique identifier. This Framework is assigned the
+ * unique identifier zero (0) since this Framework is also a System Bundle.
+ *
+ * @return 0.
+ * @see Bundle#getBundleId()
+ */
+ long getBundleId();
+
+ /**
+ * Returns the Framework location identifier. This Framework is assigned the
+ * unique location "<code>System Bundle</code>" since this
+ * Framework is also a System Bundle.
+ *
+ * @return The string "<code>System Bundle</code>".
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,METADATA]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @see Bundle#getLocation()
+ * @see Constants#SYSTEM_BUNDLE_LOCATION
+ */
+ String getLocation();
+
+ /**
+ * Returns the symbolic name of this Framework. The symbolic name is unique
+ * for the implementation of the framework. However, the symbolic name
+ * "<code>system.bundle</code>" must be recognized as an alias to
+ * the implementation-defined symbolic name since this Framework is also a
+ * System Bundle.
+ *
+ * @return The symbolic name of this Framework.
+ * @see Bundle#getSymbolicName()
+ * @see Constants#SYSTEM_BUNDLE_SYMBOLICNAME
+ */
+ String getSymbolicName();
+}
diff --git a/framework/src/main/java/org/osgi/framework/launch/FrameworkFactory.java b/framework/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
new file mode 100644
index 0000000..bcb6da3
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework.launch;
+
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * A factory for creating {@link Framework} instances.
+ *
+ * <p>
+ * A framework implementation jar must contain the following resource:
+ *
+ * <pre>
+ * /META-INF/services/org.osgi.framework.launch.FrameworkFactory
+ * </pre>
+ *
+ * This UTF-8 encoded resource must contain the name of the framework
+ * implementation's FrameworkFactory implementation class. Space and tab
+ * characters, including blank lines, in the resource must be ignored. The
+ * number sign ('#' \u0023) and all characters following it on each line are
+ * a comment and must be ignored.
+ *
+ * <p>
+ * Launchers can find the name of the FrameworkFactory implementation class in
+ * the resource and then load and construct a FrameworkFactory object for the
+ * framework implementation. The FrameworkFactory implementation class must have
+ * a public, no-argument constructor. Java™ SE 6 introduced the
+ * <code>ServiceLoader</code> class which can create a FrameworkFactory instance
+ * from the resource.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6888 $
+ */
+public interface FrameworkFactory {
+
+ /**
+ * Create a new {@link Framework} instance.
+ *
+ * @param configuration The framework properties to configure the new
+ * framework instance. If framework properties are not provided by
+ * the configuration argument, the created framework instance must
+ * use some reasonable default configuration appropriate for the
+ * current VM. For example, the system packages for the current
+ * execution environment should be properly exported. The specified
+ * configuration argument may be <code>null</code>. The created
+ * framework instance must copy any information needed from the
+ * specified configuration argument since the configuration argument
+ * can be changed after the framework instance has been created.
+ * @return A new, configured {@link Framework} instance. The framework
+ * instance must be in the {@link Bundle#INSTALLED} state.
+ * @throws SecurityException If the caller does not have
+ * <code>AllPermission</code>, and the Java Runtime Environment
+ * supports permissions.
+ */
+ Framework newFramework(Map configuration);
+}
diff --git a/framework/src/main/java/org/osgi/framework/launch/package.html b/framework/src/main/java/org/osgi/framework/launch/package.html
new file mode 100644
index 0000000..6b0407b
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/launch/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Framework Launch Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework.launch;version="[1.0,2.0)"
+</pre>
+</BODY>
+
diff --git a/framework/src/main/java/org/osgi/framework/launch/packageinfo b/framework/src/main/java/org/osgi/framework/launch/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/launch/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/framework/src/main/java/org/osgi/framework/package.html b/framework/src/main/java/org/osgi/framework/package.html
new file mode 100644
index 0000000..44d6c48
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Framework Package Version 1.5.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework;version="[1.5,2.0)"
+</pre>
+</BODY>
+
diff --git a/framework/src/main/java/org/osgi/framework/packageinfo b/framework/src/main/java/org/osgi/framework/packageinfo
new file mode 100644
index 0000000..ccee95e
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/packageinfo
@@ -0,0 +1 @@
+version 1.5
diff --git a/framework/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java b/framework/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java
new file mode 100644
index 0000000..67ba3e9
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) OSGi Alliance (2001, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.packageadmin;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+
+/**
+ * An exported package.
+ *
+ * Objects implementing this interface are created by the Package Admin service.
+ *
+ * <p>
+ * The term <i>exported package</i> refers to a package that has been exported
+ * from a resolved bundle. This package may or may not be currently wired to
+ * other bundles.
+ *
+ * <p>
+ * The information about an exported package provided by this object may change.
+ * An <code>ExportedPackage</code> object becomes stale if the package it
+ * references has been updated or removed as a result of calling
+ * <code>PackageAdmin.refreshPackages()</code>.
+ *
+ * If this object becomes stale, its <code>getName()</code> and
+ * <code>getVersion()</code> methods continue to return their original values,
+ * <code>isRemovalPending()</code> returns <code>true</code>, and
+ * <code>getExportingBundle()</code> and <code>getImportingBundles()</code>
+ * return <code>null</code>.
+ *
+ * @ThreadSafe
+ * @version $Revision: 5673 $
+ */
+public interface ExportedPackage {
+ /**
+ * Returns the name of the package associated with this exported package.
+ *
+ * @return The name of this exported package.
+ */
+ public String getName();
+
+ /**
+ * Returns the bundle exporting the package associated with this exported
+ * package.
+ *
+ * @return The exporting bundle, or <code>null</code> if this
+ * <code>ExportedPackage</code> object has become stale.
+ */
+ public Bundle getExportingBundle();
+
+ /**
+ * Returns the resolved bundles that are currently wired to this exported
+ * package.
+ *
+ * <p>
+ * Bundles which require the exporting bundle associated with this exported
+ * package are considered to be wired to this exported package are included
+ * in the returned array. See {@link RequiredBundle#getRequiringBundles()}.
+ *
+ * @return The array of resolved bundles currently wired to this exported
+ * package, or <code>null</code> if this
+ * <code>ExportedPackage</code> object has become stale. The array
+ * will be empty if no bundles are wired to this exported package.
+ */
+ public Bundle[] getImportingBundles();
+
+ /**
+ * Returns the version of this exported package.
+ *
+ * @return The version of this exported package, or <code>null</code> if
+ * no version information is available.
+ * @deprecated As of 1.2, replaced by {@link #getVersion}.
+ */
+ public String getSpecificationVersion();
+
+ /**
+ * Returns the version of this exported package.
+ *
+ * @return The version of this exported package, or
+ * {@link Version#emptyVersion} if no version information is
+ * available.
+ * @since 1.2
+ */
+ public Version getVersion();
+
+ /**
+ * Returns <code>true</code> if the package associated with this
+ * <code>ExportedPackage</code> object has been exported by a bundle that
+ * has been updated or uninstalled.
+ *
+ * @return <code>true</code> if the associated package is being exported
+ * by a bundle that has been updated or uninstalled, or if this
+ * <code>ExportedPackage</code> object has become stale;
+ * <code>false</code> otherwise.
+ */
+ public boolean isRemovalPending();
+}
diff --git a/framework/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java b/framework/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java
new file mode 100644
index 0000000..c93cd28
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) OSGi Alliance (2001, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.packageadmin;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * Framework service which allows bundle programmers to inspect the package
+ * wiring state of bundles in the Framework as well as other functions related
+ * to the class loader network among bundles.
+ *
+ * <p>
+ * If present, there will only be a single instance of this service registered
+ * with the Framework.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6779 $
+ * @see org.osgi.service.packageadmin.ExportedPackage
+ * @see org.osgi.service.packageadmin.RequiredBundle
+ */
+public interface PackageAdmin {
+ /**
+ * Gets the exported packages for the specified bundle.
+ *
+ * @param bundle The bundle whose exported packages are to be returned, or
+ * <code>null</code> if all exported packages are to be returned. If
+ * the specified bundle is the system bundle (that is, the bundle
+ * with id zero), this method returns all the packages known to be
+ * exported by the system bundle. This will include the package
+ * specified by the <code>org.osgi.framework.system.packages</code>
+ * system property as well as any other package exported by the
+ * framework implementation.
+ *
+ * @return An array of exported packages, or <code>null</code> if the
+ * specified bundle has no exported packages.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+ * not created by the same framework instance that registered this
+ * <code>PackageAdmin</code> service.
+ */
+ public ExportedPackage[] getExportedPackages(Bundle bundle);
+
+ /**
+ * Gets the exported packages for the specified package name.
+ *
+ * @param name The name of the exported packages to be returned.
+ *
+ * @return An array of the exported packages, or <code>null</code> if no
+ * exported packages with the specified name exists.
+ * @since 1.2
+ */
+ public ExportedPackage[] getExportedPackages(String name);
+
+ /**
+ * Gets the exported package for the specified package name.
+ *
+ * <p>
+ * If there are multiple exported packages with specified name, the exported
+ * package with the highest version will be returned.
+ *
+ * @param name The name of the exported package to be returned.
+ *
+ * @return The exported package, or <code>null</code> if no exported
+ * package with the specified name exists.
+ * @see #getExportedPackages(String)
+ */
+ public ExportedPackage getExportedPackage(String name);
+
+ /**
+ * Forces the update (replacement) or removal of packages exported by the
+ * specified bundles.
+ *
+ * <p>
+ * If no bundles are specified, this method will update or remove any
+ * packages exported by any bundles that were previously updated or
+ * uninstalled since the last call to this method. The technique by which
+ * this is accomplished may vary among different Framework implementations.
+ * One permissible implementation is to stop and restart the Framework.
+ *
+ * <p>
+ * This method returns to the caller immediately and then performs the
+ * following steps on a separate thread:
+ *
+ * <ol>
+ * <li>Compute a graph of bundles starting with the specified bundles. If no
+ * bundles are specified, compute a graph of bundles starting with bundle
+ * updated or uninstalled since the last call to this method. Add to the
+ * graph any bundle that is wired to a package that is currently exported by
+ * a bundle in the graph. The graph is fully constructed when there is no
+ * bundle outside the graph that is wired to a bundle in the graph. The
+ * graph may contain <code>UNINSTALLED</code> bundles that are currently
+ * still exporting packages.
+ *
+ * <li>Each bundle in the graph that is in the <code>ACTIVE</code> state
+ * will be stopped as described in the <code>Bundle.stop</code> method.
+ *
+ * <li>Each bundle in the graph that is in the <code>RESOLVED</code> state
+ * is unresolved and thus moved to the <code>INSTALLED</code> state. The
+ * effect of this step is that bundles in the graph are no longer
+ * <code>RESOLVED</code>.
+ *
+ * <li>Each bundle in the graph that is in the <code>UNINSTALLED</code>
+ * state is removed from the graph and is now completely removed from the
+ * Framework.
+ *
+ * <li>Each bundle in the graph that was in the <code>ACTIVE</code> state
+ * prior to Step 2 is started as described in the <code>Bundle.start</code>
+ * method, causing all bundles required for the restart to be resolved. It
+ * is possible that, as a result of the previous steps, packages that were
+ * previously exported no longer are. Therefore, some bundles may be
+ * unresolvable until another bundle offering a compatible package for
+ * export has been installed in the Framework.
+ * <li>A framework event of type
+ * <code>FrameworkEvent.PACKAGES_REFRESHED</code> is fired.
+ * </ol>
+ *
+ * <p>
+ * For any exceptions that are thrown during any of these steps, a
+ * <code>FrameworkEvent</code> of type <code>ERROR</code> is fired
+ * containing the exception. The source bundle for these events should be
+ * the specific bundle to which the exception is related. If no specific
+ * bundle can be associated with the exception then the System Bundle must
+ * be used as the source bundle for the event.
+ *
+ * @param bundles The bundles whose exported packages are to be updated or
+ * removed, or <code>null</code> for all bundles updated or
+ * uninstalled since the last call to this method.
+ * @throws SecurityException If the caller does not have
+ * <code>AdminPermission[System Bundle,RESOLVE]</code> and the Java
+ * runtime environment supports permissions.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code>s
+ * were not created by the same framework instance that registered
+ * this <code>PackageAdmin</code> service.
+ */
+ public void refreshPackages(Bundle[] bundles);
+
+ /**
+ * Resolve the specified bundles. The Framework must attempt to resolve the
+ * specified bundles that are unresolved. Additional bundles that are not
+ * included in the specified bundles may be resolved as a result of calling
+ * this method. A permissible implementation of this method is to attempt to
+ * resolve all unresolved bundles installed in the framework.
+ *
+ * <p>
+ * If <code>null</code> is specified then the Framework will attempt to
+ * resolve all unresolved bundles. This method must not cause any bundle to
+ * be refreshed, stopped, or started. This method will not return until the
+ * operation has completed.
+ *
+ * @param bundles The bundles to resolve or <code>null</code> to resolve all
+ * unresolved bundles installed in the Framework.
+ * @return <code>true</code> if all specified bundles are resolved;
+ * @throws SecurityException If the caller does not have
+ * <code>AdminPermission[System Bundle,RESOLVE]</code> and the Java
+ * runtime environment supports permissions.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code>s
+ * were not created by the same framework instance that registered
+ * this <code>PackageAdmin</code> service.
+ * @since 1.2
+ */
+ public boolean resolveBundles(Bundle[] bundles);
+
+ /**
+ * Returns an array of required bundles having the specified symbolic name.
+ *
+ * <p>
+ * If <code>null</code> is specified, then all required bundles will be
+ * returned.
+ *
+ * @param symbolicName The bundle symbolic name or <code>null</code> for
+ * all required bundles.
+ * @return An array of required bundles or <code>null</code> if no
+ * required bundles exist for the specified symbolic name.
+ * @since 1.2
+ */
+ public RequiredBundle[] getRequiredBundles(String symbolicName);
+
+ /**
+ * Returns the bundles with the specified symbolic name whose bundle version
+ * is within the specified version range. If no bundles are installed that
+ * have the specified symbolic name, then <code>null</code> is returned.
+ * If a version range is specified, then only the bundles that have the
+ * specified symbolic name and whose bundle versions belong to the specified
+ * version range are returned. The returned bundles are ordered by version
+ * in descending version order so that the first element of the array
+ * contains the bundle with the highest version.
+ *
+ * @see org.osgi.framework.Constants#BUNDLE_VERSION_ATTRIBUTE
+ * @param symbolicName The symbolic name of the desired bundles.
+ * @param versionRange The version range of the desired bundles, or
+ * <code>null</code> if all versions are desired.
+ * @return An array of bundles with the specified name belonging to the
+ * specified version range ordered in descending version order, or
+ * <code>null</code> if no bundles are found.
+ * @since 1.2
+ */
+ public Bundle[] getBundles(String symbolicName, String versionRange);
+
+ /**
+ * Returns an array of attached fragment bundles for the specified bundle.
+ * If the specified bundle is a fragment then <code>null</code> is returned.
+ * If no fragments are attached to the specified bundle then
+ * <code>null</code> is returned.
+ * <p>
+ * This method does not attempt to resolve the specified bundle. If the
+ * specified bundle is not resolved then <code>null</code> is returned.
+ *
+ * @param bundle The bundle whose attached fragment bundles are to be
+ * returned.
+ * @return An array of fragment bundles or <code>null</code> if the bundle
+ * does not have any attached fragment bundles or the bundle is not
+ * resolved.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+ * not created by the same framework instance that registered this
+ * <code>PackageAdmin</code> service.
+ * @since 1.2
+ */
+ public Bundle[] getFragments(Bundle bundle);
+
+ /**
+ * Returns the host bundles to which the specified fragment bundle is
+ * attached.
+ *
+ * @param bundle The fragment bundle whose host bundles are to be returned.
+ * @return An array containing the host bundles to which the specified
+ * fragment is attached or <code>null</code> if the specified bundle
+ * is not a fragment or is not attached to any host bundles.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+ * not created by the same framework instance that registered this
+ * <code>PackageAdmin</code> service.
+ * @since 1.2
+ */
+ public Bundle[] getHosts(Bundle bundle);
+
+ /**
+ * Returns the bundle from which the specified class is loaded. The class
+ * loader of the returned bundle must have been used to load the specified
+ * class. If the class was not loaded by a bundle class loader then
+ * <code>null</code> is returned.
+ *
+ * @param clazz The class object from which to locate the bundle.
+ * @return The bundle from which the specified class is loaded or
+ * <code>null</code> if the class was not loaded by a bundle class
+ * loader created by the same framework instance that registered
+ * this <code>PackageAdmin</code> service.
+ * @since 1.2
+ */
+ public Bundle getBundle(Class clazz);
+
+ /**
+ * Bundle type indicating the bundle is a fragment bundle.
+ *
+ * <p>
+ * The value of <code>BUNDLE_TYPE_FRAGMENT</code> is 0x00000001.
+ *
+ * @since 1.2
+ */
+ public static final int BUNDLE_TYPE_FRAGMENT = 0x00000001;
+
+ /**
+ * Returns the special type of the specified bundle. The bundle type values
+ * are:
+ * <ul>
+ * <li>{@link #BUNDLE_TYPE_FRAGMENT}
+ * </ul>
+ *
+ * A bundle may be more than one type at a time. A type code is used to
+ * identify the bundle type for future extendability.
+ *
+ * <p>
+ * If a bundle is not one or more of the defined types then 0x00000000 is
+ * returned.
+ *
+ * @param bundle The bundle for which to return the special type.
+ * @return The special type of the bundle.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+ * not created by the same framework instance that registered this
+ * <code>PackageAdmin</code> service.
+ * @since 1.2
+ */
+ public int getBundleType(Bundle bundle);
+}
diff --git a/framework/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java b/framework/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java
new file mode 100644
index 0000000..b15c5df
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.packageadmin;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+
+/**
+ * A required bundle.
+ *
+ * Objects implementing this interface are created by the Package Admin service.
+ *
+ * <p>
+ * The term <i>required bundle</i> refers to a resolved bundle that has a
+ * bundle symbolic name and is not a fragment. That is, a bundle that may be
+ * required by other bundles. This bundle may or may not be currently required
+ * by other bundles.
+ *
+ * <p>
+ * The information about a required bundle provided by this object may change. A
+ * <code>RequiredBundle</code> object becomes stale if an exported package of
+ * the bundle it references has been updated or removed as a result of calling
+ * <code>PackageAdmin.refreshPackages()</code>).
+ *
+ * If this object becomes stale, its <code>getSymbolicName()</code> and
+ * <code>getVersion()</code> methods continue to return their original values,
+ * <code>isRemovalPending()</code> returns true, and <code>getBundle()</code>
+ * and <code>getRequiringBundles()</code> return <code>null</code>.
+ *
+ * @since 1.2
+ * @ThreadSafe
+ * @version $Revision: 5673 $
+ */
+public interface RequiredBundle {
+ /**
+ * Returns the symbolic name of this required bundle.
+ *
+ * @return The symbolic name of this required bundle.
+ */
+ public String getSymbolicName();
+
+ /**
+ * Returns the bundle associated with this required bundle.
+ *
+ * @return The bundle, or <code>null</code> if this
+ * <code>RequiredBundle</code> object has become stale.
+ */
+ public Bundle getBundle();
+
+ /**
+ * Returns the bundles that currently require this required bundle.
+ *
+ * <p>
+ * If this required bundle is required and then re-exported by another
+ * bundle then all the requiring bundles of the re-exporting bundle are
+ * included in the returned array.
+ *
+ * @return An array of bundles currently requiring this required bundle, or
+ * <code>null</code> if this <code>RequiredBundle</code> object
+ * has become stale. The array will be empty if no bundles require
+ * this required package.
+ */
+ public Bundle[] getRequiringBundles();
+
+ /**
+ * Returns the version of this required bundle.
+ *
+ * @return The version of this required bundle, or
+ * {@link Version#emptyVersion} if no version information is
+ * available.
+ */
+ public Version getVersion();
+
+ /**
+ * Returns <code>true</code> if the bundle associated with this
+ * <code>RequiredBundle</code> object has been updated or uninstalled.
+ *
+ * @return <code>true</code> if the required bundle has been updated or
+ * uninstalled, or if the <code>RequiredBundle</code> object has
+ * become stale; <code>false</code> otherwise.
+ */
+ public boolean isRemovalPending();
+}
diff --git a/framework/src/main/java/org/osgi/service/packageadmin/package.html b/framework/src/main/java/org/osgi/service/packageadmin/package.html
new file mode 100644
index 0000000..9fc9cab
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/packageadmin/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Package Admin Package Version 1.2.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.packageadmin; version="[1.2,2.0)"
+</pre>
+</BODY>
+
diff --git a/framework/src/main/java/org/osgi/service/packageadmin/packageinfo b/framework/src/main/java/org/osgi/service/packageadmin/packageinfo
new file mode 100644
index 0000000..ef7df68
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/packageadmin/packageinfo
@@ -0,0 +1 @@
+version 1.2
diff --git a/framework/src/main/java/org/osgi/service/startlevel/StartLevel.java b/framework/src/main/java/org/osgi/service/startlevel/StartLevel.java
new file mode 100644
index 0000000..8a69b03
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/startlevel/StartLevel.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) OSGi Alliance (2002, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.startlevel;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * The StartLevel service allows management agents to manage a start level
+ * assigned to each bundle and the active start level of the Framework. There is
+ * at most one StartLevel service present in the OSGi environment.
+ *
+ * <p>
+ * A start level is defined to be a state of execution in which the Framework
+ * exists. StartLevel values are defined as unsigned integers with 0 (zero)
+ * being the state where the Framework is not launched. Progressively higher
+ * integral values represent progressively higher start levels. e.g. 2 is a
+ * higher start level than 1.
+ * <p>
+ * Access to the StartLevel service is protected by corresponding
+ * <code>ServicePermission</code>. In addition <code>AdminPermission</code>
+ * is required to actually modify start level information.
+ * <p>
+ * Start Level support in the Framework includes the ability to control the
+ * beginning start level of the Framework, to modify the active start level of
+ * the Framework and to assign a specific start level to a bundle. How the
+ * beginning start level of a Framework is specified is implementation
+ * dependent. It may be a command line argument when invoking the Framework
+ * implementation.
+ * <p>
+ * When the Framework is first started it must be at start level zero. In this
+ * state, no bundles are running. This is the initial state of the Framework
+ * before it is launched.
+ *
+ * When the Framework is launched, the Framework will enter start level one and
+ * all bundles which are assigned to start level one and whose autostart setting
+ * indicates the bundle should be started are started as described in the
+ * <code>Bundle.start</code> method. The Framework will continue to increase
+ * the start level, starting bundles at each start level, until the Framework
+ * has reached a beginning start level. At this point the Framework has
+ * completed starting bundles and will then fire a Framework event of type
+ * <code>FrameworkEvent.STARTED</code> to announce it has completed its
+ * launch.
+ *
+ * <p>
+ * Within a start level, bundles may be started in an order defined by the
+ * Framework implementation. This may be something like ascending
+ * <code>Bundle.getBundleId</code> order or an order based upon dependencies
+ * between bundles. A similar but reversed order may be used when stopping
+ * bundles within a start level.
+ *
+ * <p>
+ * The StartLevel service can be used by management bundles to alter the active
+ * start level of the framework.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6747 $
+ */
+public interface StartLevel {
+ /**
+ * Return the active start level value of the Framework.
+ *
+ * If the Framework is in the process of changing the start level this
+ * method must return the active start level if this differs from the
+ * requested start level.
+ *
+ * @return The active start level value of the Framework.
+ */
+ public int getStartLevel();
+
+ /**
+ * Modify the active start level of the Framework.
+ *
+ * <p>
+ * The Framework will move to the requested start level. This method will
+ * return immediately to the caller and the start level change will occur
+ * asynchronously on another thread.
+ *
+ * <p>
+ * If the specified start level is higher than the active start level, the
+ * Framework will continue to increase the start level until the Framework
+ * has reached the specified start level.
+ *
+ * At each intermediate start level value on the way to and including the
+ * target start level, the Framework must:
+ * <ol>
+ * <li>Change the active start level to the intermediate start level value.
+ * <li>Start bundles at the intermediate start level whose autostart
+ * setting indicate they must be started. They are started as described in
+ * the {@link Bundle#start(int)} method using the
+ * {@link Bundle#START_TRANSIENT} option. The
+ * {@link Bundle#START_ACTIVATION_POLICY} option must also be used if
+ * {@link #isBundleActivationPolicyUsed(Bundle)} returns <code>true</code>
+ * for the bundle.
+ * </ol>
+ * When this process completes after the specified start level is reached,
+ * the Framework will fire a Framework event of type
+ * <code>FrameworkEvent.STARTLEVEL_CHANGED</code> to announce it has moved
+ * to the specified start level.
+ *
+ * <p>
+ * If the specified start level is lower than the active start level, the
+ * Framework will continue to decrease the start level until the Framework
+ * has reached the specified start level.
+ *
+ * At each intermediate start level value on the way to and including the
+ * specified start level, the framework must:
+ * <ol>
+ * <li>Stop bundles at the intermediate start level as described in the
+ * {@link Bundle#stop(int)} method using the {@link Bundle#STOP_TRANSIENT}
+ * option.
+ * <li>Change the active start level to the intermediate start level value.
+ * </ol>
+ * When this process completes after the specified start level is reached,
+ * the Framework will fire a Framework event of type
+ * <code>FrameworkEvent.STARTLEVEL_CHANGED</code> to announce it has moved
+ * to the specified start level.
+ *
+ * <p>
+ * If the specified start level is equal to the active start level, then no
+ * bundles are started or stopped, however, the Framework must fire a
+ * Framework event of type <code>FrameworkEvent.STARTLEVEL_CHANGED</code>
+ * to announce it has finished moving to the specified start level. This
+ * event may arrive before this method return.
+ *
+ * @param startlevel The requested start level for the Framework.
+ * @throws IllegalArgumentException If the specified start level is less
+ * than or equal to zero.
+ * @throws SecurityException If the caller does not have
+ * <code>AdminPermission[System Bundle,STARTLEVEL]</code> and the
+ * Java runtime environment supports permissions.
+ */
+ public void setStartLevel(int startlevel);
+
+ /**
+ * Return the assigned start level value for the specified Bundle.
+ *
+ * @param bundle The target bundle.
+ * @return The start level value of the specified Bundle.
+ * @throws java.lang.IllegalArgumentException If the specified bundle has
+ * been uninstalled or if the specified bundle was not created by
+ * the same framework instance that registered this
+ * <code>StartLevel</code> service.
+ */
+ public int getBundleStartLevel(Bundle bundle);
+
+ /**
+ * Assign a start level value to the specified Bundle.
+ *
+ * <p>
+ * The specified bundle will be assigned the specified start level. The
+ * start level value assigned to the bundle will be persistently recorded by
+ * the Framework.
+ * <p>
+ * If the new start level for the bundle is lower than or equal to the
+ * active start level of the Framework and the bundle's autostart setting
+ * indicates the bundle must be started, the Framework will start the
+ * specified bundle as described in the {@link Bundle#start(int)} method
+ * using the {@link Bundle#START_TRANSIENT} option. The
+ * {@link Bundle#START_ACTIVATION_POLICY} option must also be used if
+ * {@link #isBundleActivationPolicyUsed(Bundle)} returns <code>true</code>
+ * for the bundle. The actual starting of this bundle must occur
+ * asynchronously.
+ * <p>
+ * If the new start level for the bundle is higher than the active start
+ * level of the Framework, the Framework will stop the specified bundle as
+ * described in the {@link Bundle#stop(int)} method using the
+ * {@link Bundle#STOP_TRANSIENT} option. The actual stopping of this bundle
+ * must occur asynchronously.
+ *
+ * @param bundle The target bundle.
+ * @param startlevel The new start level for the specified Bundle.
+ * @throws IllegalArgumentException If the specified bundle has been
+ * uninstalled, or if the specified start level is less than or
+ * equal to zero, or if the specified bundle is the system bundle,
+ * or if the specified bundle was not created by the same framework
+ * instance that registered this <code>StartLevel</code> service.
+ * @throws SecurityException If the caller does not have
+ * <code>AdminPermission[bundle,EXECUTE]</code> and the Java runtime
+ * environment supports permissions.
+ */
+ public void setBundleStartLevel(Bundle bundle, int startlevel);
+
+ /**
+ * Return the initial start level value that is assigned to a Bundle when it
+ * is first installed.
+ *
+ * @return The initial start level value for Bundles.
+ * @see #setInitialBundleStartLevel
+ */
+ public int getInitialBundleStartLevel();
+
+ /**
+ * Set the initial start level value that is assigned to a Bundle when it is
+ * first installed.
+ *
+ * <p>
+ * The initial bundle start level will be set to the specified start level.
+ * The initial bundle start level value will be persistently recorded by the
+ * Framework.
+ *
+ * <p>
+ * When a Bundle is installed via <code>BundleContext.installBundle</code>,
+ * it is assigned the initial bundle start level value.
+ *
+ * <p>
+ * The default initial bundle start level value is 1 unless this method has
+ * been called to assign a different initial bundle start level value.
+ *
+ * <p>
+ * This method does not change the start level values of installed bundles.
+ *
+ * @param startlevel The initial start level for newly installed bundles.
+ * @throws IllegalArgumentException If the specified start level is less
+ * than or equal to zero.
+ * @throws SecurityException If the caller does not have
+ * <code>AdminPermission[System Bundle,STARTLEVEL]</code> and the
+ * Java runtime environment supports permissions.
+ */
+ public void setInitialBundleStartLevel(int startlevel);
+
+ /**
+ * Returns whether the specified bundle's autostart setting indicates the
+ * bundle must be started.
+ * <p>
+ * The autostart setting of a bundle indicates whether the bundle is to be
+ * started when its start level is reached.
+ *
+ * @param bundle The bundle whose autostart setting is to be examined.
+ * @return <code>true</code> if the autostart setting of the bundle
+ * indicates the bundle is to be started. <code>false</code>
+ * otherwise.
+ * @throws java.lang.IllegalArgumentException If the specified bundle has
+ * been uninstalled or if the specified bundle was not created by
+ * the same framework instance that registered this
+ * <code>StartLevel</code> service.
+ * @see Bundle#START_TRANSIENT
+ */
+ public boolean isBundlePersistentlyStarted(Bundle bundle);
+
+ /**
+ * Returns whether the specified bundle's autostart setting indicates that
+ * the activation policy declared in the bundle's manifest must be used.
+ * <p>
+ * The autostart setting of a bundle indicates whether the bundle's declared
+ * activation policy is to be used when the bundle is started.
+ *
+ * @param bundle The bundle whose autostart setting is to be examined.
+ * @return <code>true</code> if the bundle's autostart setting indicates the
+ * activation policy declared in the manifest must be used.
+ * <code>false</code> if the bundle must be eagerly activated.
+ * @throws java.lang.IllegalArgumentException If the specified bundle has
+ * been uninstalled or if the specified bundle was not created by
+ * the same framework instance that registered this
+ * <code>StartLevel</code> service.
+ * @since 1.1
+ * @see Bundle#START_ACTIVATION_POLICY
+ */
+ public boolean isBundleActivationPolicyUsed(Bundle bundle);
+}
diff --git a/framework/src/main/java/org/osgi/service/startlevel/package.html b/framework/src/main/java/org/osgi/service/startlevel/package.html
new file mode 100644
index 0000000..4c27532
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/startlevel/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Start Level Package Version 1.1.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.startlevel; version="[1.1,2.0)"
+</pre>
+</BODY>
+
diff --git a/framework/src/main/java/org/osgi/service/startlevel/packageinfo b/framework/src/main/java/org/osgi/service/startlevel/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/startlevel/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/framework/src/main/java/org/osgi/service/url/AbstractURLStreamHandlerService.java b/framework/src/main/java/org/osgi/service/url/AbstractURLStreamHandlerService.java
new file mode 100644
index 0000000..1ad37a2
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/url/AbstractURLStreamHandlerService.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) OSGi Alliance (2002, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.url;
+
+import java.net.*;
+
+/**
+ * Abstract implementation of the <code>URLStreamHandlerService</code>
+ * interface. All the methods simply invoke the corresponding methods on
+ * <code>java.net.URLStreamHandler</code> except for <code>parseURL</code>
+ * and <code>setURL</code>, which use the <code>URLStreamHandlerSetter</code>
+ * parameter. Subclasses of this abstract class should not need to override the
+ * <code>setURL</code> and <code>parseURL(URLStreamHandlerSetter,...)</code>
+ * methods.
+ *
+ * @ThreadSafe
+ * @version $Revision: 5673 $
+ */
+public abstract class AbstractURLStreamHandlerService extends URLStreamHandler
+ implements URLStreamHandlerService {
+ /**
+ * @see "java.net.URLStreamHandler.openConnection"
+ */
+ public abstract URLConnection openConnection(URL u)
+ throws java.io.IOException;
+
+ /**
+ * The <code>URLStreamHandlerSetter</code> object passed to the parseURL
+ * method.
+ */
+ protected volatile URLStreamHandlerSetter realHandler;
+
+ /**
+ * Parse a URL using the <code>URLStreamHandlerSetter</code> object. This
+ * method sets the <code>realHandler</code> field with the specified
+ * <code>URLStreamHandlerSetter</code> object and then calls
+ * <code>parseURL(URL,String,int,int)</code>.
+ *
+ * @param realHandler The object on which the <code>setURL</code> method
+ * must be invoked for the specified URL.
+ * @see "java.net.URLStreamHandler.parseURL"
+ */
+ public void parseURL(URLStreamHandlerSetter realHandler, URL u,
+ String spec, int start, int limit) {
+ this.realHandler = realHandler;
+ parseURL(u, spec, start, limit);
+ }
+
+ /**
+ * This method calls <code>super.toExternalForm</code>.
+ *
+ * @see "java.net.URLStreamHandler.toExternalForm"
+ */
+ public String toExternalForm(URL u) {
+ return super.toExternalForm(u);
+ }
+
+ /**
+ * This method calls <code>super.equals(URL,URL)</code>.
+ *
+ * @see "java.net.URLStreamHandler.equals(URL,URL)"
+ */
+ public boolean equals(URL u1, URL u2) {
+ return super.equals(u1, u2);
+ }
+
+ /**
+ * This method calls <code>super.getDefaultPort</code>.
+ *
+ * @see "java.net.URLStreamHandler.getDefaultPort"
+ */
+ public int getDefaultPort() {
+ return super.getDefaultPort();
+ }
+
+ /**
+ * This method calls <code>super.getHostAddress</code>.
+ *
+ * @see "java.net.URLStreamHandler.getHostAddress"
+ */
+ public InetAddress getHostAddress(URL u) {
+ return super.getHostAddress(u);
+ }
+
+ /**
+ * This method calls <code>super.hashCode(URL)</code>.
+ *
+ * @see "java.net.URLStreamHandler.hashCode(URL)"
+ */
+ public int hashCode(URL u) {
+ return super.hashCode(u);
+ }
+
+ /**
+ * This method calls <code>super.hostsEqual</code>.
+ *
+ * @see "java.net.URLStreamHandler.hostsEqual"
+ */
+ public boolean hostsEqual(URL u1, URL u2) {
+ return super.hostsEqual(u1, u2);
+ }
+
+ /**
+ * This method calls <code>super.sameFile</code>.
+ *
+ * @see "java.net.URLStreamHandler.sameFile"
+ */
+ public boolean sameFile(URL u1, URL u2) {
+ return super.sameFile(u1, u2);
+ }
+
+ /**
+ * This method calls
+ * <code>realHandler.setURL(URL,String,String,int,String,String)</code>.
+ *
+ * @see "java.net.URLStreamHandler.setURL(URL,String,String,int,String,String)"
+ * @deprecated This method is only for compatibility with handlers written
+ * for JDK 1.1.
+ */
+ protected void setURL(URL u, String proto, String host, int port,
+ String file, String ref) {
+ realHandler.setURL(u, proto, host, port, file, ref);
+ }
+
+ /**
+ * This method calls
+ * <code>realHandler.setURL(URL,String,String,int,String,String,String,String)</code>.
+ *
+ * @see "java.net.URLStreamHandler.setURL(URL,String,String,int,String,String,String,String)"
+ */
+ protected void setURL(URL u, String proto, String host, int port,
+ String auth, String user, String path, String query, String ref) {
+ realHandler.setURL(u, proto, host, port, auth, user, path, query, ref);
+ }
+}
diff --git a/framework/src/main/java/org/osgi/service/url/URLConstants.java b/framework/src/main/java/org/osgi/service/url/URLConstants.java
new file mode 100644
index 0000000..ae95305
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/url/URLConstants.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) OSGi Alliance (2002, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.url;
+
+/**
+ * Defines standard names for property keys associated with
+ * {@link URLStreamHandlerService} and <code>java.net.ContentHandler</code>
+ * services.
+ *
+ * <p>
+ * The values associated with these keys are of type
+ * <code>java.lang.String[]</code> or <code>java.lang.String</code>, unless
+ * otherwise indicated.
+ *
+ * @version $Revision: 5673 $
+ */
+public interface URLConstants {
+ /**
+ * Service property naming the protocols serviced by a
+ * URLStreamHandlerService. The property's value is a protocol name or an
+ * array of protocol names.
+ */
+ public static final String URL_HANDLER_PROTOCOL = "url.handler.protocol";
+ /**
+ * Service property naming the MIME types serviced by a
+ * java.net.ContentHandler. The property's value is a MIME type or an array
+ * of MIME types.
+ */
+ public static final String URL_CONTENT_MIMETYPE = "url.content.mimetype";
+}
diff --git a/framework/src/main/java/org/osgi/service/url/URLStreamHandlerService.java b/framework/src/main/java/org/osgi/service/url/URLStreamHandlerService.java
new file mode 100644
index 0000000..b1ff7d8
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/url/URLStreamHandlerService.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) OSGi Alliance (2002, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.url;
+
+import java.net.*;
+
+/**
+ * Service interface with public versions of the protected
+ * <code>java.net.URLStreamHandler</code> methods.
+ * <p>
+ * The important differences between this interface and the
+ * <code>URLStreamHandler</code> class are that the <code>setURL</code>
+ * method is absent and the <code>parseURL</code> method takes a
+ * {@link URLStreamHandlerSetter} object as the first argument. Classes
+ * implementing this interface must call the <code>setURL</code> method on the
+ * <code>URLStreamHandlerSetter</code> object received in the
+ * <code>parseURL</code> method instead of
+ * <code>URLStreamHandler.setURL</code> to avoid a
+ * <code>SecurityException</code>.
+ *
+ * @see AbstractURLStreamHandlerService
+ *
+ * @ThreadSafe
+ * @version $Revision: 5673 $
+ */
+public interface URLStreamHandlerService {
+ /**
+ * @see "java.net.URLStreamHandler.openConnection"
+ */
+ public URLConnection openConnection(URL u) throws java.io.IOException;
+
+ /**
+ * Parse a URL. This method is called by the <code>URLStreamHandler</code>
+ * proxy, instead of <code>java.net.URLStreamHandler.parseURL</code>,
+ * passing a <code>URLStreamHandlerSetter</code> object.
+ *
+ * @param realHandler The object on which <code>setURL</code> must be
+ * invoked for this URL.
+ * @see "java.net.URLStreamHandler.parseURL"
+ */
+ public void parseURL(URLStreamHandlerSetter realHandler, URL u,
+ String spec, int start, int limit);
+
+ /**
+ * @see "java.net.URLStreamHandler.toExternalForm"
+ */
+ public String toExternalForm(URL u);
+
+ /**
+ * @see "java.net.URLStreamHandler.equals(URL, URL)"
+ */
+ public boolean equals(URL u1, URL u2);
+
+ /**
+ * @see "java.net.URLStreamHandler.getDefaultPort"
+ */
+ public int getDefaultPort();
+
+ /**
+ * @see "java.net.URLStreamHandler.getHostAddress"
+ */
+ public InetAddress getHostAddress(URL u);
+
+ /**
+ * @see "java.net.URLStreamHandler.hashCode(URL)"
+ */
+ public int hashCode(URL u);
+
+ /**
+ * @see "java.net.URLStreamHandler.hostsEqual"
+ */
+ public boolean hostsEqual(URL u1, URL u2);
+
+ /**
+ * @see "java.net.URLStreamHandler.sameFile"
+ */
+ public boolean sameFile(URL u1, URL u2);
+}
diff --git a/framework/src/main/java/org/osgi/service/url/URLStreamHandlerSetter.java b/framework/src/main/java/org/osgi/service/url/URLStreamHandlerSetter.java
new file mode 100644
index 0000000..36bdce8
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/url/URLStreamHandlerSetter.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) OSGi Alliance (2002, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.url;
+
+import java.net.URL;
+
+/**
+ * Interface used by <code>URLStreamHandlerService</code> objects to call the
+ * <code>setURL</code> method on the proxy <code>URLStreamHandler</code>
+ * object.
+ *
+ * <p>
+ * Objects of this type are passed to the
+ * {@link URLStreamHandlerService#parseURL} method. Invoking the
+ * <code>setURL</code> method on the <code>URLStreamHandlerSetter</code>
+ * object will invoke the <code>setURL</code> method on the proxy
+ * <code>URLStreamHandler</code> object that is actually registered with
+ * <code>java.net.URL</code> for the protocol.
+ *
+ * @ThreadSafe
+ * @version $Revision: 5673 $
+ */
+public interface URLStreamHandlerSetter {
+ /**
+ * @see "java.net.URLStreamHandler.setURL(URL,String,String,int,String,String)"
+ *
+ * @deprecated This method is only for compatibility with handlers written
+ * for JDK 1.1.
+ */
+ public void setURL(URL u, String protocol, String host, int port,
+ String file, String ref);
+
+ /**
+ * @see "java.net.URLStreamHandler.setURL(URL,String,String,int,String,String,String,String)"
+ */
+ public void setURL(URL u, String protocol, String host, int port,
+ String authority, String userInfo, String path, String query,
+ String ref);
+}
diff --git a/framework/src/main/java/org/osgi/service/url/package.html b/framework/src/main/java/org/osgi/service/url/package.html
new file mode 100644
index 0000000..4ed4d6e
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/url/package.html
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>URL Stream and Content Handlers Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.url; version="[1.0,2.0)"
+</pre>
+</BODY>
diff --git a/framework/src/main/java/org/osgi/service/url/packageinfo b/framework/src/main/java/org/osgi/service/url/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/url/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/framework/src/main/java/org/osgi/util/tracker/AbstractTracked.java b/framework/src/main/java/org/osgi/util/tracker/AbstractTracked.java
new file mode 100644
index 0000000..681148f
--- /dev/null
+++ b/framework/src/main/java/org/osgi/util/tracker/AbstractTracked.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) OSGi Alliance (2007, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.util.tracker;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Abstract class to track items. If a Tracker is reused (closed then reopened),
+ * then a new AbstractTracked object is used. This class acts a map of tracked
+ * item -> customized object. Subclasses of this class will act as the listener
+ * object for the tracker. This class is used to synchronize access to the
+ * tracked items. This is not a public class. It is only for use by the
+ * implementation of the Tracker class.
+ *
+ * @ThreadSafe
+ * @version $Revision: 5871 $
+ * @since 1.4
+ */
+abstract class AbstractTracked {
+ /* set this to true to compile in debug messages */
+ static final boolean DEBUG = false;
+
+ /**
+ * Map of tracked items to customized objects.
+ *
+ * @GuardedBy this
+ */
+ private final Map tracked;
+
+ /**
+ * Modification count. This field is initialized to zero and incremented by
+ * modified.
+ *
+ * @GuardedBy this
+ */
+ private int trackingCount;
+
+ /**
+ * List of items in the process of being added. This is used to deal with
+ * nesting of events. Since events may be synchronously delivered, events
+ * can be nested. For example, when processing the adding of a service and
+ * the customizer causes the service to be unregistered, notification to the
+ * nested call to untrack that the service was unregistered can be made to
+ * the track method.
+ *
+ * Since the ArrayList implementation is not synchronized, all access to
+ * this list must be protected by the same synchronized object for
+ * thread-safety.
+ *
+ * @GuardedBy this
+ */
+ private final List adding;
+
+ /**
+ * true if the tracked object is closed.
+ *
+ * This field is volatile because it is set by one thread and read by
+ * another.
+ */
+ volatile boolean closed;
+
+ /**
+ * Initial list of items for the tracker. This is used to correctly process
+ * the initial items which could be modified before they are tracked. This
+ * is necessary since the initial set of tracked items are not "announced"
+ * by events and therefore the event which makes the item untracked could be
+ * delivered before we track the item.
+ *
+ * An item must not be in both the initial and adding lists at the same
+ * time. An item must be moved from the initial list to the adding list
+ * "atomically" before we begin tracking it.
+ *
+ * Since the LinkedList implementation is not synchronized, all access to
+ * this list must be protected by the same synchronized object for
+ * thread-safety.
+ *
+ * @GuardedBy this
+ */
+ private final LinkedList initial;
+
+ /**
+ * AbstractTracked constructor.
+ */
+ AbstractTracked() {
+ tracked = new HashMap();
+ trackingCount = 0;
+ adding = new ArrayList(6);
+ initial = new LinkedList();
+ closed = false;
+ }
+
+ /**
+ * Set initial list of items into tracker before events begin to be
+ * received.
+ *
+ * This method must be called from Tracker's open method while synchronized
+ * on this object in the same synchronized block as the add listener call.
+ *
+ * @param list The initial list of items to be tracked. <code>null</code>
+ * entries in the list are ignored.
+ * @GuardedBy this
+ */
+ void setInitial(Object[] list) {
+ if (list == null) {
+ return;
+ }
+ int size = list.length;
+ for (int i = 0; i < size; i++) {
+ Object item = list[i];
+ if (item == null) {
+ continue;
+ }
+ if (DEBUG) {
+ System.out.println("AbstractTracked.setInitial: " + item); //$NON-NLS-1$
+ }
+ initial.add(item);
+ }
+ }
+
+ /**
+ * Track the initial list of items. This is called after events can begin to
+ * be received.
+ *
+ * This method must be called from Tracker's open method while not
+ * synchronized on this object after the add listener call.
+ *
+ */
+ void trackInitial() {
+ while (true) {
+ Object item;
+ synchronized (this) {
+ if (closed || (initial.size() == 0)) {
+ /*
+ * if there are no more initial items
+ */
+ return; /* we are done */
+ }
+ /*
+ * move the first item from the initial list to the adding list
+ * within this synchronized block.
+ */
+ item = initial.removeFirst();
+ if (tracked.get(item) != null) {
+ /* if we are already tracking this item */
+ if (DEBUG) {
+ System.out
+ .println("AbstractTracked.trackInitial[already tracked]: " + item); //$NON-NLS-1$
+ }
+ continue; /* skip this item */
+ }
+ if (adding.contains(item)) {
+ /*
+ * if this item is already in the process of being added.
+ */
+ if (DEBUG) {
+ System.out
+ .println("AbstractTracked.trackInitial[already adding]: " + item); //$NON-NLS-1$
+ }
+ continue; /* skip this item */
+ }
+ adding.add(item);
+ }
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackInitial: " + item); //$NON-NLS-1$
+ }
+ trackAdding(item, null); /*
+ * Begin tracking it. We call trackAdding
+ * since we have already put the item in the
+ * adding list.
+ */
+ }
+ }
+
+ /**
+ * Called by the owning Tracker object when it is closed.
+ */
+ void close() {
+ closed = true;
+ }
+
+ /**
+ * Begin to track an item.
+ *
+ * @param item Item to be tracked.
+ * @param related Action related object.
+ */
+ void track(final Object item, final Object related) {
+ final Object object;
+ synchronized (this) {
+ if (closed) {
+ return;
+ }
+ object = tracked.get(item);
+ if (object == null) { /* we are not tracking the item */
+ if (adding.contains(item)) {
+ /* if this item is already in the process of being added. */
+ if (DEBUG) {
+ System.out
+ .println("AbstractTracked.track[already adding]: " + item); //$NON-NLS-1$
+ }
+ return;
+ }
+ adding.add(item); /* mark this item is being added */
+ }
+ else { /* we are currently tracking this item */
+ if (DEBUG) {
+ System.out
+ .println("AbstractTracked.track[modified]: " + item); //$NON-NLS-1$
+ }
+ modified(); /* increment modification count */
+ }
+ }
+
+ if (object == null) { /* we are not tracking the item */
+ trackAdding(item, related);
+ }
+ else {
+ /* Call customizer outside of synchronized region */
+ customizerModified(item, related, object);
+ /*
+ * If the customizer throws an unchecked exception, it is safe to
+ * let it propagate
+ */
+ }
+ }
+
+ /**
+ * Common logic to add an item to the tracker used by track and
+ * trackInitial. The specified item must have been placed in the adding list
+ * before calling this method.
+ *
+ * @param item Item to be tracked.
+ * @param related Action related object.
+ */
+ private void trackAdding(final Object item, final Object related) {
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackAdding: " + item); //$NON-NLS-1$
+ }
+ Object object = null;
+ boolean becameUntracked = false;
+ /* Call customizer outside of synchronized region */
+ try {
+ object = customizerAdding(item, related);
+ /*
+ * If the customizer throws an unchecked exception, it will
+ * propagate after the finally
+ */
+ }
+ finally {
+ synchronized (this) {
+ if (adding.remove(item) && !closed) {
+ /*
+ * if the item was not untracked during the customizer
+ * callback
+ */
+ if (object != null) {
+ tracked.put(item, object);
+ modified(); /* increment modification count */
+ notifyAll(); /* notify any waiters */
+ }
+ }
+ else {
+ becameUntracked = true;
+ }
+ }
+ }
+ /*
+ * The item became untracked during the customizer callback.
+ */
+ if (becameUntracked && (object != null)) {
+ if (DEBUG) {
+ System.out
+ .println("AbstractTracked.trackAdding[removed]: " + item); //$NON-NLS-1$
+ }
+ /* Call customizer outside of synchronized region */
+ customizerRemoved(item, related, object);
+ /*
+ * If the customizer throws an unchecked exception, it is safe to
+ * let it propagate
+ */
+ }
+ }
+
+ /**
+ * Discontinue tracking the item.
+ *
+ * @param item Item to be untracked.
+ * @param related Action related object.
+ */
+ void untrack(final Object item, final Object related) {
+ final Object object;
+ synchronized (this) {
+ if (initial.remove(item)) { /*
+ * if this item is already in the list
+ * of initial references to process
+ */
+ if (DEBUG) {
+ System.out
+ .println("AbstractTracked.untrack[removed from initial]: " + item); //$NON-NLS-1$
+ }
+ return; /*
+ * we have removed it from the list and it will not be
+ * processed
+ */
+ }
+
+ if (adding.remove(item)) { /*
+ * if the item is in the process of
+ * being added
+ */
+ if (DEBUG) {
+ System.out
+ .println("AbstractTracked.untrack[being added]: " + item); //$NON-NLS-1$
+ }
+ return; /*
+ * in case the item is untracked while in the process of
+ * adding
+ */
+ }
+ object = tracked.remove(item); /*
+ * must remove from tracker before
+ * calling customizer callback
+ */
+ if (object == null) { /* are we actually tracking the item */
+ return;
+ }
+ modified(); /* increment modification count */
+ }
+ if (DEBUG) {
+ System.out.println("AbstractTracked.untrack[removed]: " + item); //$NON-NLS-1$
+ }
+ /* Call customizer outside of synchronized region */
+ customizerRemoved(item, related, object);
+ /*
+ * If the customizer throws an unchecked exception, it is safe to let it
+ * propagate
+ */
+ }
+
+ /**
+ * Returns the number of tracked items.
+ *
+ * @return The number of tracked items.
+ *
+ * @GuardedBy this
+ */
+ int size() {
+ return tracked.size();
+ }
+
+ /**
+ * Return the customized object for the specified item
+ *
+ * @param item The item to lookup in the map
+ * @return The customized object for the specified item.
+ *
+ * @GuardedBy this
+ */
+ Object getCustomizedObject(final Object item) {
+ return tracked.get(item);
+ }
+
+ /**
+ * Return the list of tracked items.
+ *
+ * @param list An array to contain the tracked items.
+ * @return The specified list if it is large enough to hold the tracked
+ * items or a new array large enough to hold the tracked items.
+ * @GuardedBy this
+ */
+ Object[] getTracked(final Object[] list) {
+ return tracked.keySet().toArray(list);
+ }
+
+ /**
+ * Increment the modification count. If this method is overridden, the
+ * overriding method MUST call this method to increment the tracking count.
+ *
+ * @GuardedBy this
+ */
+ void modified() {
+ trackingCount++;
+ }
+
+ /**
+ * Returns the tracking count for this <code>ServiceTracker</code> object.
+ *
+ * The tracking count is initialized to 0 when this object is opened. Every
+ * time an item is added, modified or removed from this object the tracking
+ * count is incremented.
+ *
+ * @GuardedBy this
+ * @return The tracking count for this object.
+ */
+ int getTrackingCount() {
+ return trackingCount;
+ }
+
+ /**
+ * Call the specific customizer adding method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Item to be tracked.
+ * @param related Action related object.
+ * @return Customized object for the tracked item or <code>null</code> if
+ * the item is not to be tracked.
+ */
+ abstract Object customizerAdding(final Object item, final Object related);
+
+ /**
+ * Call the specific customizer modified method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Tracked item.
+ * @param related Action related object.
+ * @param object Customized object for the tracked item.
+ */
+ abstract void customizerModified(final Object item, final Object related,
+ final Object object);
+
+ /**
+ * Call the specific customizer removed method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Tracked item.
+ * @param related Action related object.
+ * @param object Customized object for the tracked item.
+ */
+ abstract void customizerRemoved(final Object item, final Object related,
+ final Object object);
+}
diff --git a/framework/src/main/java/org/osgi/util/tracker/BundleTracker.java b/framework/src/main/java/org/osgi/util/tracker/BundleTracker.java
new file mode 100644
index 0000000..8791d98
--- /dev/null
+++ b/framework/src/main/java/org/osgi/util/tracker/BundleTracker.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) OSGi Alliance (2007, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.util.tracker;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.SynchronousBundleListener;
+
+/**
+ * The <code>BundleTracker</code> class simplifies tracking bundles much like
+ * the <code>ServiceTracker</code> simplifies tracking services.
+ * <p>
+ * A <code>BundleTracker</code> is constructed with state criteria and a
+ * <code>BundleTrackerCustomizer</code> object. A <code>BundleTracker</code> can
+ * use the <code>BundleTrackerCustomizer</code> to select which bundles are
+ * tracked and to create a customized object to be tracked with the bundle. The
+ * <code>BundleTracker</code> can then be opened to begin tracking all bundles
+ * whose state matches the specified state criteria.
+ * <p>
+ * The <code>getBundles</code> method can be called to get the
+ * <code>Bundle</code> objects of the bundles being tracked. The
+ * <code>getObject</code> method can be called to get the customized object for
+ * a tracked bundle.
+ * <p>
+ * The <code>BundleTracker</code> class is thread-safe. It does not call a
+ * <code>BundleTrackerCustomizer</code> while holding any locks.
+ * <code>BundleTrackerCustomizer</code> implementations must also be
+ * thread-safe.
+ *
+ * @ThreadSafe
+ * @version $Revision: 5894 $
+ * @since 1.4
+ */
+public class BundleTracker implements BundleTrackerCustomizer {
+ /* set this to true to compile in debug messages */
+ static final boolean DEBUG = false;
+
+ /**
+ * The Bundle Context used by this <code>BundleTracker</code>.
+ */
+ protected final BundleContext context;
+
+ /**
+ * The <code>BundleTrackerCustomizer</code> object for this tracker.
+ */
+ final BundleTrackerCustomizer customizer;
+
+ /**
+ * Tracked bundles: <code>Bundle</code> object -> customized Object and
+ * <code>BundleListener</code> object
+ */
+ private volatile Tracked tracked;
+
+ /**
+ * Accessor method for the current Tracked object. This method is only
+ * intended to be used by the unsynchronized methods which do not modify the
+ * tracked field.
+ *
+ * @return The current Tracked object.
+ */
+ private Tracked tracked() {
+ return tracked;
+ }
+
+ /**
+ * State mask for bundles being tracked. This field contains the ORed values
+ * of the bundle states being tracked.
+ */
+ final int mask;
+
+ /**
+ * Create a <code>BundleTracker</code> for bundles whose state is present in
+ * the specified state mask.
+ *
+ * <p>
+ * Bundles whose state is present on the specified state mask will be
+ * tracked by this <code>BundleTracker</code>.
+ *
+ * @param context The <code>BundleContext</code> against which the tracking
+ * is done.
+ * @param stateMask The bit mask of the <code>OR</code>ing of the bundle
+ * states to be tracked.
+ * @param customizer The customizer object to call when bundles are added,
+ * modified, or removed in this <code>BundleTracker</code>. If
+ * customizer is <code>null</code>, then this
+ * <code>BundleTracker</code> will be used as the
+ * <code>BundleTrackerCustomizer</code> and this
+ * <code>BundleTracker</code> will call the
+ * <code>BundleTrackerCustomizer</code> methods on itself.
+ * @see Bundle#getState()
+ */
+ public BundleTracker(BundleContext context, int stateMask,
+ BundleTrackerCustomizer customizer) {
+ this.context = context;
+ this.mask = stateMask;
+ this.customizer = (customizer == null) ? this : customizer;
+ }
+
+ /**
+ * Open this <code>BundleTracker</code> and begin tracking bundles.
+ *
+ * <p>
+ * Bundle which match the state criteria specified when this
+ * <code>BundleTracker</code> was created are now tracked by this
+ * <code>BundleTracker</code>.
+ *
+ * @throws java.lang.IllegalStateException If the <code>BundleContext</code>
+ * with which this <code>BundleTracker</code> was created is no
+ * longer valid.
+ * @throws java.lang.SecurityException If the caller and this class do not
+ * have the appropriate
+ * <code>AdminPermission[context bundle,LISTENER]</code>, and the
+ * Java Runtime Environment supports permissions.
+ */
+ public void open() {
+ final Tracked t;
+ synchronized (this) {
+ if (tracked != null) {
+ return;
+ }
+ if (DEBUG) {
+ System.out.println("BundleTracker.open"); //$NON-NLS-1$
+ }
+ t = new Tracked();
+ synchronized (t) {
+ context.addBundleListener(t);
+ Bundle[] bundles = context.getBundles();
+ if (bundles != null) {
+ int length = bundles.length;
+ for (int i = 0; i < length; i++) {
+ int state = bundles[i].getState();
+ if ((state & mask) == 0) {
+ /* null out bundles whose states are not interesting */
+ bundles[i] = null;
+ }
+ }
+ /* set tracked with the initial bundles */
+ t.setInitial(bundles);
+ }
+ }
+ tracked = t;
+ }
+ /* Call tracked outside of synchronized region */
+ t.trackInitial(); /* process the initial references */
+ }
+
+ /**
+ * Close this <code>BundleTracker</code>.
+ *
+ * <p>
+ * This method should be called when this <code>BundleTracker</code> should
+ * end the tracking of bundles.
+ *
+ * <p>
+ * This implementation calls {@link #getBundles()} to get the list of
+ * tracked bundles to remove.
+ */
+ public void close() {
+ final Bundle[] bundles;
+ final Tracked outgoing;
+ synchronized (this) {
+ outgoing = tracked;
+ if (outgoing == null) {
+ return;
+ }
+ if (DEBUG) {
+ System.out.println("BundleTracker.close"); //$NON-NLS-1$
+ }
+ outgoing.close();
+ bundles = getBundles();
+ tracked = null;
+ try {
+ context.removeBundleListener(outgoing);
+ }
+ catch (IllegalStateException e) {
+ /* In case the context was stopped. */
+ }
+ }
+ if (bundles != null) {
+ for (int i = 0; i < bundles.length; i++) {
+ outgoing.untrack(bundles[i], null);
+ }
+ }
+ }
+
+ /**
+ * Default implementation of the
+ * <code>BundleTrackerCustomizer.addingBundle</code> method.
+ *
+ * <p>
+ * This method is only called when this <code>BundleTracker</code> has been
+ * constructed with a <code>null BundleTrackerCustomizer</code> argument.
+ *
+ * <p>
+ * This implementation simply returns the specified <code>Bundle</code>.
+ *
+ * <p>
+ * This method can be overridden in a subclass to customize the object to be
+ * tracked for the bundle being added.
+ *
+ * @param bundle The <code>Bundle</code> being added to this
+ * <code>BundleTracker</code> object.
+ * @param event The bundle event which caused this customizer method to be
+ * called or <code>null</code> if there is no bundle event associated
+ * with the call to this method.
+ * @return The specified bundle.
+ * @see BundleTrackerCustomizer#addingBundle(Bundle, BundleEvent)
+ */
+ public Object addingBundle(Bundle bundle, BundleEvent event) {
+ return bundle;
+ }
+
+ /**
+ * Default implementation of the
+ * <code>BundleTrackerCustomizer.modifiedBundle</code> method.
+ *
+ * <p>
+ * This method is only called when this <code>BundleTracker</code> has been
+ * constructed with a <code>null BundleTrackerCustomizer</code> argument.
+ *
+ * <p>
+ * This implementation does nothing.
+ *
+ * @param bundle The <code>Bundle</code> whose state has been modified.
+ * @param event The bundle event which caused this customizer method to be
+ * called or <code>null</code> if there is no bundle event associated
+ * with the call to this method.
+ * @param object The customized object for the specified Bundle.
+ * @see BundleTrackerCustomizer#modifiedBundle(Bundle, BundleEvent, Object)
+ */
+ public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
+ /* do nothing */
+ }
+
+ /**
+ * Default implementation of the
+ * <code>BundleTrackerCustomizer.removedBundle</code> method.
+ *
+ * <p>
+ * This method is only called when this <code>BundleTracker</code> has been
+ * constructed with a <code>null BundleTrackerCustomizer</code> argument.
+ *
+ * <p>
+ * This implementation does nothing.
+ *
+ * @param bundle The <code>Bundle</code> being removed.
+ * @param event The bundle event which caused this customizer method to be
+ * called or <code>null</code> if there is no bundle event associated
+ * with the call to this method.
+ * @param object The customized object for the specified bundle.
+ * @see BundleTrackerCustomizer#removedBundle(Bundle, BundleEvent, Object)
+ */
+ public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
+ /* do nothing */
+ }
+
+ /**
+ * Return an array of <code>Bundle</code>s for all bundles being tracked by
+ * this <code>BundleTracker</code>.
+ *
+ * @return An array of <code>Bundle</code>s or <code>null</code> if no
+ * bundles are being tracked.
+ */
+ public Bundle[] getBundles() {
+ final Tracked t = tracked();
+ if (t == null) { /* if BundleTracker is not open */
+ return null;
+ }
+ synchronized (t) {
+ int length = t.size();
+ if (length == 0) {
+ return null;
+ }
+ return (Bundle[]) t.getTracked(new Bundle[length]);
+ }
+ }
+
+ /**
+ * Returns the customized object for the specified <code>Bundle</code> if
+ * the specified bundle is being tracked by this <code>BundleTracker</code>.
+ *
+ * @param bundle The <code>Bundle</code> being tracked.
+ * @return The customized object for the specified <code>Bundle</code> or
+ * <code>null</code> if the specified <code>Bundle</code> is not
+ * being tracked.
+ */
+ public Object getObject(Bundle bundle) {
+ final Tracked t = tracked();
+ if (t == null) { /* if BundleTracker is not open */
+ return null;
+ }
+ synchronized (t) {
+ return t.getCustomizedObject(bundle);
+ }
+ }
+
+ /**
+ * Remove a bundle from this <code>BundleTracker</code>.
+ *
+ * The specified bundle will be removed from this <code>BundleTracker</code>
+ * . If the specified bundle was being tracked then the
+ * <code>BundleTrackerCustomizer.removedBundle</code> method will be called
+ * for that bundle.
+ *
+ * @param bundle The <code>Bundle</code> to be removed.
+ */
+ public void remove(Bundle bundle) {
+ final Tracked t = tracked();
+ if (t == null) { /* if BundleTracker is not open */
+ return;
+ }
+ t.untrack(bundle, null);
+ }
+
+ /**
+ * Return the number of bundles being tracked by this
+ * <code>BundleTracker</code>.
+ *
+ * @return The number of bundles being tracked.
+ */
+ public int size() {
+ final Tracked t = tracked();
+ if (t == null) { /* if BundleTracker is not open */
+ return 0;
+ }
+ synchronized (t) {
+ return t.size();
+ }
+ }
+
+ /**
+ * Returns the tracking count for this <code>BundleTracker</code>.
+ *
+ * The tracking count is initialized to 0 when this
+ * <code>BundleTracker</code> is opened. Every time a bundle is added,
+ * modified or removed from this <code>BundleTracker</code> the tracking
+ * count is incremented.
+ *
+ * <p>
+ * The tracking count can be used to determine if this
+ * <code>BundleTracker</code> has added, modified or removed a bundle by
+ * comparing a tracking count value previously collected with the current
+ * tracking count value. If the value has not changed, then no bundle has
+ * been added, modified or removed from this <code>BundleTracker</code>
+ * since the previous tracking count was collected.
+ *
+ * @return The tracking count for this <code>BundleTracker</code> or -1 if
+ * this <code>BundleTracker</code> is not open.
+ */
+ public int getTrackingCount() {
+ final Tracked t = tracked();
+ if (t == null) { /* if BundleTracker is not open */
+ return -1;
+ }
+ synchronized (t) {
+ return t.getTrackingCount();
+ }
+ }
+
+ /**
+ * Inner class which subclasses AbstractTracked. This class is the
+ * <code>SynchronousBundleListener</code> object for the tracker.
+ *
+ * @ThreadSafe
+ * @since 1.4
+ */
+ class Tracked extends AbstractTracked implements SynchronousBundleListener {
+ /**
+ * Tracked constructor.
+ */
+ Tracked() {
+ super();
+ }
+
+ /**
+ * <code>BundleListener</code> method for the <code>BundleTracker</code>
+ * class. This method must NOT be synchronized to avoid deadlock
+ * potential.
+ *
+ * @param event <code>BundleEvent</code> object from the framework.
+ */
+ public void bundleChanged(final BundleEvent event) {
+ /*
+ * Check if we had a delayed call (which could happen when we
+ * close).
+ */
+ if (closed) {
+ return;
+ }
+ final Bundle bundle = event.getBundle();
+ final int state = bundle.getState();
+ if (DEBUG) {
+ System.out
+ .println("BundleTracker.Tracked.bundleChanged[" + state + "]: " + bundle); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if ((state & mask) != 0) {
+ track(bundle, event);
+ /*
+ * If the customizer throws an unchecked exception, it is safe
+ * to let it propagate
+ */
+ }
+ else {
+ untrack(bundle, event);
+ /*
+ * If the customizer throws an unchecked exception, it is safe
+ * to let it propagate
+ */
+ }
+ }
+
+ /**
+ * Call the specific customizer adding method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Item to be tracked.
+ * @param related Action related object.
+ * @return Customized object for the tracked item or <code>null</code>
+ * if the item is not to be tracked.
+ */
+ Object customizerAdding(final Object item,
+ final Object related) {
+ return customizer
+ .addingBundle((Bundle) item, (BundleEvent) related);
+ }
+
+ /**
+ * Call the specific customizer modified method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Tracked item.
+ * @param related Action related object.
+ * @param object Customized object for the tracked item.
+ */
+ void customizerModified(final Object item,
+ final Object related, final Object object) {
+ customizer.modifiedBundle((Bundle) item, (BundleEvent) related,
+ object);
+ }
+
+ /**
+ * Call the specific customizer removed method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Tracked item.
+ * @param related Action related object.
+ * @param object Customized object for the tracked item.
+ */
+ void customizerRemoved(final Object item,
+ final Object related, final Object object) {
+ customizer.removedBundle((Bundle) item, (BundleEvent) related,
+ object);
+ }
+ }
+}
diff --git a/framework/src/main/java/org/osgi/util/tracker/BundleTrackerCustomizer.java b/framework/src/main/java/org/osgi/util/tracker/BundleTrackerCustomizer.java
new file mode 100644
index 0000000..100c6b4
--- /dev/null
+++ b/framework/src/main/java/org/osgi/util/tracker/BundleTrackerCustomizer.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) OSGi Alliance (2007, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.util.tracker;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+
+/**
+ * The <code>BundleTrackerCustomizer</code> interface allows a
+ * <code>BundleTracker</code> to customize the <code>Bundle</code>s that are
+ * tracked. A <code>BundleTrackerCustomizer</code> is called when a bundle is
+ * being added to a <code>BundleTracker</code>. The
+ * <code>BundleTrackerCustomizer</code> can then return an object for the
+ * tracked bundle. A <code>BundleTrackerCustomizer</code> is also called when a
+ * tracked bundle is modified or has been removed from a
+ * <code>BundleTracker</code>.
+ *
+ * <p>
+ * The methods in this interface may be called as the result of a
+ * <code>BundleEvent</code> being received by a <code>BundleTracker</code>.
+ * Since <code>BundleEvent</code>s are received synchronously by the
+ * <code>BundleTracker</code>, it is highly recommended that implementations of
+ * these methods do not alter bundle states while being synchronized on any
+ * object.
+ *
+ * <p>
+ * The <code>BundleTracker</code> class is thread-safe. It does not call a
+ * <code>BundleTrackerCustomizer</code> while holding any locks.
+ * <code>BundleTrackerCustomizer</code> implementations must also be
+ * thread-safe.
+ *
+ * @ThreadSafe
+ * @version $Revision: 5874 $
+ * @since 1.4
+ */
+public interface BundleTrackerCustomizer {
+ /**
+ * A bundle is being added to the <code>BundleTracker</code>.
+ *
+ * <p>
+ * This method is called before a bundle which matched the search parameters
+ * of the <code>BundleTracker</code> is added to the
+ * <code>BundleTracker</code>. This method should return the object to be
+ * tracked for the specified <code>Bundle</code>. The returned object is
+ * stored in the <code>BundleTracker</code> and is available from the
+ * {@link BundleTracker#getObject(Bundle) getObject} method.
+ *
+ * @param bundle The <code>Bundle</code> being added to the
+ * <code>BundleTracker</code>.
+ * @param event The bundle event which caused this customizer method to be
+ * called or <code>null</code> if there is no bundle event associated
+ * with the call to this method.
+ * @return The object to be tracked for the specified <code>Bundle</code>
+ * object or <code>null</code> if the specified <code>Bundle</code>
+ * object should not be tracked.
+ */
+ public Object addingBundle(Bundle bundle, BundleEvent event);
+
+ /**
+ * A bundle tracked by the <code>BundleTracker</code> has been modified.
+ *
+ * <p>
+ * This method is called when a bundle being tracked by the
+ * <code>BundleTracker</code> has had its state modified.
+ *
+ * @param bundle The <code>Bundle</code> whose state has been modified.
+ * @param event The bundle event which caused this customizer method to be
+ * called or <code>null</code> if there is no bundle event associated
+ * with the call to this method.
+ * @param object The tracked object for the specified bundle.
+ */
+ public void modifiedBundle(Bundle bundle, BundleEvent event,
+ Object object);
+
+ /**
+ * A bundle tracked by the <code>BundleTracker</code> has been removed.
+ *
+ * <p>
+ * This method is called after a bundle is no longer being tracked by the
+ * <code>BundleTracker</code>.
+ *
+ * @param bundle The <code>Bundle</code> that has been removed.
+ * @param event The bundle event which caused this customizer method to be
+ * called or <code>null</code> if there is no bundle event associated
+ * with the call to this method.
+ * @param object The tracked object for the specified bundle.
+ */
+ public void removedBundle(Bundle bundle, BundleEvent event,
+ Object object);
+}
diff --git a/framework/src/main/java/org/osgi/util/tracker/ServiceTracker.java b/framework/src/main/java/org/osgi/util/tracker/ServiceTracker.java
new file mode 100644
index 0000000..b4e373b
--- /dev/null
+++ b/framework/src/main/java/org/osgi/util/tracker/ServiceTracker.java
@@ -0,0 +1,941 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.util.tracker;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.osgi.framework.AllServiceListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+
+/**
+ * The <code>ServiceTracker</code> class simplifies using services from the
+ * Framework's service registry.
+ * <p>
+ * A <code>ServiceTracker</code> object is constructed with search criteria and
+ * a <code>ServiceTrackerCustomizer</code> object. A <code>ServiceTracker</code>
+ * can use a <code>ServiceTrackerCustomizer</code> to customize the service
+ * objects to be tracked. The <code>ServiceTracker</code> can then be opened to
+ * begin tracking all services in the Framework's service registry that match
+ * the specified search criteria. The <code>ServiceTracker</code> correctly
+ * handles all of the details of listening to <code>ServiceEvent</code>s and
+ * getting and ungetting services.
+ * <p>
+ * The <code>getServiceReferences</code> method can be called to get references
+ * to the services being tracked. The <code>getService</code> and
+ * <code>getServices</code> methods can be called to get the service objects for
+ * the tracked service.
+ * <p>
+ * The <code>ServiceTracker</code> class is thread-safe. It does not call a
+ * <code>ServiceTrackerCustomizer</code> while holding any locks.
+ * <code>ServiceTrackerCustomizer</code> implementations must also be
+ * thread-safe.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6386 $
+ */
+public class ServiceTracker implements ServiceTrackerCustomizer {
+ /* set this to true to compile in debug messages */
+ static final boolean DEBUG = false;
+ /**
+ * The Bundle Context used by this <code>ServiceTracker</code>.
+ */
+ protected final BundleContext context;
+ /**
+ * The Filter used by this <code>ServiceTracker</code> which specifies the
+ * search criteria for the services to track.
+ *
+ * @since 1.1
+ */
+ protected final Filter filter;
+ /**
+ * The <code>ServiceTrackerCustomizer</code> for this tracker.
+ */
+ final ServiceTrackerCustomizer customizer;
+ /**
+ * Filter string for use when adding the ServiceListener. If this field is
+ * set, then certain optimizations can be taken since we don't have a user
+ * supplied filter.
+ */
+ final String listenerFilter;
+ /**
+ * Class name to be tracked. If this field is set, then we are tracking by
+ * class name.
+ */
+ private final String trackClass;
+ /**
+ * Reference to be tracked. If this field is set, then we are tracking a
+ * single ServiceReference.
+ */
+ private final ServiceReference trackReference;
+ /**
+ * Tracked services: <code>ServiceReference</code> -> customized Object and
+ * <code>ServiceListener</code> object
+ */
+ private volatile Tracked tracked;
+
+ /**
+ * Accessor method for the current Tracked object. This method is only
+ * intended to be used by the unsynchronized methods which do not modify the
+ * tracked field.
+ *
+ * @return The current Tracked object.
+ */
+ private Tracked tracked() {
+ return tracked;
+ }
+
+ /**
+ * Cached ServiceReference for getServiceReference.
+ *
+ * This field is volatile since it is accessed by multiple threads.
+ */
+ private volatile ServiceReference cachedReference;
+ /**
+ * Cached service object for getService.
+ *
+ * This field is volatile since it is accessed by multiple threads.
+ */
+ private volatile Object cachedService;
+
+ /**
+ * org.osgi.framework package version which introduced
+ * {@link ServiceEvent#MODIFIED_ENDMATCH}
+ */
+ private static final Version endMatchVersion = new Version(1, 5, 0);
+
+ /**
+ * Create a <code>ServiceTracker</code> on the specified
+ * <code>ServiceReference</code>.
+ *
+ * <p>
+ * The service referenced by the specified <code>ServiceReference</code>
+ * will be tracked by this <code>ServiceTracker</code>.
+ *
+ * @param context The <code>BundleContext</code> against which the tracking
+ * is done.
+ * @param reference The <code>ServiceReference</code> for the service to be
+ * tracked.
+ * @param customizer The customizer object to call when services are added,
+ * modified, or removed in this <code>ServiceTracker</code>. If
+ * customizer is <code>null</code>, then this
+ * <code>ServiceTracker</code> will be used as the
+ * <code>ServiceTrackerCustomizer</code> and this
+ * <code>ServiceTracker</code> will call the
+ * <code>ServiceTrackerCustomizer</code> methods on itself.
+ */
+ public ServiceTracker(final BundleContext context,
+ final ServiceReference reference,
+ final ServiceTrackerCustomizer customizer) {
+ this.context = context;
+ this.trackReference = reference;
+ this.trackClass = null;
+ this.customizer = (customizer == null) ? this : customizer;
+ this.listenerFilter = "(" + Constants.SERVICE_ID + "="
+ + reference.getProperty(Constants.SERVICE_ID).toString() + ")";
+ try {
+ this.filter = context.createFilter(listenerFilter);
+ }
+ catch (InvalidSyntaxException e) {
+ /*
+ * we could only get this exception if the ServiceReference was
+ * invalid
+ */
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "unexpected InvalidSyntaxException: " + e.getMessage());
+ iae.initCause(e);
+ throw iae;
+ }
+ }
+
+ /**
+ * Create a <code>ServiceTracker</code> on the specified class name.
+ *
+ * <p>
+ * Services registered under the specified class name will be tracked by
+ * this <code>ServiceTracker</code>.
+ *
+ * @param context The <code>BundleContext</code> against which the tracking
+ * is done.
+ * @param clazz The class name of the services to be tracked.
+ * @param customizer The customizer object to call when services are added,
+ * modified, or removed in this <code>ServiceTracker</code>. If
+ * customizer is <code>null</code>, then this
+ * <code>ServiceTracker</code> will be used as the
+ * <code>ServiceTrackerCustomizer</code> and this
+ * <code>ServiceTracker</code> will call the
+ * <code>ServiceTrackerCustomizer</code> methods on itself.
+ */
+ public ServiceTracker(final BundleContext context, final String clazz,
+ final ServiceTrackerCustomizer customizer) {
+ this.context = context;
+ this.trackReference = null;
+ this.trackClass = clazz;
+ this.customizer = (customizer == null) ? this : customizer;
+ // we call clazz.toString to verify clazz is non-null!
+ this.listenerFilter = "(" + Constants.OBJECTCLASS + "="
+ + clazz.toString() + ")";
+ try {
+ this.filter = context.createFilter(listenerFilter);
+ }
+ catch (InvalidSyntaxException e) {
+ /*
+ * we could only get this exception if the clazz argument was
+ * malformed
+ */
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "unexpected InvalidSyntaxException: " + e.getMessage());
+ iae.initCause(e);
+ throw iae;
+ }
+ }
+
+ /**
+ * Create a <code>ServiceTracker</code> on the specified <code>Filter</code>
+ * object.
+ *
+ * <p>
+ * Services which match the specified <code>Filter</code> object will be
+ * tracked by this <code>ServiceTracker</code>.
+ *
+ * @param context The <code>BundleContext</code> against which the tracking
+ * is done.
+ * @param filter The <code>Filter</code> to select the services to be
+ * tracked.
+ * @param customizer The customizer object to call when services are added,
+ * modified, or removed in this <code>ServiceTracker</code>. If
+ * customizer is null, then this <code>ServiceTracker</code> will be
+ * used as the <code>ServiceTrackerCustomizer</code> and this
+ * <code>ServiceTracker</code> will call the
+ * <code>ServiceTrackerCustomizer</code> methods on itself.
+ * @since 1.1
+ */
+ public ServiceTracker(final BundleContext context, final Filter filter,
+ final ServiceTrackerCustomizer customizer) {
+ this.context = context;
+ this.trackReference = null;
+ this.trackClass = null;
+ final Version frameworkVersion = (Version) AccessController
+ .doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ String version = context
+ .getProperty(Constants.FRAMEWORK_VERSION);
+ return (version == null) ? Version.emptyVersion
+ : new Version(version);
+ }
+ });
+ final boolean endMatchSupported = (frameworkVersion
+ .compareTo(endMatchVersion) >= 0);
+ this.listenerFilter = endMatchSupported ? filter.toString() : null;
+ this.filter = filter;
+ this.customizer = (customizer == null) ? this : customizer;
+ if ((context == null) || (filter == null)) {
+ /*
+ * we throw a NPE here to be consistent with the other constructors
+ */
+ throw new NullPointerException();
+ }
+ }
+
+ /**
+ * Open this <code>ServiceTracker</code> and begin tracking services.
+ *
+ * <p>
+ * This implementation calls <code>open(false)</code>.
+ *
+ * @throws java.lang.IllegalStateException If the <code>BundleContext</code>
+ * with which this <code>ServiceTracker</code> was created is no
+ * longer valid.
+ * @see #open(boolean)
+ */
+ public void open() {
+ open(false);
+ }
+
+ /**
+ * Open this <code>ServiceTracker</code> and begin tracking services.
+ *
+ * <p>
+ * Services which match the search criteria specified when this
+ * <code>ServiceTracker</code> was created are now tracked by this
+ * <code>ServiceTracker</code>.
+ *
+ * @param trackAllServices If <code>true</code>, then this
+ * <code>ServiceTracker</code> will track all matching services
+ * regardless of class loader accessibility. If <code>false</code>,
+ * then this <code>ServiceTracker</code> will only track matching
+ * services which are class loader accessible to the bundle whose
+ * <code>BundleContext</code> is used by this
+ * <code>ServiceTracker</code>.
+ * @throws java.lang.IllegalStateException If the <code>BundleContext</code>
+ * with which this <code>ServiceTracker</code> was created is no
+ * longer valid.
+ * @since 1.3
+ */
+ public void open(boolean trackAllServices) {
+ final Tracked t;
+ synchronized (this) {
+ if (tracked != null) {
+ return;
+ }
+ if (DEBUG) {
+ System.out.println("ServiceTracker.open: " + filter);
+ }
+ t = trackAllServices ? new AllTracked() : new Tracked();
+ synchronized (t) {
+ try {
+ context.addServiceListener(t, listenerFilter);
+ ServiceReference[] references = null;
+ if (trackClass != null) {
+ references = getInitialReferences(trackAllServices,
+ trackClass, null);
+ }
+ else {
+ if (trackReference != null) {
+ if (trackReference.getBundle() != null) {
+ references = new ServiceReference[] {trackReference};
+ }
+ }
+ else { /* user supplied filter */
+ references = getInitialReferences(trackAllServices,
+ null,
+ (listenerFilter != null) ? listenerFilter
+ : filter.toString());
+ }
+ }
+ /* set tracked with the initial references */
+ t.setInitial(references);
+ }
+ catch (InvalidSyntaxException e) {
+ throw new RuntimeException(
+ "unexpected InvalidSyntaxException: "
+ + e.getMessage(), e);
+ }
+ }
+ tracked = t;
+ }
+ /* Call tracked outside of synchronized region */
+ t.trackInitial(); /* process the initial references */
+ }
+
+ /**
+ * Returns the list of initial <code>ServiceReference</code>s that will be
+ * tracked by this <code>ServiceTracker</code>.
+ *
+ * @param trackAllServices If <code>true</code>, use
+ * <code>getAllServiceReferences</code>.
+ * @param className The class name with which the service was registered, or
+ * <code>null</code> for all services.
+ * @param filterString The filter criteria or <code>null</code> for all
+ * services.
+ * @return The list of initial <code>ServiceReference</code>s.
+ * @throws InvalidSyntaxException If the specified filterString has an
+ * invalid syntax.
+ */
+ private ServiceReference[] getInitialReferences(boolean trackAllServices,
+ String className, String filterString)
+ throws InvalidSyntaxException {
+ if (trackAllServices) {
+ return context.getAllServiceReferences(className, filterString);
+ }
+ return context.getServiceReferences(className, filterString);
+ }
+
+ /**
+ * Close this <code>ServiceTracker</code>.
+ *
+ * <p>
+ * This method should be called when this <code>ServiceTracker</code> should
+ * end the tracking of services.
+ *
+ * <p>
+ * This implementation calls {@link #getServiceReferences()} to get the list
+ * of tracked services to remove.
+ */
+ public void close() {
+ final Tracked outgoing;
+ final ServiceReference[] references;
+ synchronized (this) {
+ outgoing = tracked;
+ if (outgoing == null) {
+ return;
+ }
+ if (DEBUG) {
+ System.out.println("ServiceTracker.close: " + filter);
+ }
+ outgoing.close();
+ references = getServiceReferences();
+ tracked = null;
+ try {
+ context.removeServiceListener(outgoing);
+ }
+ catch (IllegalStateException e) {
+ /* In case the context was stopped. */
+ }
+ }
+ modified(); /* clear the cache */
+ synchronized (outgoing) {
+ outgoing.notifyAll(); /* wake up any waiters */
+ }
+ if (references != null) {
+ for (int i = 0; i < references.length; i++) {
+ outgoing.untrack(references[i], null);
+ }
+ }
+ if (DEBUG) {
+ if ((cachedReference == null) && (cachedService == null)) {
+ System.out
+ .println("ServiceTracker.close[cached cleared]: "
+ + filter);
+ }
+ }
+ }
+
+ /**
+ * Default implementation of the
+ * <code>ServiceTrackerCustomizer.addingService</code> method.
+ *
+ * <p>
+ * This method is only called when this <code>ServiceTracker</code> has been
+ * constructed with a <code>null ServiceTrackerCustomizer</code> argument.
+ *
+ * <p>
+ * This implementation returns the result of calling <code>getService</code>
+ * on the <code>BundleContext</code> with which this
+ * <code>ServiceTracker</code> was created passing the specified
+ * <code>ServiceReference</code>.
+ * <p>
+ * This method can be overridden in a subclass to customize the service
+ * object to be tracked for the service being added. In that case, take care
+ * not to rely on the default implementation of
+ * {@link #removedService(ServiceReference, Object) removedService} to unget
+ * the service.
+ *
+ * @param reference The reference to the service being added to this
+ * <code>ServiceTracker</code>.
+ * @return The service object to be tracked for the service added to this
+ * <code>ServiceTracker</code>.
+ * @see ServiceTrackerCustomizer#addingService(ServiceReference)
+ */
+ public Object addingService(ServiceReference reference) {
+ return context.getService(reference);
+ }
+
+ /**
+ * Default implementation of the
+ * <code>ServiceTrackerCustomizer.modifiedService</code> method.
+ *
+ * <p>
+ * This method is only called when this <code>ServiceTracker</code> has been
+ * constructed with a <code>null ServiceTrackerCustomizer</code> argument.
+ *
+ * <p>
+ * This implementation does nothing.
+ *
+ * @param reference The reference to modified service.
+ * @param service The service object for the modified service.
+ * @see ServiceTrackerCustomizer#modifiedService(ServiceReference, Object)
+ */
+ public void modifiedService(ServiceReference reference, Object service) {
+ /* do nothing */
+ }
+
+ /**
+ * Default implementation of the
+ * <code>ServiceTrackerCustomizer.removedService</code> method.
+ *
+ * <p>
+ * This method is only called when this <code>ServiceTracker</code> has been
+ * constructed with a <code>null ServiceTrackerCustomizer</code> argument.
+ *
+ * <p>
+ * This implementation calls <code>ungetService</code>, on the
+ * <code>BundleContext</code> with which this <code>ServiceTracker</code>
+ * was created, passing the specified <code>ServiceReference</code>.
+ * <p>
+ * This method can be overridden in a subclass. If the default
+ * implementation of {@link #addingService(ServiceReference) addingService}
+ * method was used, this method must unget the service.
+ *
+ * @param reference The reference to removed service.
+ * @param service The service object for the removed service.
+ * @see ServiceTrackerCustomizer#removedService(ServiceReference, Object)
+ */
+ public void removedService(ServiceReference reference, Object service) {
+ context.ungetService(reference);
+ }
+
+ /**
+ * Wait for at least one service to be tracked by this
+ * <code>ServiceTracker</code>. This method will also return when this
+ * <code>ServiceTracker</code> is closed.
+ *
+ * <p>
+ * It is strongly recommended that <code>waitForService</code> is not used
+ * during the calling of the <code>BundleActivator</code> methods.
+ * <code>BundleActivator</code> methods are expected to complete in a short
+ * period of time.
+ *
+ * <p>
+ * This implementation calls {@link #getService()} to determine if a service
+ * is being tracked.
+ *
+ * @param timeout The time interval in milliseconds to wait. If zero, the
+ * method will wait indefinitely.
+ * @return Returns the result of {@link #getService()}.
+ * @throws InterruptedException If another thread has interrupted the
+ * current thread.
+ * @throws IllegalArgumentException If the value of timeout is negative.
+ */
+ public Object waitForService(long timeout) throws InterruptedException {
+ if (timeout < 0) {
+ throw new IllegalArgumentException("timeout value is negative");
+ }
+ Object object = getService();
+ while (object == null) {
+ final Tracked t = tracked();
+ if (t == null) { /* if ServiceTracker is not open */
+ return null;
+ }
+ synchronized (t) {
+ if (t.size() == 0) {
+ t.wait(timeout);
+ }
+ }
+ object = getService();
+ if (timeout > 0) {
+ return object;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * Return an array of <code>ServiceReference</code>s for all services being
+ * tracked by this <code>ServiceTracker</code>.
+ *
+ * @return Array of <code>ServiceReference</code>s or <code>null</code> if
+ * no services are being tracked.
+ */
+ public ServiceReference[] getServiceReferences() {
+ final Tracked t = tracked();
+ if (t == null) { /* if ServiceTracker is not open */
+ return null;
+ }
+ synchronized (t) {
+ int length = t.size();
+ if (length == 0) {
+ return null;
+ }
+ return (ServiceReference[]) t
+ .getTracked(new ServiceReference[length]);
+ }
+ }
+
+ /**
+ * Returns a <code>ServiceReference</code> for one of the services being
+ * tracked by this <code>ServiceTracker</code>.
+ *
+ * <p>
+ * If multiple services are being tracked, the service with the highest
+ * ranking (as specified in its <code>service.ranking</code> property) is
+ * returned. If there is a tie in ranking, the service with the lowest
+ * service ID (as specified in its <code>service.id</code> property); that
+ * is, the service that was registered first is returned. This is the same
+ * algorithm used by <code>BundleContext.getServiceReference</code>.
+ *
+ * <p>
+ * This implementation calls {@link #getServiceReferences()} to get the list
+ * of references for the tracked services.
+ *
+ * @return A <code>ServiceReference</code> or <code>null</code> if no
+ * services are being tracked.
+ * @since 1.1
+ */
+ public ServiceReference getServiceReference() {
+ ServiceReference reference = cachedReference;
+ if (reference != null) {
+ if (DEBUG) {
+ System.out
+ .println("ServiceTracker.getServiceReference[cached]: "
+ + filter);
+ }
+ return reference;
+ }
+ if (DEBUG) {
+ System.out.println("ServiceTracker.getServiceReference: " + filter);
+ }
+ ServiceReference[] references = getServiceReferences();
+ int length = (references == null) ? 0 : references.length;
+ if (length == 0) { /* if no service is being tracked */
+ return null;
+ }
+ int index = 0;
+ if (length > 1) { /* if more than one service, select highest ranking */
+ int rankings[] = new int[length];
+ int count = 0;
+ int maxRanking = Integer.MIN_VALUE;
+ for (int i = 0; i < length; i++) {
+ Object property = references[i]
+ .getProperty(Constants.SERVICE_RANKING);
+ int ranking = (property instanceof Integer) ? ((Integer) property)
+ .intValue()
+ : 0;
+ rankings[i] = ranking;
+ if (ranking > maxRanking) {
+ index = i;
+ maxRanking = ranking;
+ count = 1;
+ }
+ else {
+ if (ranking == maxRanking) {
+ count++;
+ }
+ }
+ }
+ if (count > 1) { /* if still more than one service, select lowest id */
+ long minId = Long.MAX_VALUE;
+ for (int i = 0; i < length; i++) {
+ if (rankings[i] == maxRanking) {
+ long id = ((Long) (references[i]
+ .getProperty(Constants.SERVICE_ID)))
+ .longValue();
+ if (id < minId) {
+ index = i;
+ minId = id;
+ }
+ }
+ }
+ }
+ }
+ return cachedReference = references[index];
+ }
+
+ /**
+ * Returns the service object for the specified
+ * <code>ServiceReference</code> if the specified referenced service is
+ * being tracked by this <code>ServiceTracker</code>.
+ *
+ * @param reference The reference to the desired service.
+ * @return A service object or <code>null</code> if the service referenced
+ * by the specified <code>ServiceReference</code> is not being
+ * tracked.
+ */
+ public Object getService(ServiceReference reference) {
+ final Tracked t = tracked();
+ if (t == null) { /* if ServiceTracker is not open */
+ return null;
+ }
+ synchronized (t) {
+ return t.getCustomizedObject(reference);
+ }
+ }
+
+ /**
+ * Return an array of service objects for all services being tracked by this
+ * <code>ServiceTracker</code>.
+ *
+ * <p>
+ * This implementation calls {@link #getServiceReferences()} to get the list
+ * of references for the tracked services and then calls
+ * {@link #getService(ServiceReference)} for each reference to get the
+ * tracked service object.
+ *
+ * @return An array of service objects or <code>null</code> if no services
+ * are being tracked.
+ */
+ public Object[] getServices() {
+ final Tracked t = tracked();
+ if (t == null) { /* if ServiceTracker is not open */
+ return null;
+ }
+ synchronized (t) {
+ ServiceReference[] references = getServiceReferences();
+ int length = (references == null) ? 0 : references.length;
+ if (length == 0) {
+ return null;
+ }
+ Object[] objects = new Object[length];
+ for (int i = 0; i < length; i++) {
+ objects[i] = getService(references[i]);
+ }
+ return objects;
+ }
+ }
+
+ /**
+ * Returns a service object for one of the services being tracked by this
+ * <code>ServiceTracker</code>.
+ *
+ * <p>
+ * If any services are being tracked, this implementation returns the result
+ * of calling <code>getService(getServiceReference())</code>.
+ *
+ * @return A service object or <code>null</code> if no services are being
+ * tracked.
+ */
+ public Object getService() {
+ Object service = cachedService;
+ if (service != null) {
+ if (DEBUG) {
+ System.out
+ .println("ServiceTracker.getService[cached]: "
+ + filter);
+ }
+ return service;
+ }
+ if (DEBUG) {
+ System.out.println("ServiceTracker.getService: " + filter);
+ }
+ ServiceReference reference = getServiceReference();
+ if (reference == null) {
+ return null;
+ }
+ return cachedService = getService(reference);
+ }
+
+ /**
+ * Remove a service from this <code>ServiceTracker</code>.
+ *
+ * The specified service will be removed from this
+ * <code>ServiceTracker</code>. If the specified service was being tracked
+ * then the <code>ServiceTrackerCustomizer.removedService</code> method will
+ * be called for that service.
+ *
+ * @param reference The reference to the service to be removed.
+ */
+ public void remove(ServiceReference reference) {
+ final Tracked t = tracked();
+ if (t == null) { /* if ServiceTracker is not open */
+ return;
+ }
+ t.untrack(reference, null);
+ }
+
+ /**
+ * Return the number of services being tracked by this
+ * <code>ServiceTracker</code>.
+ *
+ * @return The number of services being tracked.
+ */
+ public int size() {
+ final Tracked t = tracked();
+ if (t == null) { /* if ServiceTracker is not open */
+ return 0;
+ }
+ synchronized (t) {
+ return t.size();
+ }
+ }
+
+ /**
+ * Returns the tracking count for this <code>ServiceTracker</code>.
+ *
+ * The tracking count is initialized to 0 when this
+ * <code>ServiceTracker</code> is opened. Every time a service is added,
+ * modified or removed from this <code>ServiceTracker</code>, the tracking
+ * count is incremented.
+ *
+ * <p>
+ * The tracking count can be used to determine if this
+ * <code>ServiceTracker</code> has added, modified or removed a service by
+ * comparing a tracking count value previously collected with the current
+ * tracking count value. If the value has not changed, then no service has
+ * been added, modified or removed from this <code>ServiceTracker</code>
+ * since the previous tracking count was collected.
+ *
+ * @since 1.2
+ * @return The tracking count for this <code>ServiceTracker</code> or -1 if
+ * this <code>ServiceTracker</code> is not open.
+ */
+ public int getTrackingCount() {
+ final Tracked t = tracked();
+ if (t == null) { /* if ServiceTracker is not open */
+ return -1;
+ }
+ synchronized (t) {
+ return t.getTrackingCount();
+ }
+ }
+
+ /**
+ * Called by the Tracked object whenever the set of tracked services is
+ * modified. Clears the cache.
+ */
+ /*
+ * This method must not be synchronized since it is called by Tracked while
+ * Tracked is synchronized. We don't want synchronization interactions
+ * between the listener thread and the user thread.
+ */
+ void modified() {
+ cachedReference = null; /* clear cached value */
+ cachedService = null; /* clear cached value */
+ if (DEBUG) {
+ System.out.println("ServiceTracker.modified: " + filter);
+ }
+ }
+
+ /**
+ * Inner class which subclasses AbstractTracked. This class is the
+ * <code>ServiceListener</code> object for the tracker.
+ *
+ * @ThreadSafe
+ */
+ class Tracked extends AbstractTracked implements ServiceListener {
+ /**
+ * Tracked constructor.
+ */
+ Tracked() {
+ super();
+ }
+
+ /**
+ * <code>ServiceListener</code> method for the
+ * <code>ServiceTracker</code> class. This method must NOT be
+ * synchronized to avoid deadlock potential.
+ *
+ * @param event <code>ServiceEvent</code> object from the framework.
+ */
+ public void serviceChanged(final ServiceEvent event) {
+ /*
+ * Check if we had a delayed call (which could happen when we
+ * close).
+ */
+ if (closed) {
+ return;
+ }
+ final ServiceReference reference = event.getServiceReference();
+ if (DEBUG) {
+ System.out
+ .println("ServiceTracker.Tracked.serviceChanged["
+ + event.getType() + "]: " + reference);
+ }
+
+ switch (event.getType()) {
+ case ServiceEvent.REGISTERED :
+ case ServiceEvent.MODIFIED :
+ if (listenerFilter != null) { // service listener added with
+ // filter
+ track(reference, event);
+ /*
+ * If the customizer throws an unchecked exception, it
+ * is safe to let it propagate
+ */
+ }
+ else { // service listener added without filter
+ if (filter.match(reference)) {
+ track(reference, event);
+ /*
+ * If the customizer throws an unchecked exception,
+ * it is safe to let it propagate
+ */
+ }
+ else {
+ untrack(reference, event);
+ /*
+ * If the customizer throws an unchecked exception,
+ * it is safe to let it propagate
+ */
+ }
+ }
+ break;
+ case ServiceEvent.MODIFIED_ENDMATCH :
+ case ServiceEvent.UNREGISTERING :
+ untrack(reference, event);
+ /*
+ * If the customizer throws an unchecked exception, it is
+ * safe to let it propagate
+ */
+ break;
+ }
+ }
+
+ /**
+ * Increment the tracking count and tell the tracker there was a
+ * modification.
+ *
+ * @GuardedBy this
+ */
+ void modified() {
+ super.modified(); /* increment the modification count */
+ ServiceTracker.this.modified();
+ }
+
+ /**
+ * Call the specific customizer adding method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Item to be tracked.
+ * @param related Action related object.
+ * @return Customized object for the tracked item or <code>null</code>
+ * if the item is not to be tracked.
+ */
+ Object customizerAdding(final Object item,
+ final Object related) {
+ return customizer.addingService((ServiceReference) item);
+ }
+
+ /**
+ * Call the specific customizer modified method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Tracked item.
+ * @param related Action related object.
+ * @param object Customized object for the tracked item.
+ */
+ void customizerModified(final Object item,
+ final Object related, final Object object) {
+ customizer.modifiedService((ServiceReference) item, object);
+ }
+
+ /**
+ * Call the specific customizer removed method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Tracked item.
+ * @param related Action related object.
+ * @param object Customized object for the tracked item.
+ */
+ void customizerRemoved(final Object item,
+ final Object related, final Object object) {
+ customizer.removedService((ServiceReference) item, object);
+ }
+ }
+
+ /**
+ * Subclass of Tracked which implements the AllServiceListener interface.
+ * This class is used by the ServiceTracker if open is called with true.
+ *
+ * @since 1.3
+ * @ThreadSafe
+ */
+ class AllTracked extends Tracked implements AllServiceListener {
+ /**
+ * AllTracked constructor.
+ */
+ AllTracked() {
+ super();
+ }
+ }
+}
diff --git a/framework/src/main/java/org/osgi/util/tracker/ServiceTrackerCustomizer.java b/framework/src/main/java/org/osgi/util/tracker/ServiceTrackerCustomizer.java
new file mode 100644
index 0000000..5c270e3
--- /dev/null
+++ b/framework/src/main/java/org/osgi/util/tracker/ServiceTrackerCustomizer.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.util.tracker;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * The <code>ServiceTrackerCustomizer</code> interface allows a
+ * <code>ServiceTracker</code> to customize the service objects that are
+ * tracked. A <code>ServiceTrackerCustomizer</code> is called when a service is
+ * being added to a <code>ServiceTracker</code>. The
+ * <code>ServiceTrackerCustomizer</code> can then return an object for the
+ * tracked service. A <code>ServiceTrackerCustomizer</code> is also called when
+ * a tracked service is modified or has been removed from a
+ * <code>ServiceTracker</code>.
+ *
+ * <p>
+ * The methods in this interface may be called as the result of a
+ * <code>ServiceEvent</code> being received by a <code>ServiceTracker</code>.
+ * Since <code>ServiceEvent</code>s are synchronously delivered by the
+ * Framework, it is highly recommended that implementations of these methods do
+ * not register (<code>BundleContext.registerService</code>), modify (
+ * <code>ServiceRegistration.setProperties</code>) or unregister (
+ * <code>ServiceRegistration.unregister</code>) a service while being
+ * synchronized on any object.
+ *
+ * <p>
+ * The <code>ServiceTracker</code> class is thread-safe. It does not call a
+ * <code>ServiceTrackerCustomizer</code> while holding any locks.
+ * <code>ServiceTrackerCustomizer</code> implementations must also be
+ * thread-safe.
+ *
+ * @ThreadSafe
+ * @version $Revision: 5874 $
+ */
+public interface ServiceTrackerCustomizer {
+ /**
+ * A service is being added to the <code>ServiceTracker</code>.
+ *
+ * <p>
+ * This method is called before a service which matched the search
+ * parameters of the <code>ServiceTracker</code> is added to the
+ * <code>ServiceTracker</code>. This method should return the service object
+ * to be tracked for the specified <code>ServiceReference</code>. The
+ * returned service object is stored in the <code>ServiceTracker</code> and
+ * is available from the <code>getService</code> and
+ * <code>getServices</code> methods.
+ *
+ * @param reference The reference to the service being added to the
+ * <code>ServiceTracker</code>.
+ * @return The service object to be tracked for the specified referenced
+ * service or <code>null</code> if the specified referenced service
+ * should not be tracked.
+ */
+ public Object addingService(ServiceReference reference);
+
+ /**
+ * A service tracked by the <code>ServiceTracker</code> has been modified.
+ *
+ * <p>
+ * This method is called when a service being tracked by the
+ * <code>ServiceTracker</code> has had it properties modified.
+ *
+ * @param reference The reference to the service that has been modified.
+ * @param service The service object for the specified referenced service.
+ */
+ public void modifiedService(ServiceReference reference, Object service);
+
+ /**
+ * A service tracked by the <code>ServiceTracker</code> has been removed.
+ *
+ * <p>
+ * This method is called after a service is no longer being tracked by the
+ * <code>ServiceTracker</code>.
+ *
+ * @param reference The reference to the service that has been removed.
+ * @param service The service object for the specified referenced service.
+ */
+ public void removedService(ServiceReference reference, Object service);
+}
diff --git a/framework/src/main/resources/org/osgi/framework/hooks/service/package.html b/framework/src/main/resources/org/osgi/framework/hooks/service/package.html
new file mode 100644
index 0000000..46d18ac
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/framework/hooks/service/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6211 $ -->
+<BODY>
+<p>Framework Service Hooks Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework.hooks.service;version="[1.0,2.0)"
+</pre>
+</BODY>
+
diff --git a/framework/src/main/resources/org/osgi/framework/hooks/service/packageinfo b/framework/src/main/resources/org/osgi/framework/hooks/service/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/framework/hooks/service/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/framework/src/main/resources/org/osgi/framework/launch/package.html b/framework/src/main/resources/org/osgi/framework/launch/package.html
new file mode 100644
index 0000000..6b0407b
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/framework/launch/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Framework Launch Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework.launch;version="[1.0,2.0)"
+</pre>
+</BODY>
+
diff --git a/framework/src/main/resources/org/osgi/framework/launch/packageinfo b/framework/src/main/resources/org/osgi/framework/launch/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/framework/launch/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/framework/src/main/resources/org/osgi/framework/package.html b/framework/src/main/resources/org/osgi/framework/package.html
new file mode 100644
index 0000000..44d6c48
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/framework/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Framework Package Version 1.5.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework;version="[1.5,2.0)"
+</pre>
+</BODY>
+
diff --git a/framework/src/main/resources/org/osgi/framework/packageinfo b/framework/src/main/resources/org/osgi/framework/packageinfo
new file mode 100644
index 0000000..ccee95e
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/framework/packageinfo
@@ -0,0 +1 @@
+version 1.5
diff --git a/framework/src/main/resources/org/osgi/service/packageadmin/package.html b/framework/src/main/resources/org/osgi/service/packageadmin/package.html
new file mode 100644
index 0000000..9fc9cab
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/service/packageadmin/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Package Admin Package Version 1.2.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.packageadmin; version="[1.2,2.0)"
+</pre>
+</BODY>
+
diff --git a/framework/src/main/resources/org/osgi/service/packageadmin/packageinfo b/framework/src/main/resources/org/osgi/service/packageadmin/packageinfo
new file mode 100644
index 0000000..ef7df68
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/service/packageadmin/packageinfo
@@ -0,0 +1 @@
+version 1.2
diff --git a/framework/src/main/resources/org/osgi/service/startlevel/package.html b/framework/src/main/resources/org/osgi/service/startlevel/package.html
new file mode 100644
index 0000000..4c27532
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/service/startlevel/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Start Level Package Version 1.1.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.startlevel; version="[1.1,2.0)"
+</pre>
+</BODY>
+
diff --git a/framework/src/main/resources/org/osgi/service/startlevel/packageinfo b/framework/src/main/resources/org/osgi/service/startlevel/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/service/startlevel/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/framework/src/main/resources/org/osgi/service/url/package.html b/framework/src/main/resources/org/osgi/service/url/package.html
new file mode 100644
index 0000000..4ed4d6e
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/service/url/package.html
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>URL Stream and Content Handlers Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.url; version="[1.0,2.0)"
+</pre>
+</BODY>
diff --git a/framework/src/main/resources/org/osgi/service/url/packageinfo b/framework/src/main/resources/org/osgi/service/url/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/service/url/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/framework/src/main/resources/org/osgi/util/tracker/package.html b/framework/src/main/resources/org/osgi/util/tracker/package.html
new file mode 100644
index 0000000..c29c891
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/util/tracker/package.html
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Tracker Package Version 1.4.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.util.tracker; version="[1.4,2.0)"
+</pre>
+</BODY>
diff --git a/framework/src/main/resources/org/osgi/util/tracker/packageinfo b/framework/src/main/resources/org/osgi/util/tracker/packageinfo
new file mode 100644
index 0000000..cc13f19
--- /dev/null
+++ b/framework/src/main/resources/org/osgi/util/tracker/packageinfo
@@ -0,0 +1 @@
+version 1.4