Updated to the latest R4.2 interfaces.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@782737 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/AdminPermission.java b/org.osgi.core/src/main/java/org/osgi/framework/AdminPermission.java
index 396e114..c55fc7b 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/AdminPermission.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/AdminPermission.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/AdminPermission.java,v 1.34 2007/02/21 16:49:05 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,9 +16,24 @@
package org.osgi.framework;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.security.*;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.security.AccessController;
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
/**
* A bundle's authority to perform specific privileged administrative operations
@@ -28,182 +41,183 @@
* permission are:
*
* <pre>
- * Action Methods
- * class Bundle.loadClass
- * execute Bundle.start
- * Bundle.stop
- * StartLevel.setBundleStartLevel
- * extensionLifecycle BundleContext.installBundle for extension bundles
- * Bundle.update for extension bundles
- * Bundle.uninstall for extension bundles
- * lifecycle BundleContext.installBundle
- * Bundle.update
- * Bundle.uninstall
- * listener BundleContext.addBundleListener for SynchronousBundleListener
- * BundleContext.removeBundleListener for SynchronousBundleListener
- * metadata Bundle.getHeaders
- * Bundle.getLocation
- * resolve PackageAdmin.refreshPackages
- * PackageAdmin.resolveBundles
- * resource Bundle.getResource
- * Bundle.getResources
- * Bundle.getEntry
- * Bundle.getEntryPaths
- * Bundle.findEntries
- * Bundle resource/entry URL creation
- * startlevel StartLevel.setStartLevel
- * StartLevel.setInitialBundleStartLevel
- * context Bundle.getBundleContext
- *
+ * Action Methods
+ * class Bundle.loadClass
+ * execute Bundle.start
+ * Bundle.stop
+ * StartLevel.setBundleStartLevel
+ * extensionLifecycle BundleContext.installBundle for extension bundles
+ * Bundle.update for extension bundles
+ * Bundle.uninstall for extension bundles
+ * lifecycle BundleContext.installBundle
+ * Bundle.update
+ * Bundle.uninstall
+ * listener BundleContext.addBundleListener for SynchronousBundleListener
+ * BundleContext.removeBundleListener for SynchronousBundleListener
+ * metadata Bundle.getHeaders
+ * Bundle.getLocation
+ * resolve PackageAdmin.refreshPackages
+ * PackageAdmin.resolveBundles
+ * resource Bundle.getResource
+ * Bundle.getResources
+ * Bundle.getEntry
+ * Bundle.getEntryPaths
+ * Bundle.findEntries
+ * Bundle resource/entry URL creation
+ * startlevel StartLevel.setStartLevel
+ * StartLevel.setInitialBundleStartLevel
+ * context Bundle.getBundleContext
* </pre>
*
* <p>
- * The special action "*" will represent all actions.
+ * 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 parameters:
+ * to the following attributes:
* <ul>
- * <li>signer - A Distinguished Name chain used to sign a bundle. Wildcards in
- * a DN are not matched according to the filter string rules, but according to
- * the rules defined for a DN chain.</li>
+ * <li>signer - A Distinguished Name chain used to sign a bundle. Wildcards in a
+ * DN are not matched according to the filter string rules, but according to the
+ * rules defined for a DN chain.</li>
* <li>location - The location of a bundle.</li>
* <li>id - The bundle ID of the designated bundle.</li>
* <li>name - The symbolic name of a bundle.</li>
* </ul>
+ * Filter attribute names are processed in a case sensitive manner.
*
* @ThreadSafe
- * @version $Revision: 1.34 $
+ * @version $Revision: 6867 $
*/
public final class AdminPermission extends BasicPermission {
- static final long serialVersionUID = 307051004521261705L;
+ static final long serialVersionUID = 307051004521261705L;
/**
- * The action string <code>class</code> (Value is "class").
+ * The action string <code>class</code>. The <code>class</code> action
+ * implies the <code>resolve</code> action.
+ *
* @since 1.3
*/
- public final static String CLASS = "class";
+ public final static String CLASS = "class";
/**
- * The action string <code>execute</code> (Value is "execute").
+ * The action string <code>execute</code>. The <code>execute</code> action
+ * implies the <code>resolve</code> action.
+ *
* @since 1.3
*/
- public final static String EXECUTE = "execute";
+ public final static String EXECUTE = "execute";
/**
- * The action string <code>extensionLifecycle</code> (Value is
- * "extensionLifecycle").
+ * The action string <code>extensionLifecycle</code>.
+ *
* @since 1.3
*/
- public final static String EXTENSIONLIFECYCLE = "extensionLifecycle";
+ public final static String EXTENSIONLIFECYCLE = "extensionLifecycle";
/**
- * The action string <code>lifecycle</code> (Value is "lifecycle").
+ * The action string <code>lifecycle</code>.
+ *
* @since 1.3
*/
- public final static String LIFECYCLE = "lifecycle";
+ public final static String LIFECYCLE = "lifecycle";
/**
- * The action string <code>listener</code> (Value is "listener").
+ * The action string <code>listener</code>.
+ *
* @since 1.3
*/
- public final static String LISTENER = "listener";
+ public final static String LISTENER = "listener";
/**
- * The action string <code>metadata</code> (Value is "metadata").
+ * The action string <code>metadata</code>.
+ *
* @since 1.3
*/
- public final static String METADATA = "metadata";
+ public final static String METADATA = "metadata";
/**
- * The action string <code>resolve</code> (Value is "resolve").
+ * The action string <code>resolve</code>. The <code>resolve</code> action
+ * is implied by the <code>class</code>, <code>execute</code> and
+ * <code>resource</code> actions.
+ *
* @since 1.3
*/
- public final static String RESOLVE = "resolve";
+ public final static String RESOLVE = "resolve";
/**
- * The action string <code>resource</code> (Value is "resource").
+ * The action string <code>resource</code>. The <code>resource</code> action
+ * implies the <code>resolve</code> action.
+ *
* @since 1.3
*/
- public final static String RESOURCE = "resource";
+ public final static String RESOURCE = "resource";
/**
- * The action string <code>startlevel</code> (Value is "startlevel").
+ * The action string <code>startlevel</code>.
+ *
* @since 1.3
*/
- public final static String STARTLEVEL = "startlevel";
+ public final static String STARTLEVEL = "startlevel";
/**
- * The action string <code>context</code> (Value is "context").
+ * The action string <code>context</code>.
+ *
* @since 1.4
*/
- public final static String CONTEXT = "context";
-
- /*
- * NOTE: A framework implementor may also choose to replace this class in
- * their distribution with a class that directly interfaces with the
- * framework implementation. This replacement class MUST NOT
- * alter the public/protected signature of this class.
- */
+ public final static String CONTEXT = "context";
- /*
- * This class will load the AdminPermission class in the package named by
- * the org.osgi.vendor.framework package. For each instance of this class,
- * an instance of the vendor AdminPermission class will be created and this
- * class will delegate method calls to the vendor AdminPermission instance.
- */
+ private final static int ACTION_CLASS = 0x00000001;
+ private final static int ACTION_EXECUTE = 0x00000002;
+ private final static int ACTION_LIFECYCLE = 0x00000004;
+ private final static int ACTION_LISTENER = 0x00000008;
+ private final static int ACTION_METADATA = 0x00000010;
+ private final static int ACTION_RESOLVE = 0x00000040;
+ private final static int ACTION_RESOURCE = 0x00000080;
+ private final static int ACTION_STARTLEVEL = 0x00000100;
+ private final static int ACTION_EXTENSIONLIFECYCLE = 0x00000200;
+ private final static int ACTION_CONTEXT = 0x00000400;
+ private final static int ACTION_ALL = ACTION_CLASS
+ | ACTION_EXECUTE
+ | ACTION_LIFECYCLE
+ | ACTION_LISTENER
+ | ACTION_METADATA
+ | ACTION_RESOLVE
+ | ACTION_RESOURCE
+ | ACTION_STARTLEVEL
+ | ACTION_EXTENSIONLIFECYCLE
+ | ACTION_CONTEXT;
+ final static int ACTION_NONE = 0;
- private static class ImplHolder implements PrivilegedAction {
- private static final String packageProperty = "org.osgi.vendor.framework";
- static final Constructor initStringString;
- static final Constructor initBundleString;
- static {
- Constructor[] constructors = (Constructor[]) AccessController.doPrivileged(new ImplHolder());
-
- initStringString = constructors[0];
- initBundleString = constructors[1];
- }
-
- private ImplHolder() {
- }
-
- public Object run() {
- String packageName = System
- .getProperty(packageProperty);
- if (packageName == null) {
- throw new NoClassDefFoundError(packageProperty
- + " property not set");
- }
-
- Class delegateClass;
- try {
- delegateClass = Class.forName(packageName
- + ".AdminPermission");
- }
- catch (ClassNotFoundException e) {
- throw new NoClassDefFoundError(e.toString());
- }
-
- Constructor[] result = new Constructor[2];
- try {
- result[0] = delegateClass
- .getConstructor(new Class[] {String.class,
- String.class });
- result[1] = delegateClass
- .getConstructor(new Class[] {Bundle.class,
- String.class });
- }
- catch (NoSuchMethodException e) {
- throw new NoSuchMethodError(e.toString());
- }
-
- return result;
- }
- }
-
- /*
- * This is the delegate permission created by the constructor.
+ /**
+ * The actions in canonical form.
+ *
+ * @serial
*/
- private final Permission delegate;
+ private volatile String actions = null;
+
+ /**
+ * The actions mask.
+ */
+ transient int action_mask;
+
+ /**
+ * If this AdminPermission was constructed with a filter, this holds a
+ * Filter matching object used to evaluate the filter in implies.
+ */
+ transient Filter filter;
+
+ /**
+ * The bundle governed by this AdminPermission - only used if filter == null
+ */
+ transient final Bundle bundle;
+
+ /**
+ * This dictionary holds the properties of the permission, used to match a
+ * filter in implies. This is not initialized until necessary, and then
+ * cached in this object.
+ */
+ private transient volatile Dictionary properties;
/**
* Creates a new <code>AdminPermission</code> object that matches all
* bundles and has all actions. Equivalent to AdminPermission("*","*");
*/
public AdminPermission() {
- this("*", "*"); //$NON-NLS-1$
+ this(null, ACTION_ALL);
}
/**
@@ -228,70 +242,41 @@
*
* @param filter A filter expression that can use signer, location, id, and
* name keys. A value of "*" or <code>null</code> matches
- * all bundle.
+ * all bundle. Filter attribute names are processed in a case
+ * sensitive manner.
* @param actions <code>class</code>, <code>execute</code>,
* <code>extensionLifecycle</code>, <code>lifecycle</code>,
- * <code>listener</code>, <code>metadata</code>,
- * <code>resolve</code>, <code>resource</code>,
- * <code>startlevel</code> or <code>context</code>. A value of "*" or <code>null</code>
- * indicates all actions
+ * <code>listener</code>, <code>metadata</code>, <code>resolve</code>
+ * , <code>resource</code>, <code>startlevel</code> or
+ * <code>context</code>. A value of "*" or <code>null</code>
+ * indicates all actions.
+ * @throws IllegalArgumentException If the filter has an invalid syntax.
*/
public AdminPermission(String filter, String actions) {
// arguments will be null if called from a PermissionInfo defined with
// no args
- super(filter == null ? "*" : filter);
- try {
- try {
- delegate = (Permission) ImplHolder.initStringString
- .newInstance(new Object[] {filter, actions});
- }
- catch (InvocationTargetException e) {
- throw e.getTargetException();
- }
- }
- catch (Error e) {
- throw e;
- }
- catch (RuntimeException e) {
- throw e;
- }
- catch (Throwable e) {
- throw new RuntimeException(e.toString());
- }
+ this(parseFilter(filter), parseActions(actions));
}
/**
- * Creates a new <code>AdminPermission</code> object to be used by the
- * code that must check a <code>Permission</code> object.
+ * Creates a new requested <code>AdminPermission</code> object to be used by
+ * the code that must perform <code>checkPermission</code>.
+ * <code>AdminPermission</code> objects created with this constructor cannot
+ * be added to an <code>AdminPermission</code> permission collection.
*
- * @param bundle A bundle
+ * @param bundle A bundle.
* @param actions <code>class</code>, <code>execute</code>,
* <code>extensionLifecycle</code>, <code>lifecycle</code>,
- * <code>listener</code>, <code>metadata</code>,
- * <code>resolve</code>, <code>resource</code>,
- * <code>startlevel</code>, <code>context</code>.
+ * <code>listener</code>, <code>metadata</code>, <code>resolve</code>
+ * , <code>resource</code>, <code>startlevel</code>,
+ * <code>context</code>. A value of "*" or <code>null</code>
+ * indicates all actions.
* @since 1.3
*/
public AdminPermission(Bundle bundle, String actions) {
super(createName(bundle));
- try {
- try {
- delegate = (Permission) ImplHolder.initBundleString
- .newInstance(new Object[] {bundle, actions});
- }
- catch (InvocationTargetException e) {
- throw e.getTargetException();
- }
- }
- catch (Error e) {
- throw e;
- }
- catch (RuntimeException e) {
- throw e;
- }
- catch (Throwable e) {
- throw new RuntimeException(e.toString());
- }
+ setTransients(null, parseActions(actions));
+ this.bundle = bundle;
}
/**
@@ -301,59 +286,295 @@
* @return permission name.
*/
private static String createName(Bundle bundle) {
- StringBuffer sb = new StringBuffer();
- sb.append("(id=");
+ if (bundle == null) {
+ throw new IllegalArgumentException("bundle must not be null");
+ }
+ StringBuffer sb = new StringBuffer("(id=");
sb.append(bundle.getBundleId());
sb.append(")");
return sb.toString();
}
/**
- * Determines the equality of two <code>AdminPermission</code> objects.
+ * Package private constructor used by AdminPermissionCollection.
*
- * @param obj The object being compared for equality with this object.
- * @return <code>true</code> if <code>obj</code> is equivalent to this
- * <code>AdminPermission</code>; <code>false</code> otherwise.
+ * @param filter name filter or <code>null</code> for wildcard.
+ * @param mask action mask
*/
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
-
- if (!(obj instanceof AdminPermission)) {
- return false;
- }
-
- AdminPermission p = (AdminPermission) obj;
-
- return delegate.equals(p.delegate);
+ AdminPermission(Filter filter, int mask) {
+ super((filter == null) ? "*" : filter.toString());
+ setTransients(filter, mask);
+ this.bundle = null;
}
/**
- * Returns the hash code value for this object.
+ * Called by constructors and when deserialized.
*
- * @return Hash code value for this object.
+ * @param filter Permission's filter or <code>null</code> for wildcard.
+ * @param mask action mask
*/
- public int hashCode() {
- return delegate.hashCode();
+ private void setTransients(Filter filter, int mask) {
+ this.filter = filter;
+ if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
+ throw new IllegalArgumentException("invalid action string");
+ }
+ this.action_mask = mask;
}
/**
- * Returns the canonical string representation of the
- * <code>AdminPermission</code> actions.
+ * Parse action string into action mask.
*
- * <p>
- * Always returns present <code>AdminPermission</code> actions in the
- * following order: <code>class</code>, <code>execute</code>,
- * <code>extensionLifecycle</code>, <code>lifecycle</code>,
- * <code>listener</code>, <code>metadata</code>, <code>resolve</code>,
- * <code>resource</code>, <code>startlevel</code>, <code>context</code>.
- *
- * @return Canonical string representation of the
- * <code>AdminPermission</code> actions.
+ * @param actions Action string.
+ * @return action mask.
*/
- public String getActions() {
- return delegate.getActions();
+ private static int parseActions(String actions) {
+ if ((actions == null) || actions.equals("*")) {
+ return ACTION_ALL;
+ }
+
+ boolean seencomma = false;
+
+ int mask = ACTION_NONE;
+
+ if (actions == null) {
+ return mask;
+ }
+
+ char[] a = actions.toCharArray();
+
+ int i = a.length - 1;
+ if (i < 0)
+ return mask;
+
+ while (i != -1) {
+ char c;
+
+ // skip whitespace
+ while ((i != -1)
+ && ((c = a[i]) == ' ' || c == '\r' || c == '\n'
+ || c == '\f' || c == '\t'))
+ i--;
+
+ // check for the known strings
+ int matchlen;
+
+ if (i >= 4 && (a[i - 4] == 'c' || a[i - 4] == 'C')
+ && (a[i - 3] == 'l' || a[i - 3] == 'L')
+ && (a[i - 2] == 'a' || a[i - 2] == 'A')
+ && (a[i - 1] == 's' || a[i - 1] == 'S')
+ && (a[i] == 's' || a[i] == 'S')) {
+ matchlen = 5;
+ mask |= ACTION_CLASS | ACTION_RESOLVE;
+
+ }
+ else
+ if (i >= 6 && (a[i - 6] == 'e' || a[i - 6] == 'E')
+ && (a[i - 5] == 'x' || a[i - 5] == 'X')
+ && (a[i - 4] == 'e' || a[i - 4] == 'E')
+ && (a[i - 3] == 'c' || a[i - 3] == 'C')
+ && (a[i - 2] == 'u' || a[i - 2] == 'U')
+ && (a[i - 1] == 't' || a[i - 1] == 'T')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 7;
+ mask |= ACTION_EXECUTE | ACTION_RESOLVE;
+
+ }
+ else
+ if (i >= 17 && (a[i - 17] == 'e' || a[i - 17] == 'E')
+ && (a[i - 16] == 'x' || a[i - 16] == 'X')
+ && (a[i - 15] == 't' || a[i - 15] == 'T')
+ && (a[i - 14] == 'e' || a[i - 14] == 'E')
+ && (a[i - 13] == 'n' || a[i - 13] == 'N')
+ && (a[i - 12] == 's' || a[i - 12] == 'S')
+ && (a[i - 11] == 'i' || a[i - 11] == 'I')
+ && (a[i - 10] == 'o' || a[i - 10] == 'O')
+ && (a[i - 9] == 'n' || a[i - 9] == 'N')
+ && (a[i - 8] == 'l' || a[i - 8] == 'L')
+ && (a[i - 7] == 'i' || a[i - 7] == 'I')
+ && (a[i - 6] == 'f' || a[i - 6] == 'F')
+ && (a[i - 5] == 'e' || a[i - 5] == 'E')
+ && (a[i - 4] == 'c' || a[i - 4] == 'C')
+ && (a[i - 3] == 'y' || a[i - 3] == 'Y')
+ && (a[i - 2] == 'c' || a[i - 2] == 'C')
+ && (a[i - 1] == 'l' || a[i - 1] == 'L')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 18;
+ mask |= ACTION_EXTENSIONLIFECYCLE;
+
+ }
+ else
+ if (i >= 8 && (a[i - 8] == 'l' || a[i - 8] == 'L')
+ && (a[i - 7] == 'i' || a[i - 7] == 'I')
+ && (a[i - 6] == 'f' || a[i - 6] == 'F')
+ && (a[i - 5] == 'e' || a[i - 5] == 'E')
+ && (a[i - 4] == 'c' || a[i - 4] == 'C')
+ && (a[i - 3] == 'y' || a[i - 3] == 'Y')
+ && (a[i - 2] == 'c' || a[i - 2] == 'C')
+ && (a[i - 1] == 'l' || a[i - 1] == 'L')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 9;
+ mask |= ACTION_LIFECYCLE;
+
+ }
+ else
+ if (i >= 7 && (a[i - 7] == 'l' || a[i - 7] == 'L')
+ && (a[i - 6] == 'i' || a[i - 6] == 'I')
+ && (a[i - 5] == 's' || a[i - 5] == 'S')
+ && (a[i - 4] == 't' || a[i - 4] == 'T')
+ && (a[i - 3] == 'e' || a[i - 3] == 'E')
+ && (a[i - 2] == 'n' || a[i - 2] == 'N')
+ && (a[i - 1] == 'e' || a[i - 1] == 'E')
+ && (a[i] == 'r' || a[i] == 'R')) {
+ matchlen = 8;
+ mask |= ACTION_LISTENER;
+
+ }
+ else
+ if (i >= 7
+ && (a[i - 7] == 'm' || a[i - 7] == 'M')
+ && (a[i - 6] == 'e' || a[i - 6] == 'E')
+ && (a[i - 5] == 't' || a[i - 5] == 'T')
+ && (a[i - 4] == 'a' || a[i - 4] == 'A')
+ && (a[i - 3] == 'd' || a[i - 3] == 'D')
+ && (a[i - 2] == 'a' || a[i - 2] == 'A')
+ && (a[i - 1] == 't' || a[i - 1] == 'T')
+ && (a[i] == 'a' || a[i] == 'A')) {
+ matchlen = 8;
+ mask |= ACTION_METADATA;
+
+ }
+ else
+ if (i >= 6
+ && (a[i - 6] == 'r' || a[i - 6] == 'R')
+ && (a[i - 5] == 'e' || a[i - 5] == 'E')
+ && (a[i - 4] == 's' || a[i - 4] == 'S')
+ && (a[i - 3] == 'o' || a[i - 3] == 'O')
+ && (a[i - 2] == 'l' || a[i - 2] == 'L')
+ && (a[i - 1] == 'v' || a[i - 1] == 'V')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 7;
+ mask |= ACTION_RESOLVE;
+
+ }
+ else
+ if (i >= 7
+ && (a[i - 7] == 'r' || a[i - 7] == 'R')
+ && (a[i - 6] == 'e' || a[i - 6] == 'E')
+ && (a[i - 5] == 's' || a[i - 5] == 'S')
+ && (a[i - 4] == 'o' || a[i - 4] == 'O')
+ && (a[i - 3] == 'u' || a[i - 3] == 'U')
+ && (a[i - 2] == 'r' || a[i - 2] == 'R')
+ && (a[i - 1] == 'c' || a[i - 1] == 'C')
+ && (a[i] == 'e' || a[i] == 'E')) {
+ matchlen = 8;
+ mask |= ACTION_RESOURCE
+ | ACTION_RESOLVE;
+
+ }
+ else
+ if (i >= 9
+ && (a[i - 9] == 's' || a[i - 9] == 'S')
+ && (a[i - 8] == 't' || a[i - 8] == 'T')
+ && (a[i - 7] == 'a' || a[i - 7] == 'A')
+ && (a[i - 6] == 'r' || a[i - 6] == 'R')
+ && (a[i - 5] == 't' || a[i - 5] == 'T')
+ && (a[i - 4] == 'l' || a[i - 4] == 'L')
+ && (a[i - 3] == 'e' || a[i - 3] == 'E')
+ && (a[i - 2] == 'v' || a[i - 2] == 'V')
+ && (a[i - 1] == 'e' || a[i - 1] == 'E')
+ && (a[i] == 'l' || a[i] == 'L')) {
+ matchlen = 10;
+ mask |= ACTION_STARTLEVEL;
+
+ }
+ else
+ if (i >= 6
+ && (a[i - 6] == 'c' || a[i - 6] == 'C')
+ && (a[i - 5] == 'o' || a[i - 5] == 'O')
+ && (a[i - 4] == 'n' || a[i - 4] == 'N')
+ && (a[i - 3] == 't' || a[i - 3] == 'T')
+ && (a[i - 2] == 'e' || a[i - 2] == 'E')
+ && (a[i - 1] == 'x' || a[i - 1] == 'X')
+ && (a[i] == 't' || a[i] == 'T')) {
+ matchlen = 7;
+ mask |= ACTION_CONTEXT;
+
+ }
+ else
+ if (i >= 0 &&
+
+ (a[i] == '*')) {
+ matchlen = 1;
+ mask |= ACTION_ALL;
+
+ }
+ else {
+ // parse error
+ throw new IllegalArgumentException(
+ "invalid permission: "
+ + actions);
+ }
+
+ // make sure we didn't just match the tail of a word
+ // like "ackbarfstartlevel". Also, skip to the comma.
+ seencomma = false;
+ while (i >= matchlen && !seencomma) {
+ switch (a[i - matchlen]) {
+ case ',' :
+ seencomma = true;
+ /* FALLTHROUGH */
+ case ' ' :
+ case '\r' :
+ case '\n' :
+ case '\f' :
+ case '\t' :
+ break;
+ default :
+ throw new IllegalArgumentException(
+ "invalid permission: " + actions);
+ }
+ i--;
+ }
+
+ // point i at the location of the comma minus one (or -1).
+ i -= matchlen;
+ }
+
+ if (seencomma) {
+ throw new IllegalArgumentException("invalid permission: " +
+ actions);
+ }
+
+ return mask;
+ }
+
+ /**
+ * Parse filter string into a Filter object.
+ *
+ * @param filterString The filter string to parse.
+ * @return a Filter for this bundle. If the specified filterString is
+ * <code>null</code> or equals "*", then <code>null</code> is
+ * returned to indicate a wildcard.
+ * @throws IllegalArgumentException If the filter syntax is invalid.
+ */
+ private static Filter parseFilter(String filterString) {
+ if (filterString == null) {
+ return null;
+ }
+ filterString = filterString.trim();
+ if (filterString.equals("*")) {
+ return null;
+ }
+
+ try {
+ return FrameworkUtil.createFilter(filterString);
+ }
+ catch (InvalidSyntaxException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "invalid filter");
+ iae.initCause(e);
+ throw iae;
+ }
}
/**
@@ -378,20 +599,135 @@
* filter is "*" and this object's actions include all of the specified
* permission's actions
*
- * @param p The permission to interrogate.
- *
- * @return <code>true</code> if the specified permission is implied by
- * this object; <code>false</code> otherwise.
- * @throws RuntimeException if specified permission was not constructed with
- * a bundle or "*"
+ * @param p The requested permission.
+ * @return <code>true</code> if the specified permission is implied by this
+ * object; <code>false</code> otherwise.
*/
public boolean implies(Permission p) {
if (!(p instanceof AdminPermission)) {
return false;
}
+ AdminPermission requested = (AdminPermission) p;
+ if (bundle != null) {
+ return false;
+ }
+ // if requested permission has a filter, then it is an invalid argument
+ if (requested.filter != null) {
+ return false;
+ }
+ return implies0(requested, ACTION_NONE);
+ }
- AdminPermission pp = (AdminPermission) p;
- return delegate.implies(pp.delegate);
+ /**
+ * Internal implies method. Used by the implies and the permission
+ * collection implies methods.
+ *
+ * @param requested The requested AdminPermision which has already be
+ * validated as a proper argument. The requested AdminPermission must
+ * not have a filter expression.
+ * @param effective The effective actions with which to start.
+ * @return <code>true</code> if the specified permission is implied by this
+ * object; <code>false</code> otherwise.
+ */
+ boolean implies0(AdminPermission requested, int effective) {
+ /* check actions first - much faster */
+ effective |= action_mask;
+ final int desired = requested.action_mask;
+ if ((effective & desired) != desired) {
+ return false;
+ }
+
+ /* Get our filter */
+ Filter f = filter;
+ if (f == null) {
+ // it's "*"
+ return true;
+ }
+ /* is requested a wildcard filter? */
+ if (requested.bundle == null) {
+ return false;
+ }
+ return f.matchCase(requested.getProperties());
+ }
+
+ /**
+ * Returns the canonical string representation of the
+ * <code>AdminPermission</code> actions.
+ *
+ * <p>
+ * Always returns present <code>AdminPermission</code> actions in the
+ * following order: <code>class</code>, <code>execute</code>,
+ * <code>extensionLifecycle</code>, <code>lifecycle</code>,
+ * <code>listener</code>, <code>metadata</code>, <code>resolve</code>,
+ * <code>resource</code>, <code>startlevel</code>, <code>context</code>.
+ *
+ * @return Canonical string representation of the
+ * <code>AdminPermission</code> actions.
+ */
+ public String getActions() {
+ String result = actions;
+ if (result == null) {
+ StringBuffer sb = new StringBuffer();
+
+ int mask = action_mask;
+ if ((mask & ACTION_CLASS) == ACTION_CLASS) {
+ sb.append(CLASS);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_EXECUTE) == ACTION_EXECUTE) {
+ sb.append(EXECUTE);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_EXTENSIONLIFECYCLE) == ACTION_EXTENSIONLIFECYCLE) {
+ sb.append(EXTENSIONLIFECYCLE);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_LIFECYCLE) == ACTION_LIFECYCLE) {
+ sb.append(LIFECYCLE);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_LISTENER) == ACTION_LISTENER) {
+ sb.append(LISTENER);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_METADATA) == ACTION_METADATA) {
+ sb.append(METADATA);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_RESOLVE) == ACTION_RESOLVE) {
+ sb.append(RESOLVE);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_RESOURCE) == ACTION_RESOURCE) {
+ sb.append(RESOURCE);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_STARTLEVEL) == ACTION_STARTLEVEL) {
+ sb.append(STARTLEVEL);
+ sb.append(',');
+ }
+
+ if ((mask & ACTION_CONTEXT) == ACTION_CONTEXT) {
+ sb.append(CONTEXT);
+ sb.append(',');
+ }
+
+ // remove trailing comma
+ if (sb.length() > 0) {
+ sb.setLength(sb.length() - 1);
+ }
+
+ actions = result = sb.toString();
+ }
+ return result;
}
/**
@@ -401,6 +737,265 @@
* @return A new <code>PermissionCollection</code> object.
*/
public PermissionCollection newPermissionCollection() {
- return delegate.newPermissionCollection();
+ return new AdminPermissionCollection();
+ }
+
+ /**
+ * Determines the equality of two <code>AdminPermission</code> objects.
+ *
+ * @param obj The object being compared for equality with this object.
+ * @return <code>true</code> if <code>obj</code> is equivalent to this
+ * <code>AdminPermission</code>; <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (!(obj instanceof AdminPermission)) {
+ return false;
+ }
+
+ AdminPermission ap = (AdminPermission) obj;
+
+ return (action_mask == ap.action_mask)
+ && ((bundle == ap.bundle) || ((bundle != null) && bundle
+ .equals(ap.bundle)))
+ && (filter == null ? ap.filter == null : filter
+ .equals(ap.filter));
+ }
+
+ /**
+ * Returns the hash code value for this object.
+ *
+ * @return Hash code value for this object.
+ */
+ public int hashCode() {
+ int h = 31 * 17 + getName().hashCode();
+ h = 31 * h + getActions().hashCode();
+ if (bundle != null) {
+ h = 31 * h + bundle.hashCode();
+ }
+ return h;
+ }
+
+ /**
+ * WriteObject is called to save the state of this permission object to a
+ * stream. The actions are serialized, and the superclass takes care of the
+ * name.
+ */
+ private synchronized void writeObject(java.io.ObjectOutputStream s)
+ throws IOException {
+ if (bundle != null) {
+ throw new NotSerializableException("cannot serialize");
+ }
+ // Write out the actions. The superclass takes care of the name
+ // call getActions to make sure actions field is initialized
+ if (actions == null)
+ getActions();
+ s.defaultWriteObject();
+ }
+
+ /**
+ * readObject is called to restore the state of this permission from a
+ * stream.
+ */
+ private synchronized void readObject(java.io.ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ // Read in the data, then initialize the transients
+ s.defaultReadObject();
+ setTransients(parseFilter(getName()), parseActions(actions));
+ }
+
+ /**
+ * Called by <code><@link AdminPermission#implies(Permission)></code> on an
+ * AdminPermission which was constructed with a Bundle. This method loads a
+ * dictionary with the filter-matchable properties of this bundle. The
+ * dictionary is cached so this lookup only happens once.
+ *
+ * This method should only be called on an AdminPermission which was
+ * constructed with a bundle
+ *
+ * @return a dictionary of properties for this bundle
+ */
+ private Dictionary getProperties() {
+ Dictionary result = properties;
+ if (result != null) {
+ return result;
+ }
+ final Dictionary dict = new Hashtable(4);
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ dict.put("id", new Long(bundle.getBundleId()));
+ dict.put("location", bundle.getLocation());
+ String name = bundle.getSymbolicName();
+ if (name != null) {
+ dict.put("name", name);
+ }
+ SignerProperty signer = new SignerProperty(bundle);
+ if (signer.isBundleSigned()) {
+ dict.put("signer", signer);
+ }
+ return null;
+ }
+ });
+ return properties = dict;
+ }
+}
+
+/**
+ * Stores a collection of <code>AdminPermission</code>s.
+ */
+final class AdminPermissionCollection extends PermissionCollection {
+ private static final long serialVersionUID = 3906372644575328048L;
+ /**
+ * Collection of permissions.
+ *
+ * @GuardedBy this
+ */
+ private transient Map permissions;
+
+ /**
+ * Boolean saying if "*" is in the collection.
+ *
+ * @serial
+ * @GuardedBy this
+ */
+ private boolean all_allowed;
+
+ /**
+ * Create an empty AdminPermissions object.
+ *
+ */
+ public AdminPermissionCollection() {
+ permissions = new HashMap();
+ }
+
+ /**
+ * Adds a permission to this permission collection.
+ *
+ * @param permission The <code>AdminPermission</code> object to add.
+ * @throws IllegalArgumentException If the specified permission is not an
+ * <code>AdminPermission</code> instance or was constructed with a
+ * Bundle object.
+ * @throws SecurityException If this <code>AdminPermissionCollection</code>
+ * object has been marked read-only.
+ */
+ public void add(Permission permission) {
+ if (!(permission instanceof AdminPermission)) {
+ throw new IllegalArgumentException("invalid permission: "
+ + permission);
+ }
+ if (isReadOnly()) {
+ throw new SecurityException("attempt to add a Permission to a "
+ + "readonly PermissionCollection");
+ }
+ final AdminPermission ap = (AdminPermission) permission;
+ if (ap.bundle != null) {
+ throw new IllegalArgumentException("cannot add to collection: "
+ + ap);
+ }
+ final String name = ap.getName();
+ synchronized (this) {
+ Map pc = permissions;
+ AdminPermission existing = (AdminPermission) pc.get(name);
+ if (existing != null) {
+ int oldMask = existing.action_mask;
+ int newMask = ap.action_mask;
+
+ if (oldMask != newMask) {
+ pc.put(name, new AdminPermission(existing.filter, oldMask
+ | newMask));
+ }
+ }
+ else {
+ pc.put(name, ap);
+ }
+ if (!all_allowed) {
+ if (name.equals("*")) {
+ all_allowed = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Determines if the specified permissions implies the permissions expressed
+ * in <code>permission</code>.
+ *
+ * @param permission The Permission object to compare with the
+ * <code>AdminPermission</code> objects in this collection.
+ * @return <code>true</code> if <code>permission</code> is implied by an
+ * <code>AdminPermission</code> in this collection,
+ * <code>false</code> otherwise.
+ */
+ public boolean implies(Permission permission) {
+ if (!(permission instanceof AdminPermission)) {
+ return false;
+ }
+
+ AdminPermission requested = (AdminPermission) permission;
+ // if requested permission has a filter, then it is an invalid argument
+ if (requested.filter != null) {
+ return false;
+ }
+ int effective = AdminPermission.ACTION_NONE;
+ Collection perms;
+ synchronized (this) {
+ Map pc = permissions;
+ // short circuit if the "*" Permission was added
+ if (all_allowed) {
+ AdminPermission ap = (AdminPermission) pc.get("*");
+ if (ap != null) {
+ effective |= ap.action_mask;
+ final int desired = requested.action_mask;
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ }
+ perms = pc.values();
+ }
+
+ // just iterate one by one
+ for (Iterator iter = perms.iterator(); iter.hasNext();) {
+ if (((AdminPermission) iter.next()).implies0(requested, effective)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an enumeration of all <code>AdminPermission</code> objects in the
+ * container.
+ *
+ * @return Enumeration of all <code>AdminPermission</code> objects.
+ */
+ public synchronized Enumeration elements() {
+ return Collections.enumeration(permissions.values());
+ }
+
+ /* serialization logic */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("permissions", Hashtable.class),
+ new ObjectStreamField("all_allowed", Boolean.TYPE) };
+
+ private synchronized void writeObject(ObjectOutputStream out)
+ throws IOException {
+ Hashtable hashtable = new Hashtable(permissions);
+ ObjectOutputStream.PutField pfields = out.putFields();
+ pfields.put("permissions", hashtable);
+ pfields.put("all_allowed", all_allowed);
+ out.writeFields();
+ }
+
+ private synchronized void readObject(java.io.ObjectInputStream in)
+ throws IOException,
+ ClassNotFoundException {
+ ObjectInputStream.GetField gfields = in.readFields();
+ Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+ permissions = new HashMap(hashtable);
+ all_allowed = gfields.get("all_allowed", false);
}
}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/AllServiceListener.java b/org.osgi.core/src/main/java/org/osgi/framework/AllServiceListener.java
index e126c5c..688f51e 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/AllServiceListener.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/AllServiceListener.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/AllServiceListener.java,v 1.10 2007/02/20 00:16:30 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2005, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -57,7 +55,7 @@
* @see ServicePermission
* @ThreadSafe
* @since 1.3
- * @version $Revision: 1.10 $
+ * @version $Revision: 5673 $
*/
public interface AllServiceListener extends ServiceListener {
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/Bundle.java b/org.osgi.core/src/main/java/org/osgi/framework/Bundle.java
index b814f82..692bc5e 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/Bundle.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/Bundle.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/Bundle.java,v 1.54 2007/02/21 16:49:05 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +21,7 @@
import java.net.URL;
import java.util.Dictionary;
import java.util.Enumeration;
+import java.util.Map;
/**
* An installed bundle in the Framework.
@@ -65,7 +64,7 @@
* Framework that created them.
*
* @ThreadSafe
- * @version $Revision: 1.54 $
+ * @version $Revision: 6906 $
*/
public interface Bundle {
/**
@@ -216,6 +215,23 @@
public static final int STOP_TRANSIENT = 0x00000001;
/**
+ * Request that all certificates used to sign the bundle be returned.
+ *
+ * @since 1.5
+ * @see #getSignerCertificates(int)
+ */
+ public final static int SIGNERS_ALL = 1;
+
+ /**
+ * Request that only certificates used to sign the bundle that are trusted
+ * by the framework be returned.
+ *
+ * @since 1.5
+ * @see #getSignerCertificates(int)
+ */
+ public final static int SIGNERS_TRUSTED = 2;
+
+ /**
* Returns this bundle's current state.
*
* <p>
@@ -255,8 +271,8 @@
* <li>If this bundle is in the process of being activated or deactivated
* then this method must wait for activation or deactivation to complete
* before continuing. If this does not occur in a reasonable time, a
- * <code>BundleException</code> is thrown to indicate this bundle was
- * unable to be started.
+ * <code>BundleException</code> is thrown to indicate this bundle was unable
+ * to be started.
*
* <li>If this bundle's state is <code>ACTIVE</code> then this method
* returns immediately.
@@ -264,17 +280,17 @@
* <li>If the {@link #START_TRANSIENT} option is not set then set this
* bundle's autostart setting to <em>Started with declared activation</em>
* if the {@link #START_ACTIVATION_POLICY} option is set or
- * <em>Started with eager activation</em> if not set. When the Framework
- * is restarted and this bundle's autostart setting is not <em>Stopped</em>,
+ * <em>Started with eager activation</em> if not set. When the Framework is
+ * restarted and this bundle's autostart setting is not <em>Stopped</em>,
* this bundle must be automatically started.
*
- * <li>If this bundle's state is not <code>RESOLVED</code>, an attempt
- * is made to resolve this bundle. If the Framework cannot resolve this
- * bundle, a <code>BundleException</code> is thrown.
+ * <li>If this bundle's state is not <code>RESOLVED</code>, an attempt is
+ * made to resolve this bundle. If the Framework cannot resolve this bundle,
+ * a <code>BundleException</code> is thrown.
*
* <li>If the {@link #START_ACTIVATION_POLICY} option is set and this
- * bundle's declared activation policy is
- * {@link Constants#ACTIVATION_LAZY lazy} then:
+ * bundle's declared activation policy is {@link Constants#ACTIVATION_LAZY
+ * lazy} then:
* <ul>
* <li>If this bundle's state is <code>STARTING</code> then this method
* returns immediately.
@@ -313,40 +329,40 @@
*
* <b>Preconditions </b>
* <ul>
- * <li><code>getState()</code> in {<code>INSTALLED</code>,
- * <code>RESOLVED</code>} or {<code>INSTALLED</code>,
- * <code>RESOLVED</code>, <code>STARTING</code>} if this bundle has a
- * lazy activation policy.
+ * <li><code>getState()</code> in { <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>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>}.
+ * <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.
+ * {@link #START_TRANSIENT} and {@link #START_ACTIVATION_POLICY}. The
+ * Framework must ignore unrecognized options.
* @throws BundleException If this bundle could not be started. This could
* be because a code dependency could not be resolved or the
* specified <code>BundleActivator</code> could not be loaded or
* threw an exception or this bundle is a fragment.
- * @throws java.lang.IllegalStateException If this bundle has been
- * uninstalled or this bundle tries to change its own state.
- * @throws java.lang.SecurityException If the caller does not have the
- * appropriate <code>AdminPermission[this,EXECUTE]</code>, and
- * the Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
* @since 1.4
*/
public void start(int options) throws BundleException;
@@ -355,17 +371,17 @@
* Starts this bundle with no options.
*
* <p>
- * This method calls <code>start(0)</code>.
+ * This method performs the same function as calling <code>start(0)</code>.
*
* @throws BundleException If this bundle could not be started. This could
* be because a code dependency could not be resolved or the
* specified <code>BundleActivator</code> could not be loaded or
* threw an exception or this bundle is a fragment.
- * @throws java.lang.IllegalStateException If this bundle has been
- * uninstalled or this bundle tries to change its own state.
- * @throws java.lang.SecurityException If the caller does not have the
- * appropriate <code>AdminPermission[this,EXECUTE]</code>, and
- * the Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
* @see #start(int)
*/
public void start() throws BundleException;
@@ -382,33 +398,34 @@
* <li>If this bundle is in the process of being activated or deactivated
* then this method must wait for activation or deactivation to complete
* before continuing. If this does not occur in a reasonable time, a
- * <code>BundleException</code> is thrown to indicate this bundle was
- * unable to be stopped.
+ * <code>BundleException</code> is thrown to indicate this bundle was unable
+ * to be stopped.
* <li>If the {@link #STOP_TRANSIENT} option is not set then then set this
* bundle's persistent autostart setting to to <em>Stopped</em>. When the
* Framework is restarted and this bundle's autostart setting is
* <em>Stopped</em>, this bundle must not be automatically started.
*
- * <li>If this bundle's state is not <code>ACTIVE</code> then this method
- * returns immediately.
+ * <li>If this bundle's state is not <code>STARTING</code> or
+ * <code>ACTIVE</code> then this method returns immediately.
*
* <li>This bundle's state is set to <code>STOPPING</code>.
*
* <li>A bundle event of type {@link BundleEvent#STOPPING} is fired.
*
- * <li>The {@link BundleActivator#stop} method of this bundle's
- * <code>BundleActivator</code>, if one is specified, is called. If that
- * method throws an exception, this method must continue to stop this
- * bundle. A <code>BundleException</code> must be thrown after completion
- * of the remaining steps.
+ * <li>If this bundle's state was <code>ACTIVE</code> prior to setting the
+ * state to <code>STOPPING</code>, the {@link BundleActivator#stop} method
+ * of this bundle's <code>BundleActivator</code>, if one is specified, is
+ * called. If that method throws an exception, this method must continue to
+ * stop this bundle and a <code>BundleException</code> must be thrown after
+ * completion of the remaining steps.
*
* <li>Any services registered by this bundle must be unregistered.
* <li>Any services used by this bundle must be released.
* <li>Any listeners registered by this bundle must be removed.
*
* <li>If this bundle's state is <code>UNINSTALLED</code>, because this
- * bundle was uninstalled while the <code>BundleActivator.stop</code>
- * method was running, a <code>BundleException</code> must be thrown.
+ * bundle was uninstalled while the <code>BundleActivator.stop</code> method
+ * was running, a <code>BundleException</code> must be thrown.
*
* <li>This bundle's state is set to <code>RESOLVED</code>.
*
@@ -417,16 +434,16 @@
*
* <b>Preconditions </b>
* <ul>
- * <li><code>getState()</code> in {<code>ACTIVE</code>}.
+ * <li><code>getState()</code> in { <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.
+ * <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>
@@ -439,11 +456,11 @@
* options.
* @throws BundleException If this bundle's <code>BundleActivator</code>
* threw an exception or this bundle is a fragment.
- * @throws java.lang.IllegalStateException If this bundle has been
- * uninstalled or this bundle tries to change its own state.
- * @throws java.lang.SecurityException If the caller does not have the
- * appropriate <code>AdminPermission[this,EXECUTE]</code>, and
- * the Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
* @since 1.4
*/
public void stop(int options) throws BundleException;
@@ -452,31 +469,40 @@
* Stops this bundle with no options.
*
* <p>
- * This method calls <code>stop(0)</code>.
+ * This method performs the same function as calling <code>stop(0)</code>.
*
* @throws BundleException If this bundle's <code>BundleActivator</code>
* threw an exception or this bundle is a fragment.
- * @throws java.lang.IllegalStateException If this bundle has been
- * uninstalled or this bundle tries to change its own state.
- * @throws java.lang.SecurityException If the caller does not have the
- * appropriate <code>AdminPermission[this,EXECUTE]</code>, and
- * the Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
* @see #start(int)
*/
public void stop() throws BundleException;
/**
- * Updates this bundle.
+ * Updates this bundle from an <code>InputStream</code>.
*
* <p>
- * If this bundle's state is <code>ACTIVE</code>, it must be stopped
- * before the update and started after the update successfully completes.
+ * If the specified <code>InputStream</code> is <code>null</code>, the
+ * Framework must create the <code>InputStream</code> from which to read the
+ * updated bundle by interpreting, in an implementation dependent manner,
+ * this bundle's {@link Constants#BUNDLE_UPDATELOCATION
+ * Bundle-UpdateLocation} Manifest header, if present, or this bundle's
+ * original location.
*
* <p>
- * If this bundle has exported any packages, these packages must not be
- * updated. Instead, the previous package version must remain exported until
- * the <code>PackageAdmin.refreshPackages</code> method has been has been
- * called or the Framework is relaunched.
+ * If this bundle's state is <code>ACTIVE</code>, it must be stopped before
+ * the update and started after the update successfully completes.
+ *
+ * <p>
+ * If this bundle has exported any packages that are imported by another
+ * bundle, these packages must not be updated. Instead, the previous package
+ * version must remain exported until the
+ * <code>PackageAdmin.refreshPackages</code> method has been has been called
+ * or the Framework is relaunched.
*
* <p>
* The following steps are required to update a bundle:
@@ -484,36 +510,20 @@
* <li>If this bundle's state is <code>UNINSTALLED</code> then an
* <code>IllegalStateException</code> is thrown.
*
- * <li>If this bundle's state is <code>ACTIVE</code>,
- * <code>STARTING</code> or <code>STOPPING</code>, this bundle is
- * stopped as described in the <code>Bundle.stop</code> method. If
- * <code>Bundle.stop</code> throws an exception, the exception is rethrown
- * terminating the update.
+ * <li>If this bundle's state is <code>ACTIVE</code>, <code>STARTING</code>
+ * or <code>STOPPING</code>, this bundle is stopped as described in the
+ * <code>Bundle.stop</code> method. If <code>Bundle.stop</code> throws an
+ * exception, the exception is rethrown terminating the update.
*
- * <li>The download location of the new version of this bundle is
- * determined from either this bundle's
- * {@link Constants#BUNDLE_UPDATELOCATION} Manifest header (if available) or
- * this bundle's original location.
- *
- * <li>The location is interpreted in an implementation dependent manner,
- * typically as a URL, and the new version of this bundle is obtained from
- * this location.
- *
- * <li>The new version of this bundle is installed. If the Framework is
- * unable to install the new version of this bundle, the original version of
- * this bundle must be restored and a <code>BundleException</code> must be
- * thrown after completion of the remaining steps.
- *
- * <li>If this bundle has declared an Bundle-RequiredExecutionEnvironment
- * header, then the listed execution environments must be verified against
- * the installed execution environments. If they do not all match, the
- * original version of this bundle must be restored and a
+ * <li>The updated version of this bundle is read from the input stream and
+ * installed. If the Framework is unable to install the updated version of
+ * this bundle, the original version of this bundle must be restored and a
* <code>BundleException</code> must be thrown after completion of the
* remaining steps.
*
* <li>This bundle's state is set to <code>INSTALLED</code>.
*
- * <li>If the new version of this bundle was successfully installed, a
+ * <li>If the updated version of this bundle was successfully installed, a
* bundle event of type {@link BundleEvent#UPDATED} is fired.
*
* <li>If this bundle's state was originally <code>ACTIVE</code>, the
@@ -525,57 +535,59 @@
*
* <b>Preconditions </b>
* <ul>
- * <li><code>getState()</code> not in {<code>UNINSTALLED</code>}.
+ * <li><code>getState()</code> not in { <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><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><code>getState()</code> in { <code>INSTALLED</code>,
+ * <code>RESOLVED</code>, <code>ACTIVE</code> }.
* <li>Original bundle is still used; no update occurred.
* </ul>
*
- * @throws BundleException If the update fails.
- * @throws java.lang.IllegalStateException If this bundle has been
- * uninstalled or this bundle tries to change its own state.
- * @throws java.lang.SecurityException If the caller does not have the
- * appropriate <code>AdminPermission[this,LIFECYCLE]</code> for
- * both the current bundle and the updated bundle, and the Java
- * Runtime Environment supports permissions.
+ * @param input The <code>InputStream</code> from which to read the new
+ * bundle or <code>null</code> to indicate the Framework must create
+ * the input stream from this bundle's
+ * {@link Constants#BUNDLE_UPDATELOCATION Bundle-UpdateLocation}
+ * Manifest header, if present, or this bundle's original location.
+ * The input stream must always be closed when this method completes,
+ * even if an exception is thrown.
+ * @throws BundleException If the input stream cannot be read or the update
+ * fails.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code> for both the current
+ * bundle and the updated bundle, and the Java Runtime Environment
+ * supports permissions.
* @see #stop()
* @see #start()
*/
- public void update() throws BundleException;
+ public void update(InputStream input) throws BundleException;
/**
- * Updates this bundle from an <code>InputStream</code>.
+ * Updates this bundle.
*
* <p>
- * This method performs all the steps listed in <code>Bundle.update()</code>,
- * except the new version of this bundle must be read from the supplied
- * <code>InputStream</code>, rather than a <code>URL</code>.
- * <p>
- * This method must always close the <code>InputStream</code> when it is
- * done, even if an exception is thrown.
+ * This method performs the same function as calling
+ * {@link #update(InputStream)} with a <code>null</code> InputStream.
*
- * @param in The <code>InputStream</code> from which to read the new
- * bundle.
- * @throws BundleException If the provided stream cannot be read or the
- * update fails.
- * @throws java.lang.IllegalStateException If this bundle has been
- * uninstalled or this bundle tries to change its own state.
- * @throws java.lang.SecurityException If the caller does not have the
- * appropriate <code>AdminPermission[this,LIFECYCLE]</code> for
- * both the current bundle and the updated bundle, and the Java
- * Runtime Environment supports permissions.
- * @see #update()
+ * @throws BundleException If the update fails.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code> for both the current
+ * bundle and the updated bundle, and the Java Runtime Environment
+ * supports permissions.
+ * @see #update(InputStream)
*/
- public void update(InputStream in) throws BundleException;
+ public void update() throws BundleException;
/**
* Uninstalls this bundle.
@@ -598,11 +610,11 @@
* <li>If this bundle's state is <code>UNINSTALLED</code> then an
* <code>IllegalStateException</code> is thrown.
*
- * <li>If this bundle's state is <code>ACTIVE</code>,
- * <code>STARTING</code> or <code>STOPPING</code>, this bundle is
- * stopped as described in the <code>Bundle.stop</code> method. If
- * <code>Bundle.stop</code> throws an exception, a Framework event of type
- * {@link FrameworkEvent#ERROR} is fired containing the exception.
+ * <li>If this bundle's state is <code>ACTIVE</code>, <code>STARTING</code>
+ * or <code>STOPPING</code>, this bundle is stopped as described in the
+ * <code>Bundle.stop</code> method. If <code>Bundle.stop</code> throws an
+ * exception, a Framework event of type {@link FrameworkEvent#ERROR} is
+ * fired containing the exception.
*
* <li>This bundle's state is set to <code>UNINSTALLED</code>.
*
@@ -614,27 +626,30 @@
*
* <b>Preconditions </b>
* <ul>
- * <li><code>getState()</code> not in {<code>UNINSTALLED</code>}.
+ * <li><code>getState()</code> not in { <code>UNINSTALLED</code>
+ * }.
* </ul>
* <b>Postconditions, no exceptions thrown </b>
* <ul>
- * <li><code>getState()</code> in {<code>UNINSTALLED</code>}.
+ * <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><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 java.lang.IllegalStateException If this bundle has been
- * uninstalled or this bundle tries to change its own state.
- * @throws java.lang.SecurityException If the caller does not have the
- * appropriate <code>AdminPermission[this,LIFECYCLE]</code>, and
- * the Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been uninstalled or this
+ * bundle tries to change its own state.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+ * Runtime Environment supports permissions.
* @see #stop()
*/
public void uninstall() throws BundleException;
@@ -650,7 +665,9 @@
* case-insensitive manner.
*
* If a Manifest header value starts with "%", it must be
- * localized according to the default locale.
+ * localized according to the default locale. If no localization is found
+ * for a header value, the header value without the leading "%" is
+ * returned.
*
* <p>
* For example, the following Manifest headers and values are included if
@@ -671,14 +688,12 @@
*
* @return A <code>Dictionary</code> object containing this bundle's
* Manifest headers and values.
- *
- * @throws java.lang.SecurityException If the caller does not have the
+ * @throws SecurityException If the caller does not have the
* appropriate <code>AdminPermission[this,METADATA]</code>, and
* the Java Runtime Environment supports permissions.
- *
* @see Constants#BUNDLE_LOCALIZATION
*/
- public Dictionary getHeaders();
+ public Dictionary/* <String,String> */getHeaders();
/**
* Returns this bundle's unique identifier. This bundle is assigned a unique
@@ -718,7 +733,7 @@
* while this bundle is in the <code>UNINSTALLED</code> state.
*
* @return The string representation of this bundle's location identifier.
- * @throws java.lang.SecurityException If the caller does not have the
+ * @throws SecurityException If the caller does not have the
* appropriate <code>AdminPermission[this,METADATA]</code>, and
* the Java Runtime Environment supports permissions.
*/
@@ -742,7 +757,7 @@
*
* @return An array of <code>ServiceReference</code> objects or
* <code>null</code>.
- * @throws java.lang.IllegalStateException If this bundle has been
+ * @throws IllegalStateException If this bundle has been
* uninstalled.
* @see ServiceRegistration
* @see ServiceReference
@@ -769,7 +784,7 @@
*
* @return An array of <code>ServiceReference</code> objects or
* <code>null</code>.
- * @throws java.lang.IllegalStateException If this bundle has been
+ * @throws IllegalStateException If this bundle has been
* uninstalled.
* @see ServiceReference
* @see ServicePermission
@@ -795,43 +810,43 @@
* the same set of permissions.
*
* @param permission The permission to verify.
- *
* @return <code>true</code> if this bundle has the specified permission
* or the permissions possessed by this bundle imply the specified
* permission; <code>false</code> if this bundle does not have the
* specified permission or <code>permission</code> is not an
* <code>instanceof</code> <code>java.security.Permission</code>.
- *
- * @throws java.lang.IllegalStateException If this bundle has been
+ * @throws IllegalStateException If this bundle has been
* uninstalled.
*/
public boolean hasPermission(Object permission);
/**
- * Find the specified resource from this bundle.
+ * Find the specified resource from this bundle's class loader.
*
* This bundle's class loader is called to search for the specified
- * resource. If this bundle's state is <code>INSTALLED</code>, this
- * method must attempt to resolve this bundle before attempting to get the
+ * resource. If this bundle's state is <code>INSTALLED</code>, this method
+ * must attempt to resolve this bundle before attempting to get the
* specified resource. If this bundle cannot be resolved, then only this
* bundle must be searched for the specified resource. Imported packages
* cannot be searched when this bundle has not been resolved. If this bundle
* is a fragment bundle then <code>null</code> is returned.
+ * <p>
+ * Note: Jar and zip files are not required to include directory entries.
+ * URLs to directory entries will not be returned if the bundle contents do
+ * not contain directory entries.
*
* @param name The name of the resource. See
- * <code>java.lang.ClassLoader.getResource</code> for a description
- * of the format of a resource name.
- * @return A URL to the named resource, or <code>null</code> if the
- * resource could not be found or if this bundle is a fragment
- * bundle or if the caller does not have the appropriate
- * <code>AdminPermission[this,RESOURCE]</code>, and the Java
- * Runtime Environment supports permissions.
- *
- * @since 1.1
- * @throws java.lang.IllegalStateException If this bundle has been
- * uninstalled.
+ * <code>ClassLoader.getResource</code> for a description of the
+ * format of a resource name.
+ * @return A URL to the named resource, or <code>null</code> if the resource
+ * could not be found or if this bundle is a fragment bundle or if
+ * the caller does not have the appropriate
+ * <code>AdminPermission[this,RESOURCE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been uninstalled.
* @see #getEntry
* @see #findEntries
+ * @since 1.1
*/
public URL getResource(String name);
@@ -851,13 +866,13 @@
* default locale. Localizations are searched for in the following order:
*
* <pre>
- * bn + "_" + Ls + "_" + Cs + "_" + Vs
- * bn + "_" + Ls + "_" + Cs
- * bn + "_" + Ls
- * bn + "_" + Ld + "_" + Cd + "_" + Vd
- * bn + "_" + Ld + "_" + Cd
- * bn + "_" + Ld
- * bn
+ * bn + "_" + 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,
@@ -870,7 +885,9 @@
* 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.
+ * 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
@@ -886,35 +903,34 @@
* leading "%".
* @return A <code>Dictionary</code> object containing this bundle's
* Manifest headers and values.
- *
- * @throws java.lang.SecurityException If the caller does not have the
+ * @throws SecurityException If the caller does not have the
* appropriate <code>AdminPermission[this,METADATA]</code>, and
* the Java Runtime Environment supports permissions.
- *
* @see #getHeaders()
* @see Constants#BUNDLE_LOCALIZATION
* @since 1.3
*/
- public Dictionary getHeaders(String locale);
+ public Dictionary/* <String,String> */getHeaders(String locale);
/**
* Returns the symbolic name of this bundle as specified by its
- * <code>Bundle-SymbolicName</code> manifest header. The name must be
- * unique, it is recommended to use a reverse domain name naming convention
- * like that used for java packages. If this bundle does not have a
- * specified symbolic name then <code>null</code> is returned.
+ * <code>Bundle-SymbolicName</code> manifest header. The bundle symbolic
+ * name together with a version must identify a unique bundle. The bundle
+ * symbolic name should be based on the reverse domain name naming
+ * convention like that used for java packages.
*
* <p>
* This method must continue to return this bundle's symbolic name while
* this bundle is in the <code>UNINSTALLED</code> state.
*
- * @return The symbolic name of this bundle.
+ * @return The symbolic name of this bundle or <code>null</code> if this
+ * bundle does not have a symbolic name.
* @since 1.3
*/
public String getSymbolicName();
/**
- * Loads the specified class using this bundle's classloader.
+ * Loads the specified class using this bundle's class loader.
*
* <p>
* If this bundle is a fragment bundle then this method must throw a
@@ -937,47 +953,49 @@
*
* @param name The name of the class to load.
* @return The Class object for the requested class.
- * @throws java.lang.ClassNotFoundException If no such class can be found or
+ * @throws ClassNotFoundException If no such class can be found or
* if this bundle is a fragment bundle or if the caller does not
* have the appropriate <code>AdminPermission[this,CLASS]</code>,
* and the Java Runtime Environment supports permissions.
- * @throws java.lang.IllegalStateException If this bundle has been
+ * @throws IllegalStateException If this bundle has been
* uninstalled.
* @since 1.3
*/
public Class loadClass(String name) throws ClassNotFoundException;
/**
- * Find the specified resources from this bundle.
+ * Find the specified resources from this bundle's class loader.
*
* This bundle's class loader is called to search for the specified
- * resources. If this bundle's state is <code>INSTALLED</code>, this
- * method must attempt to resolve this bundle before attempting to get the
+ * resources. If this bundle's state is <code>INSTALLED</code>, this method
+ * must attempt to resolve this bundle before attempting to get the
* specified resources. If this bundle cannot be resolved, then only this
* bundle must be searched for the specified resources. Imported packages
* cannot be searched when a bundle has not been resolved. If this bundle is
* a fragment bundle then <code>null</code> is returned.
+ * <p>
+ * Note: Jar and zip files are not required to include directory entries.
+ * URLs to directory entries will not be returned if the bundle contents do
+ * not contain directory entries.
*
* @param name The name of the resource. See
- * <code>java.lang.ClassLoader.getResources</code> for a
- * description of the format of a resource name.
+ * <code>ClassLoader.getResources</code> for a description of the
+ * format of a resource name.
* @return An enumeration of URLs to the named resources, or
* <code>null</code> if the resource could not be found or if this
* bundle is a fragment bundle or if the caller does not have the
- * appropriate <code>AdminPermission[this,RESOURCE]</code>, and
- * the Java Runtime Environment supports permissions.
- *
+ * appropriate <code>AdminPermission[this,RESOURCE]</code>, and the
+ * Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this bundle has been uninstalled.
+ * @throws IOException If there is an I/O error.
* @since 1.3
- * @throws java.lang.IllegalStateException If this bundle has been
- * uninstalled.
- * @throws java.io.IOException If there is an I/O error.
*/
- public Enumeration getResources(String name) throws IOException;
+ public Enumeration/* <URL> */getResources(String name) throws IOException;
/**
* Returns an Enumeration of all the paths (<code>String</code> objects)
* to entries within this bundle whose longest sub-path matches the
- * specified path. This bundle's classloader is not used to search for
+ * specified path. This bundle's class loader is not used to search for
* entries. Only the contents of this bundle are searched.
* <p>
* The specified path is always relative to the root of this bundle and may
@@ -987,6 +1005,10 @@
* Returned paths indicating subdirectory paths end with a "/".
* 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>
@@ -994,28 +1016,31 @@
* the caller does not have the appropriate
* <code>AdminPermission[this,RESOURCE]</code> and the Java
* Runtime Environment supports permissions.
- * @throws java.lang.IllegalStateException If this bundle has been
+ * @throws IllegalStateException If this bundle has been
* uninstalled.
* @since 1.3
*/
- public Enumeration getEntryPaths(String path);
+ public Enumeration/* <String> */getEntryPaths(String path);
/**
* Returns a URL to the entry at the specified path in this bundle. This
- * bundle's classloader is not used to search for the entry. Only the
+ * bundle's class loader is not used to search for the entry. Only the
* contents of this bundle are searched for the entry.
* <p>
* The specified path is always relative to the root of this bundle and may
* begin with "/". 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 java.lang.IllegalStateException If this bundle has been
+ * @throws IllegalStateException If this bundle has been
* uninstalled.
* @since 1.3
*/
@@ -1036,7 +1061,7 @@
/**
* Returns entries in this bundle and its attached fragments. This bundle's
- * classloader is not used to search for entries. Only the contents of this
+ * class loader is not used to search for entries. Only the contents of this
* bundle and its attached fragments are searched for the specified entries.
*
* If this bundle's state is <code>INSTALLED</code>, this method must
@@ -1064,36 +1089,43 @@
* Enumeration e = b.findEntries("OSGI-INF", "*.xml", true);
*
* // Find a specific localization file
- * Enumeration e = b.findEntries("OSGI-INF/l10n",
- * "bundle_nl_DU.properties",
- * false);
+ * 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 and it supports substring matching, as
- * specified in the Filter specification, using the wildcard
- * character ("*"). If null is specified, this is
- * equivalent to "*" and matches all files.
+ * 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
+ * <code>null</code> if an entry could not be found or if the caller
+ * does not have the appropriate
+ * <code>AdminPermission[this,RESOURCE]</code>, and the Java Runtime
+ * Environment supports permissions. The URLs are sorted such that
+ * entries from this bundle are returned first followed by the
+ * entries from attached fragments in ascending bundle id order. If
+ * this bundle is a fragment, then only matching entries in this
* fragment are returned.
+ * @throws IllegalStateException If this bundle has been uninstalled.
* @since 1.3
*/
- public Enumeration findEntries(String path, String filePattern,
+ public Enumeration/* <URL> */findEntries(String path, String filePattern,
boolean recurse);
/**
@@ -1111,10 +1143,52 @@
* @return A <code>BundleContext</code> for this bundle or
* <code>null</code> if this bundle has no valid
* <code>BundleContext</code>.
- * @throws java.lang.SecurityException If the caller does not have the
+ * @throws SecurityException If the caller does not have the
* appropriate <code>AdminPermission[this,CONTEXT]</code>, and
* the Java Runtime Environment supports permissions.
* @since 1.4
*/
public BundleContext getBundleContext();
+
+ /**
+ * Return the certificates for the signers of this bundle and the
+ * certificate chains for those signers.
+ *
+ * @param signersType If {@link #SIGNERS_ALL} is specified, then information
+ * on all signers of this bundle is returned. If
+ * {@link #SIGNERS_TRUSTED} is specified, then only information on
+ * the signers of this bundle trusted by the framework is returned.
+ * @return The <code>X509Certificate</code>s for the signers of this bundle
+ * and the <code>X509Certificate</code> chains for those signers.
+ * The keys of the <code>Map</code> are the
+ * <code>X509Certificate</code>s of the signers of this bundle. The
+ * value for a key is a <code>List</code> containing the
+ * <code>X509Certificate</code> chain for the signer. The first item
+ * in the <code>List</code> is the signer's
+ * <code>X509Certificate</code> which is then followed by the rest
+ * of the <code>X509Certificate</code> chain. The returned
+ * <code>Map</code> will be empty if there are no signers. The
+ * returned <code>Map</code> is the property of the caller who is
+ * free to modify it.
+ * @throws IllegalArgumentException If the specified
+ * <code>signersType</code> is not {@link #SIGNERS_ALL} or
+ * {@link #SIGNERS_TRUSTED}.
+ * @since 1.5
+ */
+ public Map/* <X509Certificate, List<X509Certificate>> */getSignerCertificates(
+ int signersType);
+
+ /**
+ * Returns the version of this bundle as specified by its
+ * <code>Bundle-Version</code> manifest header. If this bundle does not have a
+ * specified version then {@link Version#emptyVersion} is returned.
+ *
+ * <p>
+ * This method must continue to return this bundle's version while
+ * this bundle is in the <code>UNINSTALLED</code> state.
+ *
+ * @return The version of this bundle.
+ * @since 1.5
+ */
+ public Version getVersion();
}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleActivator.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleActivator.java
index a3344e6..56660b1 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundleActivator.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleActivator.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundleActivator.java,v 1.14 2007/02/21 16:49:05 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,7 +45,7 @@
* object can be created by <code>Class.newInstance()</code>.
*
* @NotThreadSafe
- * @version $Revision: 1.14 $
+ * @version $Revision: 6361 $
*/
public interface BundleActivator {
@@ -61,7 +59,7 @@
* This method must complete and return to its caller in a timely manner.
*
* @param context The execution context of the bundle being started.
- * @throws java.lang.Exception If this method throws an exception, this
+ * @throws Exception If this method throws an exception, this
* bundle is marked as stopped and the Framework will remove this
* bundle's listeners, unregister all services registered by this
* bundle, and release all services used by this bundle.
@@ -80,7 +78,7 @@
* This method must complete and return to its caller in a timely manner.
*
* @param context The execution context of the bundle being stopped.
- * @throws java.lang.Exception If this method throws an exception, the
+ * @throws Exception If this method throws an exception, the
* bundle is still marked as stopped, and the Framework will remove
* the bundle's listeners, unregister all services registered by the
* bundle, and release all services used by the bundle.
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleContext.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleContext.java
index c7d1768..44b3801 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundleContext.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleContext.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundleContext.java,v 1.22 2007/02/21 16:49:05 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -70,7 +68,7 @@
* objects and they are only valid within the Framework that created them.
*
* @ThreadSafe
- * @version $Revision: 1.22 $
+ * @version $Revision: 6781 $
*/
public interface BundleContext {
@@ -80,36 +78,15 @@
* method returns <code>null</code> if the property is not found.
*
* <p>
- * The Framework defines the following standard property keys:
- * </p>
- * <ul>
- * <li>{@link Constants#FRAMEWORK_VERSION} - The OSGi Framework version.
- * </li>
- * <li>{@link Constants#FRAMEWORK_VENDOR} - The Framework implementation
- * vendor.</li>
- * <li>{@link Constants#FRAMEWORK_LANGUAGE} - The language being used. See
- * ISO 639 for possible values.</li>
- * <li>{@link Constants#FRAMEWORK_OS_NAME} - The host computer operating
- * system.</li>
- * <li>{@link Constants#FRAMEWORK_OS_VERSION} - The host computer
- * operating system version number.</li>
- * <li>{@link Constants#FRAMEWORK_PROCESSOR} - The host computer processor
- * name.</li>
- * </ul>
- * <p>
- * All bundles must have permission to read these properties.
- *
- * <p>
- * Note: The last four standard properties are used by the
- * {@link Constants#BUNDLE_NATIVECODE} <code>Manifest</code> header's
- * matching algorithm for selecting native language code.
+ * All bundles must have permission to read properties whose names start
+ * with "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 java.lang.SecurityException If the caller does not have the
- * appropriate <code>PropertyPermission</code> to read the
- * property, and the Java Runtime Environment supports permissions.
+ * @return The value of the requested property, or <code>null</code> if the
+ * property is undefined.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>PropertyPermission</code> to read the property, and the
+ * Java Runtime Environment supports permissions.
*/
public String getProperty(String key);
@@ -119,53 +96,51 @@
*
* @return The <code>Bundle</code> object associated with this
* <code>BundleContext</code>.
- * @throws java.lang.IllegalStateException If this BundleContext is no
+ * @throws IllegalStateException If this BundleContext is no
* longer valid.
*/
public Bundle getBundle();
/**
- * Installs a bundle from the specified location string. A bundle is
- * obtained from <code>location</code> as interpreted by the Framework in
- * an implementation dependent manner.
+ * Installs a bundle from the specified <code>InputStream</code> object.
+ *
* <p>
- * Every installed bundle is uniquely identified by its location string,
- * typically in the form of a URL.
+ * If the specified <code>InputStream</code> is <code>null</code>, the
+ * Framework must create the <code>InputStream</code> from which to read the
+ * bundle by interpreting, in an implementation dependent manner, the
+ * specified <code>location</code>.
+ *
+ * <p>
+ * The specified <code>location</code> identifier will be used as the
+ * identity of the bundle. Every installed bundle is uniquely identified by
+ * its location identifier which is typically in the form of a URL.
*
* <p>
* The following steps are required to install a bundle:
* <ol>
- * <li>If a bundle containing the same location string is already
+ * <li>If a bundle containing the same location identifier is already
* installed, the <code>Bundle</code> object for that bundle is returned.
*
- * <li>The bundle's content is read from the location string. If this
- * fails, a {@link BundleException} is thrown.
- *
- * <li>The bundle's <code>Bundle-NativeCode</code> dependencies are
- * resolved. If this fails, a <code>BundleException</code> is thrown.
+ * <li>The bundle's content is read from the input stream. If this fails, a
+ * {@link BundleException} is thrown.
*
* <li>The bundle's associated resources are allocated. The associated
* resources minimally consist of a unique identifier and a persistent
* storage area if the platform has file system support. If this step fails,
* a <code>BundleException</code> is thrown.
*
- * <li>If the bundle has declared an Bundle-RequiredExecutionEnvironment
- * header, then the listed execution environments must be verified against
- * the installed execution environments. If none of the listed execution
- * environments match an installed execution environment, a
- * <code>BundleException</code> must be thrown.
- *
* <li>The bundle's state is set to <code>INSTALLED</code>.
*
* <li>A bundle event of type {@link BundleEvent#INSTALLED} is fired.
*
- * <li>The <code>Bundle</code> object for the newly or previously
- * installed bundle is returned.
+ * <li>The <code>Bundle</code> object for the newly or previously installed
+ * bundle is returned.
* </ol>
*
* <b>Postconditions, no exceptions thrown </b>
* <ul>
- * <li><code>getState()</code> in {<code>INSTALLED</code>,<code>RESOLVED</code>}.
+ * <li><code>getState()</code> in { <code>INSTALLED</code>,
+ * <code>RESOLVED</code> }.
* <li>Bundle has a unique ID.
* </ul>
* <b>Postconditions, when an exception is thrown </b>
@@ -174,48 +149,42 @@
* </ul>
*
* @param location The location identifier of the bundle to install.
- * @return The <code>Bundle</code> object of the installed bundle.
- * @throws BundleException If the installation failed.
- * @throws java.lang.SecurityException If the caller does not have the
- * appropriate <code>AdminPermission[installed bundle,LIFECYCLE]</code>, and the
- * Java Runtime Environment supports permissions.
- * @throws java.lang.IllegalStateException If this BundleContext is no
- * longer valid.
- */
- public Bundle installBundle(String location)
- throws BundleException;
-
- /**
- * Installs a bundle from the specified <code>InputStream</code> object.
- *
- * <p>
- * This method performs all of the steps listed in
- * <code>BundleContext.installBundle(String location)</code>, except that
- * the bundle's content will be read from the <code>InputStream</code>
- * object. The location identifier string specified will be used as the
- * identity of the bundle.
- *
- * <p>
- * This method must always close the <code>InputStream</code> object, even
- * if an exception is thrown.
- *
- * @param location The location identifier of the bundle to install.
* @param input The <code>InputStream</code> object from which this bundle
- * will be read.
+ * will be read or <code>null</code> to indicate the Framework must
+ * create the input stream from the specified location identifier.
+ * The input stream must always be closed when this method completes,
+ * even if an exception is thrown.
* @return The <code>Bundle</code> object of the installed bundle.
- * @throws BundleException If the provided stream cannot be read or the
+ * @throws BundleException If the input stream cannot be read or the
* installation failed.
- * @throws java.lang.SecurityException If the caller does not have the
- * appropriate <code>AdminPermission[installed bundle,LIFECYCLE]</code>, and the
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[installed bundle,LIFECYCLE]</code>, and the
* Java Runtime Environment supports permissions.
- * @throws java.lang.IllegalStateException If this BundleContext is no
- * longer valid.
- * @see #installBundle(java.lang.String)
+ * @throws IllegalStateException If this BundleContext is no longer valid.
*/
public Bundle installBundle(String location, InputStream input)
throws BundleException;
/**
+ * Installs a bundle from the specified <code>location</code> identifier.
+ *
+ * <p>
+ * This method performs the same function as calling
+ * {@link #installBundle(String,InputStream)} with the specified
+ * <code>location</code> identifier and a <code>null</code> InputStream.
+ *
+ * @param location The location identifier of the bundle to install.
+ * @return The <code>Bundle</code> object of the installed bundle.
+ * @throws BundleException If the installation failed.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[installed bundle,LIFECYCLE]</code>, and the
+ * Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
+ * @see #installBundle(String, InputStream)
+ */
+ public Bundle installBundle(String location) throws BundleException;
+
+ /**
* Returns the bundle with the specified identifier.
*
* @param id The identifier of the bundle to retrieve.
@@ -279,18 +248,16 @@
*
* @param listener The <code>ServiceListener</code> object to be added.
* @param filter The filter criteria.
- *
* @throws InvalidSyntaxException If <code>filter</code> contains an
* invalid filter string that cannot be parsed.
- * @throws java.lang.IllegalStateException If this BundleContext is no
+ * @throws IllegalStateException If this BundleContext is no
* longer valid.
- *
* @see ServiceEvent
* @see ServiceListener
* @see ServicePermission
*/
- public void addServiceListener(ServiceListener listener,
- String filter) throws InvalidSyntaxException;
+ public void addServiceListener(ServiceListener listener, String filter)
+ throws InvalidSyntaxException;
/**
* Adds the specified <code>ServiceListener</code> object to the context
@@ -303,9 +270,8 @@
* with <code>filter</code> set to <code>null</code>.
*
* @param listener The <code>ServiceListener</code> object to be added.
- * @throws java.lang.IllegalStateException If this BundleContext is no
+ * @throws IllegalStateException If this BundleContext is no
* longer valid.
- *
* @see #addServiceListener(ServiceListener, String)
*/
public void addServiceListener(ServiceListener listener);
@@ -319,7 +285,7 @@
* of listeners, this method does nothing.
*
* @param listener The <code>ServiceListener</code> to be removed.
- * @throws java.lang.IllegalStateException If this BundleContext is no
+ * @throws IllegalStateException If this BundleContext is no
* longer valid.
*/
public void removeServiceListener(ServiceListener listener);
@@ -335,13 +301,13 @@
* does nothing.
*
* @param listener The <code>BundleListener</code> to be added.
- * @throws java.lang.IllegalStateException If this BundleContext is no
+ * @throws IllegalStateException If this BundleContext is no
* longer valid.
- * @throws java.lang.SecurityException If listener is a
+ * @throws SecurityException If listener is a
* <code>SynchronousBundleListener</code> and the caller does not
- * have the appropriate <code>AdminPermission[context bundle,LISTENER]</code>,
- * and the Java Runtime Environment supports permissions.
- *
+ * have the appropriate
+ * <code>AdminPermission[context bundle,LISTENER]</code>, and the
+ * Java Runtime Environment supports permissions.
* @see BundleEvent
* @see BundleListener
*/
@@ -356,12 +322,13 @@
* of listeners, this method does nothing.
*
* @param listener The <code>BundleListener</code> object to be removed.
- * @throws java.lang.IllegalStateException If this BundleContext is no
+ * @throws IllegalStateException If this BundleContext is no
* longer valid.
- * @throws java.lang.SecurityException If listener is a
+ * @throws SecurityException If listener is a
* <code>SynchronousBundleListener</code> and the caller does not
- * have the appropriate <code>AdminPermission[context bundle,LISTENER]</code>,
- * and the Java Runtime Environment supports permissions.
+ * have the appropriate
+ * <code>AdminPermission[context bundle,LISTENER]</code>, and the
+ * Java Runtime Environment supports permissions.
*/
public void removeBundleListener(BundleListener listener);
@@ -376,9 +343,8 @@
* does nothing.
*
* @param listener The <code>FrameworkListener</code> object to be added.
- * @throws java.lang.IllegalStateException If this BundleContext is no
+ * @throws IllegalStateException If this BundleContext is no
* longer valid.
- *
* @see FrameworkEvent
* @see FrameworkListener
*/
@@ -394,7 +360,7 @@
*
* @param listener The <code>FrameworkListener</code> object to be
* removed.
- * @throws java.lang.IllegalStateException If this BundleContext is no
+ * @throws IllegalStateException If this BundleContext is no
* longer valid.
*/
public void removeFrameworkListener(FrameworkListener listener);
@@ -417,21 +383,21 @@
* <p>
* The following steps are required to register a service:
* <ol>
- * <li>If <code>service</code> is not a <code>ServiceFactory</code>,
- * an <code>IllegalArgumentException</code> is thrown if
- * <code>service</code> is not an <code>instanceof</code> all the
- * classes named.
- * <li>The Framework adds these service properties to the specified
- * <code>Dictionary</code> (which may be <code>null</code>): a property
- * named {@link Constants#SERVICE_ID} identifying the registration number of
- * the service and a property named {@link Constants#OBJECTCLASS} containing
- * all the specified classes. If any of these properties have already been
- * specified by the registering bundle, their values will be overwritten by
- * the Framework.
- * <li>The service is added to the Framework service registry and may now
- * be used by other bundles.
- * <li>A service event of type {@link ServiceEvent#REGISTERED} is
- * fired.
+ * <li>If <code>service</code> is not a <code>ServiceFactory</code>, an
+ * <code>IllegalArgumentException</code> is thrown if <code>service</code>
+ * is not an <code>instanceof</code> all the specified class names.
+ * <li>The Framework adds the following service properties to the service
+ * properties from the specified <code>Dictionary</code> (which may be
+ * <code>null</code>): <br/>
+ * A property named {@link Constants#SERVICE_ID} identifying the
+ * registration number of the service <br/>
+ * A property named {@link Constants#OBJECTCLASS} containing all the
+ * specified classes. <br/>
+ * Properties with these names in the specified <code>Dictionary</code> will
+ * be ignored.
+ * <li>The service is added to the Framework service registry and may now be
+ * used by other bundles.
+ * <li>A service event of type {@link ServiceEvent#REGISTERED} is fired.
* <li>A <code>ServiceRegistration</code> object for this registration is
* returned.
* </ol>
@@ -447,32 +413,24 @@
* Changes should not be made to this object after calling this
* method. To update the service's properties the
* {@link ServiceRegistration#setProperties} method must be called.
- * The set of properties may be <code>null</code> if the service
- * has no properties.
- *
+ * The set of properties may be <code>null</code> if the service has
+ * no properties.
* @return A <code>ServiceRegistration</code> object for use by the bundle
* registering the service to update the service's properties or to
* unregister the service.
- *
- * @throws java.lang.IllegalArgumentException If one of the following is
- * true:
+ * @throws IllegalArgumentException If one of the following is true:
* <ul>
- * <li><code>service</code> is <code>null</code>.
- * <li><code>service</code> is not a <code>ServiceFactory</code>
- * object and is not an instance of all the named classes in
- * <code>clazzes</code>.
- * <li><code>properties</code> contains case variants of the same
- * key name.
+ * <li><code>service</code> is <code>null</code>. <li><code>service
+ * </code> is not a <code>ServiceFactory</code> object and is not an
+ * instance of all the named classes in <code>clazzes</code>. <li>
+ * <code>properties</code> contains case variants of the same key
+ * name.
* </ul>
- *
- * @throws java.lang.SecurityException If the caller does not have the
+ * @throws SecurityException If the caller does not have the
* <code>ServicePermission</code> to register the service for all
* the named classes and the Java Runtime Environment supports
* permissions.
- *
- * @throws java.lang.IllegalStateException If this BundleContext is no
- * longer valid.
- *
+ * @throws IllegalStateException If this BundleContext is no longer valid.
* @see ServiceRegistration
* @see ServiceFactory
*/
@@ -485,161 +443,129 @@
*
* <p>
* This method is otherwise identical to
- * {@link #registerService(java.lang.String[], java.lang.Object,
- * java.util.Dictionary)} and is provided as a convenience when
- * <code>service</code> will only be registered under a single class name.
- * Note that even in this case the value of the service's
- * {@link Constants#OBJECTCLASS} property will be an array of strings,
- * rather than just a single string.
+ * {@link #registerService(String[], Object, Dictionary)} and is provided as
+ * a convenience when <code>service</code> will only be registered under a
+ * single class name. Note that even in this case the value of the service's
+ * {@link Constants#OBJECTCLASS} property will be an array of string, rather
+ * than just a single string.
*
* @param clazz The class name under which the service can be located.
* @param service The service object or a <code>ServiceFactory</code>
* object.
- * @param properties The properties for this service.
- *
+ * @param properties The properties for this service.
* @return A <code>ServiceRegistration</code> object for use by the bundle
* registering the service to update the service's properties or to
* unregister the service.
- *
- * @throws java.lang.IllegalStateException If this BundleContext is no
- * longer valid.
- * @see #registerService(java.lang.String[], java.lang.Object,
- * java.util.Dictionary)
+ * @throws IllegalStateException If this BundleContext is no longer valid.
+ * @see #registerService(String[], Object, Dictionary)
*/
- public ServiceRegistration registerService(String clazz,
- Object service, Dictionary properties);
+ public ServiceRegistration registerService(String clazz, Object service,
+ Dictionary properties);
/**
* Returns an array of <code>ServiceReference</code> objects. The returned
* array of <code>ServiceReference</code> objects contains services that
* were registered under the specified class, match the specified filter
- * criteria, and the packages for the class names under which the services
+ * expression, and the packages for the class names under which the services
* were registered match the context bundle's packages as defined in
* {@link ServiceReference#isAssignableTo(Bundle, String)}.
*
* <p>
- * The list is valid at the time of the call to this method, however since
+ * The list is valid at the time of the call to this method. However since
* the Framework is a very dynamic environment, services can be modified or
- * unregistered at anytime.
+ * unregistered at any time.
*
* <p>
- * <code>filter</code> is used to select the registered service whose
- * properties objects contain keys and values which satisfy the filter. See
- * {@link Filter} for a description of the filter string syntax.
+ * The specified <code>filter</code> expression is used to select the
+ * registered services whose service properties contain keys and values
+ * which satisfy the filter expression. See {@link Filter} for a description
+ * of the filter syntax. If the specified <code>filter</code> is
+ * <code>null</code>, all registered services are considered to match the
+ * filter. If the specified <code>filter</code> expression cannot be parsed,
+ * an {@link InvalidSyntaxException} will be thrown with a human readable
+ * message where the filter became unparsable.
*
* <p>
- * If <code>filter</code> is <code>null</code>, all registered services
- * are considered to match the filter. If <code>filter</code> cannot be
- * parsed, an {@link InvalidSyntaxException} will be thrown with a human
- * readable message where the filter became unparsable.
- *
- * <p>
- * The following steps are required to select a set of
- * <code>ServiceReference</code> objects:
- * <ol>
- * <li>If the filter string is not <code>null</code>, the filter string
- * is parsed and the set <code>ServiceReference</code> objects of
- * registered services that satisfy the filter is produced. If the filter
- * string is <code>null</code>, then all registered services are
- * considered to satisfy the filter.
- * <li>If the Java Runtime Environment supports permissions, the set of
- * <code>ServiceReference</code> objects produced by the previous step is
- * reduced by checking that the caller has the
- * <code>ServicePermission</code> to get at least one of the class names
- * under which the service was registered. If the caller does not have the
- * correct permission for a particular <code>ServiceReference</code>
- * object, then it is removed from the set.
- * <li>If <code>clazz</code> is not <code>null</code>, the set is
- * further reduced to those services that are an <code>instanceof</code>
- * and were registered under the specified class. The complete list of
- * classes of which a service is an instance and which were specified when
- * the service was registered is available from the service's
- * {@link Constants#OBJECTCLASS} property.
- * <li>The set is reduced one final time by cycling through each
- * <code>ServiceReference</code> object and calling
+ * The result is an array of <code>ServiceReference</code> objects for all
+ * services that meet all of the following conditions:
+ * <ul>
+ * <li>If the specified class name, <code>clazz</code>, is not
+ * <code>null</code>, the service must have been registered with the
+ * specified class name. The complete list of class names with which a
+ * service was registered is available from the service's
+ * {@link Constants#OBJECTCLASS objectClass} property.
+ * <li>If the specified <code>filter</code> is not <code>null</code>, the
+ * filter expression must match the service.
+ * <li>If the Java Runtime Environment supports permissions, the caller must
+ * have <code>ServicePermission</code> with the <code>GET</code> action for
+ * at least one of the class names under which the service was registered.
+ * <li>For each class name with which the service was registered, calling
* {@link ServiceReference#isAssignableTo(Bundle, String)} with the context
- * bundle and each class name under which the <code>ServiceReference</code>
- * object was registered. For any given <code>ServiceReference</code>
- * object, if any call to
- * {@link ServiceReference#isAssignableTo(Bundle, String)} returns
- * <code>false</code>, then it is removed from the set of
- * <code>ServiceReference</code> objects.
- * <li>An array of the remaining <code>ServiceReference</code> objects is
- * returned.
- * </ol>
+ * bundle and the class name on the service's <code>ServiceReference</code>
+ * object must return <code>true</code>
+ * </ul>
*
* @param clazz The class name with which the service was registered or
* <code>null</code> for all services.
- * @param filter The filter criteria.
+ * @param filter The filter expression or <code>null</code> for all
+ * services.
* @return An array of <code>ServiceReference</code> objects or
- * <code>null</code> if no services are registered which satisfy
- * the search.
- * @throws InvalidSyntaxException If <code>filter</code> contains an
- * invalid filter string that cannot be parsed.
- * @throws java.lang.IllegalStateException If this BundleContext is no
- * longer valid.
+ * <code>null</code> if no services are registered which satisfy the
+ * search.
+ * @throws InvalidSyntaxException If the specified <code>filter</code>
+ * contains an invalid filter expression that cannot be parsed.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
*/
- public ServiceReference[] getServiceReferences(String clazz,
- String filter) throws InvalidSyntaxException;
+ public ServiceReference[] getServiceReferences(String clazz, String filter)
+ throws InvalidSyntaxException;
/**
* Returns an array of <code>ServiceReference</code> objects. The returned
* array of <code>ServiceReference</code> objects contains services that
* were registered under the specified class and match the specified filter
- * criteria.
+ * expression.
*
* <p>
- * The list is valid at the time of the call to this method, however since
+ * The list is valid at the time of the call to this method. However since
* the Framework is a very dynamic environment, services can be modified or
- * unregistered at anytime.
+ * unregistered at any time.
*
* <p>
- * <code>filter</code> is used to select the registered service whose
- * properties objects contain keys and values which satisfy the filter. See
- * {@link Filter} for a description of the filter string syntax.
+ * The specified <code>filter</code> expression is used to select the
+ * registered services whose service properties contain keys and values
+ * which satisfy the filter expression. See {@link Filter} for a description
+ * of the filter syntax. If the specified <code>filter</code> is
+ * <code>null</code>, all registered services are considered to match the
+ * filter. If the specified <code>filter</code> expression cannot be parsed,
+ * an {@link InvalidSyntaxException} will be thrown with a human readable
+ * message where the filter became unparsable.
*
* <p>
- * If <code>filter</code> is <code>null</code>, all registered services
- * are considered to match the filter. If <code>filter</code> cannot be
- * parsed, an {@link InvalidSyntaxException} will be thrown with a human
- * readable message where the filter became unparsable.
- *
- * <p>
- * The following steps are required to select a set of
- * <code>ServiceReference</code> objects:
- * <ol>
- * <li>If the filter string is not <code>null</code>, the filter string
- * is parsed and the set <code>ServiceReference</code> objects of
- * registered services that satisfy the filter is produced. If the filter
- * string is <code>null</code>, then all registered services are
- * considered to satisfy the filter.
- * <li>If the Java Runtime Environment supports permissions, the set of
- * <code>ServiceReference</code> objects produced by the previous step is
- * reduced by checking that the caller has the
- * <code>ServicePermission</code> to get at least one of the class names
- * under which the service was registered. If the caller does not have the
- * correct permission for a particular <code>ServiceReference</code>
- * object, then it is removed from the set.
- * <li>If <code>clazz</code> is not <code>null</code>, the set is
- * further reduced to those services that are an <code>instanceof</code>
- * and were registered under the specified class. The complete list of
- * classes of which a service is an instance and which were specified when
- * the service was registered is available from the service's
- * {@link Constants#OBJECTCLASS} property.
- * <li>An array of the remaining <code>ServiceReference</code> objects is
- * returned.
- * </ol>
+ * The result is an array of <code>ServiceReference</code> objects for all
+ * services that meet all of the following conditions:
+ * <ul>
+ * <li>If the specified class name, <code>clazz</code>, is not
+ * <code>null</code>, the service must have been registered with the
+ * specified class name. The complete list of class names with which a
+ * service was registered is available from the service's
+ * {@link Constants#OBJECTCLASS objectClass} property.
+ * <li>If the specified <code>filter</code> is not <code>null</code>, the
+ * filter expression must match the service.
+ * <li>If the Java Runtime Environment supports permissions, the caller must
+ * have <code>ServicePermission</code> with the <code>GET</code> action for
+ * at least one of the class names under which the service was registered.
+ * </ul>
*
* @param clazz The class name with which the service was registered or
* <code>null</code> for all services.
- * @param filter The filter criteria.
+ * @param filter The filter expression or <code>null</code> for all
+ * services.
* @return An array of <code>ServiceReference</code> objects or
- * <code>null</code> if no services are registered which satisfy
- * the search.
- * @throws InvalidSyntaxException If <code>filter</code> contains an
- * invalid filter string that cannot be parsed.
- * @throws java.lang.IllegalStateException If this BundleContext is no
- * longer valid.
+ * <code>null</code> if no services are registered which satisfy the
+ * search.
+ * @throws InvalidSyntaxException If the specified <code>filter</code>
+ * contains an invalid filter expression that cannot be parsed.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
* @since 1.3
*/
public ServiceReference[] getAllServiceReferences(String clazz,
@@ -650,14 +576,14 @@
* implements and was registered under the specified class.
*
* <p>
- * This <code>ServiceReference</code> object is valid at the time of the
- * call to this method, however as the Framework is a very dynamic
- * environment, services can be modified or unregistered at anytime.
+ * The returned <code>ServiceReference</code> object is valid at the time of
+ * the call to this method. However as the Framework is a very dynamic
+ * environment, services can be modified or unregistered at any time.
*
* <p>
* This method is the same as calling
* {@link BundleContext#getServiceReferences(String, String)} with a
- * <code>null</code> filter string. It is provided as a convenience for
+ * <code>null</code> filter expression. It is provided as a convenience for
* when the caller is interested in any service that implements the
* specified class.
* <p>
@@ -669,16 +595,16 @@
* service that was registered first is returned.
*
* @param clazz The class name with which the service was registered.
- * @return A <code>ServiceReference</code> object, or <code>null</code>
- * if no services are registered which implement the named class.
- * @throws java.lang.IllegalStateException If this BundleContext is no
- * longer valid.
+ * @return A <code>ServiceReference</code> object, or <code>null</code> if
+ * no services are registered which implement the named class.
+ * @throws IllegalStateException If this BundleContext is no longer valid.
* @see #getServiceReferences(String, String)
*/
public ServiceReference getServiceReference(String clazz);
/**
- * Returns the specified service object for a service.
+ * Returns the service object referenced by the specified
+ * <code>ServiceReference</code> object.
* <p>
* A bundle's use of a service is tracked by the bundle's use count of that
* service. Each time a service's service object is returned by
@@ -697,8 +623,7 @@
* <p>
* The following steps are required to get the service object:
* <ol>
- * <li>If the service has been unregistered, <code>null</code> is
- * returned.
+ * <li>If the service has been unregistered, <code>null</code> is returned.
* <li>The context bundle's use count for this service is incremented by
* one.
* <li>If the context bundle's use count for the service is currently one
@@ -710,25 +635,31 @@
* for the service is greater than zero, subsequent calls to get the
* services's service object for the context bundle will return the cached
* service object. <br>
- * If the service object returned by the <code>ServiceFactory</code>
- * object is not an <code>instanceof</code> all the classes named when the
- * service was registered or the <code>ServiceFactory</code> object throws
- * an exception, <code>null</code> is returned and a Framework event of
- * type {@link FrameworkEvent#ERROR} is fired.
+ * If the service object returned by the <code>ServiceFactory</code> object
+ * is not an <code>instanceof</code> all the classes named when the service
+ * was registered or the <code>ServiceFactory</code> object throws an
+ * exception, <code>null</code> is returned and a Framework event of type
+ * {@link FrameworkEvent#ERROR} containing a {@link ServiceException}
+ * describing the error is fired.
* <li>The service object for the service is returned.
* </ol>
*
* @param reference A reference to the service.
* @return A service object for the service associated with
- * <code>reference</code> or <code>null</code> if the service is
- * not registered or does not implement the classes under which it
- * was registered in the case of a <code>ServiceFactory</code>.
- * @throws java.lang.SecurityException If the caller does not have the
- * <code>ServicePermission</code> to get the service using at
- * least one of the named classes the service was registered under
- * and the Java Runtime Environment supports permissions.
- * @throws java.lang.IllegalStateException If this BundleContext is no
+ * <code>reference</code> or <code>null</code> if the service is not
+ * registered, the service object returned by a
+ * <code>ServiceFactory</code> does not implement the classes under
+ * which it was registered or the <code>ServiceFactory</code> threw
+ * an exception.
+ * @throws SecurityException If the caller does not have the
+ * <code>ServicePermission</code> to get the service using at least
+ * one of the named classes the service was registered under and the
+ * Java Runtime Environment supports permissions.
+ * @throws IllegalStateException If this BundleContext is no
* longer valid.
+ * @throws IllegalArgumentException If the specified
+ * <code>ServiceReference</code> was not created by the same
+ * framework instance as this <code>BundleContext</code>.
* @see #ungetService(ServiceReference)
* @see ServiceFactory
*/
@@ -754,8 +685,8 @@
* <li>The context bundle's use count for this service is decremented by
* one.
* <li>If the context bundle's use count for the service is currently zero
- * and the service was registered with a <code>ServiceFactory</code>
- * object, the
+ * and the service was registered with a <code>ServiceFactory</code> object,
+ * the
* {@link ServiceFactory#ungetService(Bundle, ServiceRegistration, Object)}
* method is called to release the service object for the context bundle.
* <li><code>true</code> is returned.
@@ -765,8 +696,11 @@
* @return <code>false</code> if the context bundle's use count for the
* service is zero or if the service has been unregistered;
* <code>true</code> otherwise.
- * @throws java.lang.IllegalStateException If this BundleContext is no
+ * @throws IllegalStateException If this BundleContext is no
* longer valid.
+ * @throws IllegalArgumentException If the specified
+ * <code>ServiceReference</code> was not created by the same
+ * framework instance as this <code>BundleContext</code>.
* @see #getService
* @see ServiceFactory
*/
@@ -794,14 +728,14 @@
* @return A <code>File</code> object that represents the requested file
* or <code>null</code> if the platform does not have file system
* support.
- * @throws java.lang.IllegalStateException If this BundleContext is no
+ * @throws IllegalStateException If this BundleContext is no
* longer valid.
*/
public File getDataFile(String filename);
/**
- * Creates a <code>Filter</code> object. This <code>Filter</code> object
- * may be used to match a <code>ServiceReference</code> object or a
+ * Creates a <code>Filter</code> object. This <code>Filter</code> object may
+ * be used to match a <code>ServiceReference</code> object or a
* <code>Dictionary</code> object.
*
* <p>
@@ -810,16 +744,13 @@
*
* @param filter The filter string.
* @return A <code>Filter</code> object encapsulating the filter string.
- * @throws InvalidSyntaxException If <code>filter</code> contains an
- * invalid filter string that cannot be parsed.
+ * @throws InvalidSyntaxException If <code>filter</code> contains an invalid
+ * filter string that cannot be parsed.
* @throws NullPointerException If <code>filter</code> is null.
- * @throws java.lang.IllegalStateException If this BundleContext is no
- * longer valid.
- *
- * @since 1.1
+ * @throws IllegalStateException If this BundleContext is no longer valid.
* @see "Framework specification for a description of the filter string syntax."
* @see FrameworkUtil#createFilter(String)
+ * @since 1.1
*/
- public Filter createFilter(String filter)
- throws InvalidSyntaxException;
+ public Filter createFilter(String filter) throws InvalidSyntaxException;
}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleEvent.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleEvent.java
index 29f6fa0..7a8fb8d 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundleEvent.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleEvent.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundleEvent.java,v 1.19 2007/02/20 00:14:12 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +32,7 @@
* @Immutable
* @see BundleListener
* @see SynchronousBundleListener
- * @version $Revision: 1.19 $
+ * @version $Revision: 6542 $
*/
public class BundleEvent extends EventObject {
@@ -51,8 +49,6 @@
/**
* The bundle has been installed.
- * <p>
- * The value of <code>INSTALLED</code> is 0x00000001.
*
* @see BundleContext#installBundle(String)
*/
@@ -64,8 +60,6 @@
* The bundle's
* {@link BundleActivator#start(BundleContext) BundleActivator start} method
* has been executed if the bundle has a bundle activator class.
- * <p>
- * The value of <code>STARTED</code> is 0x00000002.
*
* @see Bundle#start()
*/
@@ -77,8 +71,6 @@
* The bundle's
* {@link BundleActivator#stop(BundleContext) BundleActivator stop} method
* has been executed if the bundle has a bundle activator class.
- * <p>
- * The value of <code>STOPPED</code> is 0x00000004.
*
* @see Bundle#stop()
*/
@@ -86,8 +78,6 @@
/**
* The bundle has been updated.
- * <p>
- * The value of <code>UPDATED</code> is 0x00000008.
*
* @see Bundle#update()
*/
@@ -95,8 +85,6 @@
/**
* The bundle has been uninstalled.
- * <p>
- * The value of <code>UNINSTALLED</code> is 0x00000010.
*
* @see Bundle#uninstall
*/
@@ -104,8 +92,6 @@
/**
* The bundle has been resolved.
- * <p>
- * The value of <code>RESOLVED</code> is 0x00000020.
*
* @see Bundle#RESOLVED
* @since 1.3
@@ -114,8 +100,6 @@
/**
* The bundle has been unresolved.
- * <p>
- * The value of <code>UNRESOLVED</code> is 0x00000040.
*
* @see Bundle#INSTALLED
* @since 1.3
@@ -130,8 +114,6 @@
* is about to be called if the bundle has a bundle activator class. This
* event is only delivered to {@link SynchronousBundleListener}s. It is not
* delivered to <code>BundleListener</code>s.
- * <p>
- * The value of <code>STARTING</code> is 0x00000080.
*
* @see Bundle#start()
* @since 1.3
@@ -146,8 +128,6 @@
* is about to be called if the bundle has a bundle activator class. This
* event is only delivered to {@link SynchronousBundleListener}s. It is not
* delivered to <code>BundleListener</code>s.
- * <p>
- * The value of <code>STOPPING</code> is 0x00000100.
*
* @see Bundle#stop()
* @since 1.3
@@ -163,8 +143,6 @@
* <code>BundleContext</code>. This event is only delivered to
* {@link SynchronousBundleListener}s. It is not delivered to
* <code>BundleListener</code>s.
- * <p>
- * The value of <code>LAZY_ACTIVATION</code> is 0x00000200.
*
* @since 1.4
*/
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleException.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleException.java
index 2203e0f..500d147 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundleException.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleException.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundleException.java,v 1.15 2006/07/11 13:15:54 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,84 +21,198 @@
* occurred.
*
* <p>
- * <code>BundleException</code> object is created by the Framework to denote
+ * A <code>BundleException</code> object is created by the Framework to denote
* an exception condition in the lifecycle of a bundle.
* <code>BundleException</code>s should not be created by bundle developers.
+ * A type code is used to identify the exception type for future extendability.
*
* <p>
- * This exception is updated to conform to the general purpose exception
- * chaining mechanism.
+ * OSGi Alliance reserves the right to extend the set of types.
*
- * @version $Revision: 1.15 $
+ * <p>
+ * This exception conforms to the general purpose exception chaining mechanism.
+ *
+ * @version $Revision: 6083 $
*/
public class BundleException extends Exception {
- static final long serialVersionUID = 3571095144220455665L;
+ static final long serialVersionUID = 3571095144220455665L;
/**
- * Nested exception.
+ * Type of bundle exception.
+ *
+ * @since 1.5
*/
- private final Throwable cause;
+ private final int type;
/**
- * Creates a <code>BundleException</code> that wraps another exception.
+ * No exception type is unspecified.
+ *
+ * @since 1.5
+ */
+ public static final int UNSPECIFIED = 0;
+ /**
+ * The operation was unsupported.
+ *
+ * @since 1.5
+ */
+ public static final int UNSUPPORTED_OPERATION = 1;
+ /**
+ * The operation was invalid.
+ *
+ * @since 1.5
+ */
+ public static final int INVALID_OPERATION = 2;
+ /**
+ * The bundle manifest was in error.
+ *
+ * @since 1.5
+ */
+ public static final int MANIFEST_ERROR = 3;
+ /**
+ * The bundle was not resolved.
+ *
+ * @since 1.5
+ */
+ public static final int RESOLVE_ERROR = 4;
+ /**
+ * The bundle activator was in error.
+ *
+ * @since 1.5
+ */
+ public static final int ACTIVATOR_ERROR = 5;
+ /**
+ * The operation failed due to insufficient permissions.
+ *
+ * @since 1.5
+ */
+ public static final int SECURITY_ERROR = 6;
+ /**
+ * The operation failed to complete the requested lifecycle state change.
+ *
+ * @since 1.5
+ */
+ public static final int STATECHANGE_ERROR = 7;
+
+ /**
+ * The bundle could not be resolved due to an error with the
+ * Bundle-NativeCode header.
+ *
+ * @since 1.5
+ */
+ public static final int NATIVECODE_ERROR = 8;
+
+ /**
+ * The install or update operation failed because another
+ * already installed bundle has the same symbolic name and version.
+ * @since 1.5
+ */
+ public static final int DUPLICATE_BUNDLE_ERROR = 9;
+
+ /**
+ * The start transient operation failed because the start level of the
+ * bundle is greater than the current framework start level
+ *
+ * @since 1.5
+ */
+ public static final int START_TRANSIENT_ERROR = 10;
+
+ /**
+ * Creates a <code>BundleException</code> with the specified message and
+ * exception cause.
*
* @param msg The associated message.
* @param cause The cause of this exception.
*/
public BundleException(String msg, Throwable cause) {
- super(msg);
- this.cause = cause;
+ this(msg, UNSPECIFIED, cause);
}
/**
- * Creates a <code>BundleException</code> object with the specified
- * message.
+ * Creates a <code>BundleException</code> with the specified message.
*
* @param msg The message.
*/
public BundleException(String msg) {
- super(msg);
- this.cause = null;
+ this(msg, UNSPECIFIED);
}
/**
- * Returns any nested exceptions included in this exception.
+ * Creates a <code>BundleException</code> with the specified message, type
+ * and exception cause.
+ *
+ * @param msg The associated message.
+ * @param type The type for this exception.
+ * @param cause The cause of this exception.
+ * @since 1.5
+ */
+ public BundleException(String msg, int type, Throwable cause) {
+ super(msg, cause);
+ this.type = type;
+ }
+
+ /**
+ * Creates a <code>BundleException</code> with the specified message and
+ * type.
+ *
+ * @param msg The message.
+ * @param type The type for this exception.
+ * @since 1.5
+ */
+ public BundleException(String msg, int type) {
+ super(msg);
+ this.type = type;
+ }
+
+ /**
+ * Returns the cause of this exception or <code>null</code> if no cause was
+ * specified when this exception was created.
*
* <p>
* This method predates the general purpose exception chaining mechanism.
- * The {@link #getCause()} method is now the preferred means of obtaining
- * this information.
+ * The <code>getCause()</code> method is now the preferred means of
+ * obtaining this information.
*
- * @return The nested exception; <code>null</code> if there is no nested
- * exception.
+ * @return The result of calling <code>getCause()</code>.
*/
public Throwable getNestedException() {
- return cause;
+ return getCause();
}
/**
- * Returns the cause of this exception or <code>null</code> if no cause
- * was specified when this exception was created.
+ * Returns the cause of this exception or <code>null</code> if no cause was
+ * set.
*
- * @return The cause of this exception or <code>null</code> if no cause
- * was specified.
+ * @return The cause of this exception or <code>null</code> if no cause was
+ * set.
* @since 1.3
*/
- public Throwable getCause() {
- return cause;
+ public Throwable getCause() {
+ return super.getCause();
}
/**
- * The cause of this exception can only be set when constructed.
+ * Initializes the cause of this exception to the specified value.
*
- * @param cause Cause of the exception.
- * @return This object.
- * @throws java.lang.IllegalStateException This method will always throw an
- * <code>IllegalStateException</code> since the cause of this
- * exception can only be set when constructed.
+ * @param cause The cause of this exception.
+ * @return This exception.
+ * @throws IllegalArgumentException If the specified cause is this
+ * exception.
+ * @throws IllegalStateException If the cause of this exception has already
+ * been set.
* @since 1.3
*/
public Throwable initCause(Throwable cause) {
- throw new IllegalStateException();
+ return super.initCause(cause);
+ }
+
+ /**
+ * Returns the type for this exception or <code>UNSPECIFIED</code> if the
+ * type was unspecified or unknown.
+ *
+ * @return The type of this exception.
+ * @since 1.5
+ */
+ public int getType() {
+ return type;
}
}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleListener.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleListener.java
index e9bc6d4..9dd7151 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundleListener.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleListener.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundleListener.java,v 1.13 2007/02/21 16:49:05 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +34,7 @@
*
* @see BundleEvent
* @NotThreadSafe
- * @version $Revision: 1.13 $
+ * @version $Revision: 5673 $
*/
public interface BundleListener extends EventListener {
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundlePermission.java b/org.osgi.core/src/main/java/org/osgi/framework/BundlePermission.java
index c313bf7..8677e69 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/BundlePermission.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundlePermission.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/BundlePermission.java,v 1.16 2007/02/20 00:06:02 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,32 +17,46 @@
package org.osgi.framework;
import java.io.IOException;
-import java.security.*;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.Hashtable;
+import java.util.Map;
/**
* A bundle's authority to require or provide a bundle or to receive or attach
* fragments.
*
* <p>
- * A bundle symbolic name defines a unique fully qualified name.
- * <p>
- * For example:
+ * A bundle symbolic name defines a unique fully qualified name. Wildcards may
+ * be used.
*
* <pre>
- * <code>
+ * name ::= <symbolic name> | <symbolic name ending in ".*"> | *
+ * </pre>
+ *
+ * Examples:
+ *
+ * <pre>
* org.osgi.example.bundle
- * </code>
+ * org.osgi.example.*
+ * *
* </pre>
*
* <p>
- * <code>BundlePermission</code> has four actions: <code>PROVIDE</code>,
- * <code>REQUIRE</code>,<code>HOST</code>, and <code>FRAGMENT</code>.
- * The <code>PROVIDE</code> action implies the <code>REQUIRE</code> action.
+ * <code>BundlePermission</code> has four actions: <code>provide</code>,
+ * <code>require</code>,<code>host</code>, and <code>fragment</code>. The
+ * <code>provide</code> action implies the <code>require</code> action.
*
* @since 1.3
- * @version $Revision: 1.16 $
+ * @ThreadSafe
+ * @version $Revision: 6860 $
*/
public final class BundlePermission extends BasicPermission {
@@ -52,12 +64,14 @@
private static final long serialVersionUID = 3257846601685873716L;
/**
- * The action string <code>provide</code>.
+ * The action string <code>provide</code>. The <code>provide</code> action
+ * implies the <code>require</code> action.
*/
public final static String PROVIDE = "provide";
/**
- * The action string <code>require</code>.
+ * The action string <code>require</code>. The <code>require</code> action
+ * is implied by the <code>provide</code> action.
*/
public final static String REQUIRE = "require";
@@ -79,18 +93,18 @@
| ACTION_REQUIRE
| ACTION_HOST
| ACTION_FRAGMENT;
- private final static int ACTION_NONE = 0;
+ final static int ACTION_NONE = 0;
/**
* The actions mask.
*/
- private transient int action_mask = ACTION_NONE;
+ private transient int action_mask;
/**
* The actions in canonical form.
*
* @serial
*/
- private String actions = null;
+ private volatile String actions = null;
/**
* Defines the authority to provide and/or require and or specify a host
@@ -104,24 +118,23 @@
* for that symbolic name; a bundle that specifies a fragment host must have
* the appropriate <code>BundlePermission</code> for that symbolic name.
*
- * @param symbolicName the bundle symbolic name.
- * @param actions <code>PROVIDE</code>,<code>REQUIRE</code>,
- * <code>HOST</code>,<code>FRAGMENT</code> (canonical order).
+ * @param symbolicName The bundle symbolic name.
+ * @param actions <code>provide</code>,<code>require</code>,
+ * <code>host</code>,<code>fragment</code> (canonical order).
*/
-
public BundlePermission(String symbolicName, String actions) {
- this(symbolicName, getMask(actions));
+ this(symbolicName, parseActions(actions));
}
/**
- * Bundle private constructor used by BundlePermissionCollection.
+ * Package private constructor used by BundlePermissionCollection.
*
* @param symbolicName the bundle symbolic name
* @param mask the action mask
*/
BundlePermission(String symbolicName, int mask) {
super(symbolicName);
- init(mask);
+ setTransients(mask);
}
/**
@@ -129,7 +142,7 @@
*
* @param mask
*/
- private void init(int mask) {
+ private synchronized void setTransients(int mask) {
if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
throw new IllegalArgumentException("invalid action string");
}
@@ -138,25 +151,36 @@
}
/**
+ * Returns the current action mask.
+ * <p>
+ * Used by the BundlePermissionCollection class.
+ *
+ * @return Current action mask.
+ */
+ synchronized int getActionsMask() {
+ return action_mask;
+ }
+
+ /**
* Parse action string into action mask.
*
* @param actions Action string.
* @return action mask.
*/
- private static int getMask(String actions) {
+ private static int parseActions(String actions) {
boolean seencomma = false;
int mask = ACTION_NONE;
if (actions == null) {
- return (mask);
+ return mask;
}
char[] a = actions.toCharArray();
int i = a.length - 1;
if (i < 0)
- return (mask);
+ return mask;
while (i != -1) {
char c;
@@ -224,7 +248,7 @@
switch (a[i - matchlen]) {
case ',' :
seencomma = true;
- /* FALLTHROUGH */
+ /* FALLTHROUGH */
case ' ' :
case '\r' :
case '\n' :
@@ -246,7 +270,7 @@
throw new IllegalArgumentException("invalid permission: " + actions);
}
- return (mask);
+ return mask;
}
/**
@@ -268,21 +292,20 @@
* x.y,"provide" -> x.y.z, "provide" is false
* </pre>
*
- * @param p The target permission to interrogate.
- * @return <code>true</code> if the specified
- * <code>BundlePermission</code> action is implied by this object;
- * <code>false</code> otherwise.
+ * @param p The requested permission.
+ * @return <code>true</code> if the specified <code>BundlePermission</code>
+ * action is implied by this object; <code>false</code> otherwise.
*/
-
public boolean implies(Permission p) {
- if (p instanceof BundlePermission) {
- BundlePermission target = (BundlePermission) p;
-
- return (((action_mask & target.action_mask) == target.action_mask) && super
- .implies(p));
+ if (!(p instanceof BundlePermission)) {
+ return false;
}
+ BundlePermission requested = (BundlePermission) p;
- return (false);
+ final int effective = getActionsMask();
+ final int desired = requested.getActionsMask();
+ return ((effective & desired) == desired)
+ && super.implies(requested);
}
/**
@@ -291,13 +314,15 @@
*
* <p>
* Always returns present <code>BundlePermission</code> actions in the
- * following order: <code>PROVIDE</code>,<code>REQUIRE</code>,
- * <code>HOST</code>,<code>FRAGMENT.
- * @return Canonical string representation of the <code>BundlePermission</code> actions.
+ * following order: <code>provide</code>, <code>require</code>,
+ * <code>host</code>, <code>fragment</code>.
+ *
+ * @return Canonical string representation of the <code>BundlePermission
+ * </code> actions.
*/
-
public String getActions() {
- if (actions == null) {
+ String result = actions;
+ if (result == null) {
StringBuffer sb = new StringBuffer();
boolean comma = false;
@@ -326,10 +351,9 @@
sb.append(FRAGMENT);
}
- actions = sb.toString();
+ actions = result = sb.toString();
}
-
- return (actions);
+ return result;
}
/**
@@ -339,7 +363,7 @@
* @return A new <code>PermissionCollection</code> object.
*/
public PermissionCollection newPermissionCollection() {
- return (new BundlePermissionCollection());
+ return new BundlePermissionCollection();
}
/**
@@ -352,22 +376,23 @@
* @param obj The object to test for equality with this
* <code>BundlePermission</code> object.
* @return <code>true</code> if <code>obj</code> is a
- * <code>BundlePermission</code>, and has the same bundle
- * symbolic name and actions as this <code>BundlePermission</code>
- * object; <code>false</code> otherwise.
+ * <code>BundlePermission</code>, and has the same bundle symbolic
+ * name and actions as this <code>BundlePermission</code> object;
+ * <code>false</code> otherwise.
*/
public boolean equals(Object obj) {
if (obj == this) {
- return (true);
+ return true;
}
if (!(obj instanceof BundlePermission)) {
- return (false);
+ return false;
}
- BundlePermission p = (BundlePermission) obj;
+ BundlePermission bp = (BundlePermission) obj;
- return ((action_mask == p.action_mask) && getName().equals(p.getName()));
+ return (getActionsMask() == bp.getActionsMask())
+ && getName().equals(bp.getName());
}
/**
@@ -375,20 +400,10 @@
*
* @return A hash code value for this object.
*/
-
public int hashCode() {
- return (getName().hashCode() ^ getActions().hashCode());
- }
-
- /**
- * Returns the current action mask.
- * <p>
- * Used by the BundlePermissionCollection class.
- *
- * @return Current action mask.
- */
- int getMask() {
- return (action_mask);
+ int h = 31 * 17 + getName().hashCode();
+ h = 31 * h + getActions().hashCode();
+ return h;
}
/**
@@ -396,7 +411,6 @@
* <code>BundlePermission</code> object to a stream. The actions are
* serialized, and the superclass takes care of the name.
*/
-
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws IOException {
// Write out the actions. The superclass takes care of the name
@@ -414,7 +428,7 @@
throws IOException, ClassNotFoundException {
// Read in the action, then initialize the rest
s.defaultReadObject();
- init(getMask(actions));
+ setTransients(parseActions(actions));
}
}
@@ -427,23 +441,20 @@
*/
final class BundlePermissionCollection extends PermissionCollection {
-
- /**
- * Comment for <code>serialVersionUID</code>
- */
private static final long serialVersionUID = 3258407326846433079L;
/**
* Table of permissions.
*
- * @serial
+ * @GuardedBy this
*/
- private Hashtable permissions;
+ private transient Map permissions;
/**
* Boolean saying if "*" is in the collection.
*
* @serial
+ * @GuardedBy this
*/
private boolean all_allowed;
@@ -451,53 +462,51 @@
* Create an empty BundlePermissions object.
*
*/
-
public BundlePermissionCollection() {
- permissions = new Hashtable();
+ permissions = new HashMap();
all_allowed = false;
}
/**
- * Adds a permission to the <code>BundlePermission</code> objects. The key
- * for the hash is the symbolic name.
+ * Add a permission to this permission collection.
*
* @param permission The <code>BundlePermission</code> object to add.
- *
* @throws IllegalArgumentException If the permission is not a
* <code>BundlePermission</code> instance.
* @throws SecurityException If this <code>BundlePermissionCollection</code>
* object has been marked read-only.
*/
-
- public void add(Permission permission) {
- if (!(permission instanceof BundlePermission))
+ public void add(final Permission permission) {
+ if (!(permission instanceof BundlePermission)) {
throw new IllegalArgumentException("invalid permission: "
+ permission);
- if (isReadOnly())
+ }
+ if (isReadOnly()) {
throw new SecurityException("attempt to add a Permission to a "
+ "readonly PermissionCollection");
+ }
+ final BundlePermission bp = (BundlePermission) permission;
+ final String name = bp.getName();
+ synchronized (this) {
+ Map pc = permissions;
+ BundlePermission existing = (BundlePermission) pc.get(name);
+ if (existing != null) {
+ final int oldMask = existing.getActionsMask();
+ final int newMask = bp.getActionsMask();
+ if (oldMask != newMask) {
+ pc.put(name, new BundlePermission(name, oldMask
+ | newMask));
- BundlePermission bp = (BundlePermission) permission;
- String name = bp.getName();
-
- BundlePermission existing = (BundlePermission) permissions.get(name);
-
- if (existing != null) {
- int oldMask = existing.getMask();
- int newMask = bp.getMask();
- if (oldMask != newMask) {
- permissions.put(name, new BundlePermission(name, oldMask
- | newMask));
-
+ }
}
- }
- else {
- permissions.put(name, permission);
- }
+ else {
+ pc.put(name, bp);
+ }
- if (!all_allowed) {
- if (name.equals("*"))
- all_allowed = true;
+ if (!all_allowed) {
+ if (name.equals("*"))
+ all_allowed = true;
+ }
}
}
@@ -507,68 +516,60 @@
*
* @param permission The Permission object to compare with this
* <code>BundlePermission</code> object.
- *
- * @return <code>true</code> if <code>permission</code> is a proper
- * subset of a permission in the set; <code>false</code>
- * otherwise.
+ * @return <code>true</code> if <code>permission</code> is a proper subset
+ * of a permission in the set; <code>false</code> otherwise.
*/
+ public boolean implies(final Permission permission) {
+ if (!(permission instanceof BundlePermission)) {
+ return false;
+ }
+ BundlePermission requested = (BundlePermission) permission;
+ String requestedName = requested.getName();
+ final int desired = requested.getActionsMask();
+ int effective = BundlePermission.ACTION_NONE;
+ BundlePermission bp;
- public boolean implies(Permission permission) {
- if (!(permission instanceof BundlePermission))
- return (false);
-
- BundlePermission bp = (BundlePermission) permission;
- BundlePermission x;
-
- int desired = bp.getMask();
- int effective = 0;
-
- // short circuit if the "*" Permission was added
- if (all_allowed) {
- x = (BundlePermission) permissions.get("*");
- if (x != null) {
- effective |= x.getMask();
- if ((effective & desired) == desired)
- return (true);
+ synchronized (this) {
+ Map pc = permissions;
+ /* short circuit if the "*" Permission was added */
+ if (all_allowed) {
+ bp = (BundlePermission) pc.get("*");
+ if (bp != null) {
+ effective |= bp.getActionsMask();
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
}
- }
-
- // strategy:
- // Check for full match first. Then work our way up the
- // name looking for matches on a.b.*
-
- String name = bp.getName();
-
- x = (BundlePermission) permissions.get(name);
-
- if (x != null) {
- // we have a direct hit!
- effective |= x.getMask();
- if ((effective & desired) == desired)
- return (true);
- }
-
- // work our way up the tree...
- int last, offset;
-
- offset = name.length() - 1;
-
- while ((last = name.lastIndexOf(".", offset)) != -1) {
-
- name = name.substring(0, last + 1) + "*";
- x = (BundlePermission) permissions.get(name);
-
- if (x != null) {
- effective |= x.getMask();
- if ((effective & desired) == desired)
- return (true);
+ bp = (BundlePermission) pc.get(requestedName);
+ // strategy:
+ // Check for full match first. Then work our way up the
+ // name looking for matches on a.b.*
+ if (bp != null) {
+ // we have a direct hit!
+ effective |= bp.getActionsMask();
+ if ((effective & desired) == desired) {
+ return true;
+ }
}
- offset = last - 1;
+ // work our way up the tree...
+ int last;
+ int offset = requestedName.length() - 1;
+ while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+ requestedName = requestedName.substring(0, last + 1) + "*";
+ bp = (BundlePermission) pc.get(requestedName);
+ if (bp != null) {
+ effective |= bp.getActionsMask();
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ offset = last - 1;
+ }
+ // we don't have to check for "*" as it was already checked
+ // at the top (all_allowed), so we just return false
+ return false;
}
-
- // we don't have to check for "*" as it was already checked
- // at the top (all_allowed), so we just return false
- return (false);
}
/**
@@ -577,8 +578,29 @@
*
* @return Enumeration of all <code>BundlePermission</code> objects.
*/
+ public synchronized Enumeration elements() {
+ return Collections.enumeration(permissions.values());
+ }
+
+ /* serialization logic */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("permissions", Hashtable.class),
+ new ObjectStreamField("all_allowed", Boolean.TYPE) };
- public Enumeration elements() {
- return (permissions.elements());
+ private synchronized void writeObject(ObjectOutputStream out)
+ throws IOException {
+ Hashtable hashtable = new Hashtable(permissions);
+ ObjectOutputStream.PutField pfields = out.putFields();
+ pfields.put("permissions", hashtable);
+ pfields.put("all_allowed", all_allowed);
+ out.writeFields();
+ }
+
+ private synchronized void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ ObjectInputStream.GetField gfields = in.readFields();
+ Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+ permissions = new HashMap(hashtable);
+ all_allowed = gfields.get("all_allowed", false);
}
}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/BundleReference.java b/org.osgi.core/src/main/java/org/osgi/framework/BundleReference.java
new file mode 100644
index 0000000..f9c4183
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/BundleReference.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * A reference to a Bundle.
+ *
+ * @since 1.5
+ * @ThreadSafe
+ * @version $Revision: 6860 $
+ */
+public interface BundleReference {
+ /**
+ * Returns the <code>Bundle</code> object associated with this
+ * <code>BundleReference</code>.
+ *
+ * @return The <code>Bundle</code> object associated with this
+ * <code>BundleReference</code>.
+ */
+ public Bundle getBundle();
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/Configurable.java b/org.osgi.core/src/main/java/org/osgi/framework/Configurable.java
index cd40557..b30910c 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/Configurable.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/Configurable.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/Configurable.java,v 1.12 2007/02/20 00:07:22 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +26,7 @@
* <code>instanceof Configurable</code>.
*
* @deprecated As of 1.2. Please use Configuration Admin service.
- * @version $Revision: 1.12 $
+ * @version $Revision: 6361 $
*/
public interface Configurable {
/**
@@ -44,7 +42,7 @@
* returning the configuration object.
*
* @return The configuration object for this service.
- * @throws java.lang.SecurityException If the caller does not have an
+ * @throws SecurityException If the caller does not have an
* appropriate permission and the Java Runtime Environment supports
* permissions.
* @deprecated As of 1.2. Please use Configuration Admin service.
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/Constants.java b/org.osgi.core/src/main/java/org/osgi/framework/Constants.java
index 0ee3a33..16a10d8 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/Constants.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/Constants.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/Constants.java,v 1.32 2007/02/20 00:07:22 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,10 +22,10 @@
*
* <p>
* The values associated with these keys are of type
- * <code>java.lang.String</code>, unless otherwise indicated.
+ * <code>String</code>, unless otherwise indicated.
*
* @since 1.1
- * @version $Revision: 1.32 $
+ * @version $Revision: 6552 $
*/
public interface Constants {
@@ -46,8 +44,7 @@
public static final String SYSTEM_BUNDLE_SYMBOLICNAME = "system.bundle";
/**
- * Manifest header (named "Bundle-Category") identifying the
- * bundle's category.
+ * Manifest header identifying the bundle's category.
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
* object returned by the <code>Bundle.getHeaders</code> method.
@@ -55,9 +52,8 @@
public static final String BUNDLE_CATEGORY = "Bundle-Category";
/**
- * Manifest header (named "Bundle-ClassPath") identifying a list
- * of directories and embedded JAR files, which are bundle resources used to
- * extend the bundle's classpath.
+ * Manifest header identifying a list of directories and embedded JAR files,
+ * which are bundle resources used to extend the bundle's classpath.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -66,8 +62,7 @@
public static final String BUNDLE_CLASSPATH = "Bundle-ClassPath";
/**
- * Manifest header (named "Bundle-Copyright") identifying the
- * bundle's copyright information.
+ * Manifest header identifying the bundle's copyright information.
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
* object returned by the <code>Bundle.getHeaders</code> method.
@@ -75,8 +70,8 @@
public static final String BUNDLE_COPYRIGHT = "Bundle-Copyright";
/**
- * Manifest header (named "Bundle-Description") containing a brief
- * description of the bundle's functionality.
+ * Manifest header containing a brief description of the bundle's
+ * functionality.
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
* object returned by the <code>Bundle.getHeaders</code> method.
@@ -84,8 +79,7 @@
public static final String BUNDLE_DESCRIPTION = "Bundle-Description";
/**
- * Manifest header (named "Bundle-Name") identifying the bundle's
- * name.
+ * Manifest header identifying the bundle's name.
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
* object returned by the <code>Bundle.getHeaders</code> method.
@@ -93,9 +87,9 @@
public static final String BUNDLE_NAME = "Bundle-Name";
/**
- * Manifest header (named "Bundle-NativeCode") identifying a
- * number of hardware environments and the native language code libraries
- * that the bundle is carrying for each of these environments.
+ * Manifest header identifying a number of hardware environments and the
+ * native language code libraries that the bundle is carrying for each of
+ * these environments.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -104,8 +98,8 @@
public static final String BUNDLE_NATIVECODE = "Bundle-NativeCode";
/**
- * Manifest header (named "Export-Package") identifying the
- * packages that the bundle offers to the Framework for export.
+ * Manifest header identifying the packages that the bundle offers to the
+ * Framework for export.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -114,9 +108,9 @@
public static final String EXPORT_PACKAGE = "Export-Package";
/**
- * Manifest header (named "Export-Service") identifying the fully
- * qualified class names of the services that the bundle may register (used
- * for informational purposes only).
+ * Manifest header identifying the fully qualified class names of the
+ * services that the bundle may register (used for informational purposes
+ * only).
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -127,8 +121,7 @@
public static final String EXPORT_SERVICE = "Export-Service";
/**
- * Manifest header (named "Import-Package") identifying the
- * packages on which the bundle depends.
+ * Manifest header identifying the packages on which the bundle depends.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -137,8 +130,8 @@
public static final String IMPORT_PACKAGE = "Import-Package";
/**
- * Manifest header (named "DynamicImport-Package") identifying the
- * packages that the bundle may dynamically import during execution.
+ * Manifest header identifying the packages that the bundle may dynamically
+ * import during execution.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -149,9 +142,8 @@
public static final String DYNAMICIMPORT_PACKAGE = "DynamicImport-Package";
/**
- * Manifest header (named "Import-Service") identifying the fully
- * qualified class names of the services that the bundle requires (used for
- * informational purposes only).
+ * Manifest header identifying the fully qualified class names of the
+ * services that the bundle requires (used for informational purposes only).
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -162,8 +154,7 @@
public static final String IMPORT_SERVICE = "Import-Service";
/**
- * Manifest header (named "Bundle-Vendor") identifying the
- * bundle's vendor.
+ * Manifest header identifying the bundle's vendor.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -172,8 +163,7 @@
public static final String BUNDLE_VENDOR = "Bundle-Vendor";
/**
- * Manifest header (named "Bundle-Version") identifying the
- * bundle's version.
+ * Manifest header identifying the bundle's version.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -182,9 +172,8 @@
public static final String BUNDLE_VERSION = "Bundle-Version";
/**
- * Manifest header (named "Bundle-DocURL") identifying the
- * bundle's documentation URL, from which further information about the
- * bundle may be obtained.
+ * Manifest header identifying the bundle's documentation URL, from which
+ * further information about the bundle may be obtained.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -193,9 +182,8 @@
public static final String BUNDLE_DOCURL = "Bundle-DocURL";
/**
- * Manifest header (named "Bundle-ContactAddress") identifying the
- * contact address where problems with the bundle may be reported; for
- * example, an email address.
+ * Manifest header identifying the contact address where problems with the
+ * bundle may be reported; for example, an email address.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -204,8 +192,7 @@
public static final String BUNDLE_CONTACTADDRESS = "Bundle-ContactAddress";
/**
- * Manifest header attribute (named "Bundle-Activator")
- * identifying the bundle's activator class.
+ * Manifest header attribute identifying the bundle's activator class.
*
* <p>
* If present, this header specifies the name of the bundle resource class
@@ -220,9 +207,8 @@
public static final String BUNDLE_ACTIVATOR = "Bundle-Activator";
/**
- * Manifest header (named "Bundle-UpdateLocation") identifying the
- * location from which a new bundle version is obtained during a bundle
- * update operation.
+ * Manifest header identifying the location from which a new bundle version
+ * is obtained during a bundle update operation.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -231,9 +217,8 @@
public static final String BUNDLE_UPDATELOCATION = "Bundle-UpdateLocation";
/**
- * Manifest header attribute (named "specification-version")
- * identifying the version of a package specified in the Export-Package or
- * Import-Package manifest header.
+ * Manifest header attribute identifying the version of a package specified
+ * in the Export-Package or Import-Package manifest header.
*
* @deprecated As of 1.3. This has been replaced by
* {@link #VERSION_ATTRIBUTE}.
@@ -241,9 +226,8 @@
public static final String PACKAGE_SPECIFICATION_VERSION = "specification-version";
/**
- * Manifest header attribute (named "processor") identifying the
- * processor required to run native bundle code specified in the
- * Bundle-NativeCode manifest header).
+ * Manifest header attribute identifying the processor required to run
+ * native bundle code specified in the Bundle-NativeCode manifest header).
*
* <p>
* The attribute value is encoded in the Bundle-NativeCode manifest header
@@ -252,13 +236,15 @@
* <pre>
* Bundle-NativeCode: http.so ; processor=x86 ...
* </pre>
+ *
+ * @see #BUNDLE_NATIVECODE
*/
public static final String BUNDLE_NATIVECODE_PROCESSOR = "processor";
/**
- * Manifest header attribute (named "osname") identifying the
- * operating system required to run native bundle code specified in the
- * Bundle-NativeCode manifest header).
+ * Manifest header attribute identifying the operating system required to
+ * run native bundle code specified in the Bundle-NativeCode manifest
+ * header).
* <p>
* The attribute value is encoded in the Bundle-NativeCode manifest header
* like:
@@ -266,13 +252,15 @@
* <pre>
* Bundle-NativeCode: http.so ; osname=Linux ...
* </pre>
+ *
+ * @see #BUNDLE_NATIVECODE
*/
public static final String BUNDLE_NATIVECODE_OSNAME = "osname";
/**
- * Manifest header attribute (named "osversion") identifying the
- * operating system version required to run native bundle code specified in
- * the Bundle-NativeCode manifest header).
+ * Manifest header attribute identifying the operating system version
+ * required to run native bundle code specified in the Bundle-NativeCode
+ * manifest header).
* <p>
* The attribute value is encoded in the Bundle-NativeCode manifest header
* like:
@@ -280,13 +268,15 @@
* <pre>
* Bundle-NativeCode: http.so ; osversion="2.34" ...
* </pre>
+ *
+ * @see #BUNDLE_NATIVECODE
*/
public static final String BUNDLE_NATIVECODE_OSVERSION = "osversion";
/**
- * Manifest header attribute (named "language") identifying the
- * language in which the native bundle code is written specified in the
- * Bundle-NativeCode manifest header. See ISO 639 for possible values.
+ * Manifest header attribute identifying the language in which the native
+ * bundle code is written specified in the Bundle-NativeCode manifest
+ * header. See ISO 639 for possible values.
* <p>
* The attribute value is encoded in the Bundle-NativeCode manifest header
* like:
@@ -294,15 +284,16 @@
* <pre>
* Bundle-NativeCode: http.so ; language=nl_be ...
* </pre>
+ *
+ * @see #BUNDLE_NATIVECODE
*/
public static final String BUNDLE_NATIVECODE_LANGUAGE = "language";
/**
- * Manifest header (named "Bundle-RequiredExecutionEnvironment")
- * identifying the required execution environment for the bundle. The
- * service platform may run this bundle if any of the execution environments
- * named in this header matches one of the execution environments it
- * implements.
+ * Manifest header identifying the required execution environment for the
+ * bundle. The service platform may run this bundle if any of the execution
+ * environments named in this header matches one of the execution
+ * environments it implements.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -312,269 +303,10 @@
*/
public static final String BUNDLE_REQUIREDEXECUTIONENVIRONMENT = "Bundle-RequiredExecutionEnvironment";
- /*
- * Framework environment properties.
- */
-
/**
- * Framework environment property (named
- * "org.osgi.framework.version") identifying the Framework
- * version.
+ * Manifest header identifying the bundle's symbolic name.
*
* <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- */
- public static final String FRAMEWORK_VERSION = "org.osgi.framework.version";
-
- /**
- * Framework environment property (named
- * "org.osgi.framework.vendor") identifying the Framework
- * implementation vendor.
- *
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- */
- public static final String FRAMEWORK_VENDOR = "org.osgi.framework.vendor";
-
- /**
- * Framework environment property (named
- * "org.osgi.framework.language") identifying the Framework
- * implementation language (see ISO 639 for possible values).
- *
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- */
- public static final String FRAMEWORK_LANGUAGE = "org.osgi.framework.language";
-
- /**
- * Framework environment property (named
- * "org.osgi.framework.os.name") identifying the Framework
- * host-computer's operating system.
- *
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- */
- public static final String FRAMEWORK_OS_NAME = "org.osgi.framework.os.name";
-
- /**
- * Framework environment property (named
- * "org.osgi.framework.os.version") identifying the Framework
- * host-computer's operating system version number.
- *
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- */
- public static final String FRAMEWORK_OS_VERSION = "org.osgi.framework.os.version";
-
- /**
- * Framework environment property (named
- * "org.osgi.framework.processor") identifying the Framework
- * host-computer's processor name.
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- */
- public static final String FRAMEWORK_PROCESSOR = "org.osgi.framework.processor";
-
- /**
- * Framework environment property (named
- * "org.osgi.framework.executionenvironment") identifying
- * execution environments provided by the Framework.
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- *
- * @since 1.2
- */
- public static final String FRAMEWORK_EXECUTIONENVIRONMENT = "org.osgi.framework.executionenvironment";
-
- /**
- * Framework environment property (named
- * "org.osgi.framework.bootdelegation") identifying packages for
- * which the Framework must delegate class loading to the boot class path.
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- *
- * @since 1.3
- */
- public static final String FRAMEWORK_BOOTDELEGATION = "org.osgi.framework.bootdelegation";
-
- /**
- * Framework environment property (named
- * "org.osgi.framework.system.packages") identifying package which
- * the system bundle must export.
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- *
- * @since 1.3
- */
- public static final String FRAMEWORK_SYSTEMPACKAGES = "org.osgi.framework.system.packages";
-
- /**
- * Framework environment property (named
- * "org.osgi.supports.framework.extension") identifying whether
- * the Framework supports framework extension bundles. As of version 1.4,
- * the value of this property must be <code>true</code>. The Framework
- * must support framework extension bundles.
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- *
- * @since 1.3
- */
- public static final String SUPPORTS_FRAMEWORK_EXTENSION = "org.osgi.supports.framework.extension";
-
- /**
- * Framework environment property (named
- * "org.osgi.supports.bootclasspath.extension") identifying
- * whether the Framework supports bootclasspath extension bundles. If the
- * value of this property is <code>true</code>, then the Framework
- * supports bootclasspath extension bundles. The default value is
- * <code>false</code>.
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- *
- * @since 1.3
- */
- public static final String SUPPORTS_BOOTCLASSPATH_EXTENSION = "org.osgi.supports.bootclasspath.extension";
-
- /**
- * Framework environment property (named
- * "org.osgi.supports.framework.fragment") identifying whether the
- * Framework supports fragment bundles. As of version 1.4, the value of this
- * property must be <code>true</code>. The Framework must support
- * fragment bundles.
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- *
- * @since 1.3
- */
- public static final String SUPPORTS_FRAMEWORK_FRAGMENT = "org.osgi.supports.framework.fragment";
-
- /**
- * Framework environment property (named
- * "org.osgi.supports.framework.requirebundle") identifying
- * whether the Framework supports the <code>Require-Bundle</code> manifest
- * header. As of version 1.4, the value of this property must be
- * <code>true</code>. The Framework must support the
- * <code>Require-Bundle</code> manifest header.
- * <p>
- * The value of this property may be retrieved by calling the
- * <code>BundleContext.getProperty</code> method.
- *
- * @since 1.3
- */
- public static final String SUPPORTS_FRAMEWORK_REQUIREBUNDLE = "org.osgi.supports.framework.requirebundle";
-
- /*
- * Service properties.
- */
-
- /**
- * Service property (named "objectClass") identifying all of the
- * class names under which a service was registered in the Framework (of
- * type <code>java.lang.String[]</code>).
- *
- * <p>
- * This property is set by the Framework when a service is registered.
- */
- public static final String OBJECTCLASS = "objectClass";
-
- /**
- * Service property (named "service.id") identifying a service's
- * registration number (of type <code>java.lang.Long</code>).
- *
- * <p>
- * The value of this property is assigned by the Framework when a service is
- * registered. The Framework assigns a unique value that is larger than all
- * previously assigned values since the Framework was started. These values
- * are NOT persistent across restarts of the Framework.
- */
- public static final String SERVICE_ID = "service.id";
-
- /**
- * Service property (named "service.pid") identifying a service's
- * persistent identifier.
- *
- * <p>
- * This property may be supplied in the <code>properties</code>
- * <code>Dictionary</code>
- * object passed to the <code>BundleContext.registerService</code> method.
- *
- * <p>
- * A service's persistent identifier uniquely identifies the service and
- * persists across multiple Framework invocations.
- *
- * <p>
- * By convention, every bundle has its own unique namespace, starting with
- * the bundle's identifier (see {@link Bundle#getBundleId}) and followed by
- * a dot (.). A bundle may use this as the prefix of the persistent
- * identifiers for the services it registers.
- */
- public static final String SERVICE_PID = "service.pid";
-
- /**
- * Service property (named "service.ranking") identifying a
- * service's ranking number (of type <code>java.lang.Integer</code>).
- *
- * <p>
- * This property may be supplied in the <code>properties
- * Dictionary</code>
- * object passed to the <code>BundleContext.registerService</code> method.
- *
- * <p>
- * The service ranking is used by the Framework to determine the <i>default
- * </i> service to be returned from a call to the
- * {@link BundleContext#getServiceReference} method: If more than one
- * service implements the specified class, the <code>ServiceReference</code>
- * object with the highest ranking is returned.
- *
- * <p>
- * The default ranking is zero (0). A service with a ranking of
- * <code>Integer.MAX_VALUE</code> is very likely to be returned as the
- * default service, whereas a service with a ranking of
- * <code>Integer.MIN_VALUE</code> is very unlikely to be returned.
- *
- * <p>
- * If the supplied property value is not of type
- * <code>java.lang.Integer</code>, it is deemed to have a ranking value
- * of zero.
- */
- public static final String SERVICE_RANKING = "service.ranking";
-
- /**
- * Service property (named "service.vendor") identifying a
- * service's vendor.
- *
- * <p>
- * This property may be supplied in the properties <code>Dictionary</code>
- * object passed to the <code>BundleContext.registerService</code> method.
- */
- public static final String SERVICE_VENDOR = "service.vendor";
-
- /**
- * Service property (named "service.description") identifying a
- * service's description.
- *
- * <p>
- * This property may be supplied in the properties <code>Dictionary</code>
- * object passed to the <code>BundleContext.registerService</code> method.
- */
- public static final String SERVICE_DESCRIPTION = "service.description";
-
- /**
- * Manifest header (named "Bundle-SymbolicName") identifying the
- * bundle's symbolic name.
- * <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
* object returned by the <code>Bundle.getHeaders</code> method.
*
@@ -583,8 +315,8 @@
public final static String BUNDLE_SYMBOLICNAME = "Bundle-SymbolicName";
/**
- * Manifest header directive (named "singleton") identifying
- * whether a bundle is a singleton. The default value is <code>false</code>.
+ * Manifest header directive identifying whether a bundle is a singleton.
+ * The default value is <code>false</code>.
*
* <p>
* The directive value is encoded in the Bundle-SymbolicName manifest header
@@ -594,14 +326,19 @@
* Bundle-SymbolicName: com.acme.module.test; singleton:=true
* </pre>
*
+ * <p>
+ * The attribute value may be retrieved from the <code>Dictionary</code>
+ * object returned by the <code>Bundle.getHeaders</code> method.
+ *
+ * @see #BUNDLE_SYMBOLICNAME
* @since 1.3
*/
public final static String SINGLETON_DIRECTIVE = "singleton";
/**
- * Manifest header directive (named "fragment-attachment")
- * identifying if and when a fragment may attach to a host bundle. The
- * default value is <code>"always"</code>.
+ * Manifest header directive identifying if and when a fragment may attach
+ * to a host bundle. The default value is
+ * {@link #FRAGMENT_ATTACHMENT_ALWAYS always}.
*
* <p>
* The directive value is encoded in the Bundle-SymbolicName manifest header
@@ -611,19 +348,19 @@
* Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="never"
* </pre>
*
- * @see Constants#FRAGMENT_ATTACHMENT_ALWAYS
- * @see Constants#FRAGMENT_ATTACHMENT_RESOLVETIME
- * @see Constants#FRAGMENT_ATTACHMENT_NEVER
+ * @see #BUNDLE_SYMBOLICNAME
+ * @see #FRAGMENT_ATTACHMENT_ALWAYS
+ * @see #FRAGMENT_ATTACHMENT_RESOLVETIME
+ * @see #FRAGMENT_ATTACHMENT_NEVER
* @since 1.3
*/
public final static String FRAGMENT_ATTACHMENT_DIRECTIVE = "fragment-attachment";
/**
- * Manifest header directive value (named "always") identifying a
- * fragment attachment type of always. A fragment attachment type of always
- * indicates that fragments are allowed to attach to the host bundle at any
- * time (while the host is resolved or during the process of resolving the
- * host bundle).
+ * Manifest header directive value identifying a fragment attachment type of
+ * always. A fragment attachment type of always indicates that fragments are
+ * allowed to attach to the host bundle at any time (while the host is
+ * resolved or during the process of resolving the host bundle).
*
* <p>
* The directive value is encoded in the Bundle-SymbolicName manifest header
@@ -633,17 +370,16 @@
* Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="always"
* </pre>
*
- * @see Constants#FRAGMENT_ATTACHMENT_DIRECTIVE
+ * @see #FRAGMENT_ATTACHMENT_DIRECTIVE
* @since 1.3
*/
public final static String FRAGMENT_ATTACHMENT_ALWAYS = "always";
/**
- * Manifest header directive value (named "resolve-time")
- * identifying a fragment attachment type of resolve-time. A fragment
- * attachment type of resolve-time indicates that fragments are allowed to
- * attach to the host bundle only during the process of resolving the host
- * bundle.
+ * Manifest header directive value identifying a fragment attachment type of
+ * resolve-time. A fragment attachment type of resolve-time indicates that
+ * fragments are allowed to attach to the host bundle only during the
+ * process of resolving the host bundle.
*
* <p>
* The directive value is encoded in the Bundle-SymbolicName manifest header
@@ -653,16 +389,15 @@
* Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="resolve-time"
* </pre>
*
- * @see Constants#FRAGMENT_ATTACHMENT_DIRECTIVE
+ * @see #FRAGMENT_ATTACHMENT_DIRECTIVE
* @since 1.3
*/
public final static String FRAGMENT_ATTACHMENT_RESOLVETIME = "resolve-time";
/**
- * Manifest header directive value (named "never") identifying a
- * fragment attachment type of never. A fragment attachment type of never
- * indicates that no fragments are allowed to attach to the host bundle at
- * any time.
+ * Manifest header directive value identifying a fragment attachment type of
+ * never. A fragment attachment type of never indicates that no fragments
+ * are allowed to attach to the host bundle at any time.
*
* <p>
* The directive value is encoded in the Bundle-SymbolicName manifest header
@@ -672,14 +407,15 @@
* Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="never"
* </pre>
*
- * @see Constants#FRAGMENT_ATTACHMENT_DIRECTIVE
+ * @see #FRAGMENT_ATTACHMENT_DIRECTIVE
* @since 1.3
*/
public final static String FRAGMENT_ATTACHMENT_NEVER = "never";
/**
- * Manifest header (named "Bundle-Localization") identifying the
- * base name of the bundle's localization entries.
+ * Manifest header identifying the base name of the bundle's localization
+ * entries.
+ *
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
* object returned by the <code>Bundle.getHeaders</code> method.
@@ -698,8 +434,8 @@
public final static String BUNDLE_LOCALIZATION_DEFAULT_BASENAME = "OSGI-INF/l10n/bundle";
/**
- * Manifest header (named "Require-Bundle") identifying the
- * symbolic names of other bundles required by the bundle.
+ * Manifest header identifying the symbolic names of other bundles required
+ * by the bundle.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -710,9 +446,10 @@
public final static String REQUIRE_BUNDLE = "Require-Bundle";
/**
- * Manifest header attribute (named "bundle-version") identifying
- * a range of versions for a bundle specified in the Require-Bundle or
- * Fragment-Host manifest headers. The default value is <code>0.0.0</code>.
+ * Manifest header attribute identifying a range of versions for a bundle
+ * specified in the <code>Require-Bundle</code> or
+ * <code>Fragment-Host</code> manifest headers. The default value is
+ * <code>0.0.0</code>.
*
* <p>
* The attribute value is encoded in the Require-Bundle manifest header
@@ -729,13 +466,14 @@
* specified as a single version means a version range that includes any
* bundle version greater than or equal to the specified version.
*
+ * @see #REQUIRE_BUNDLE
* @since 1.3
*/
public static final String BUNDLE_VERSION_ATTRIBUTE = "bundle-version";
/**
- * Manifest header (named "Fragment-Host") identifying the
- * symbolic name of another bundle for which that the bundle is a fragment.
+ * Manifest header identifying the symbolic name of another bundle for which
+ * that the bundle is a fragment.
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -746,8 +484,8 @@
public final static String FRAGMENT_HOST = "Fragment-Host";
/**
- * Manifest header attribute (named "selection-filter") is used
- * for selection by filtering based upon system properties.
+ * Manifest header attribute is used for selection by filtering based upon
+ * system properties.
*
* <p>
* The attribute value is encoded in manifest headers like:
@@ -756,19 +494,19 @@
* Bundle-NativeCode: libgtk.so; selection-filter="(ws=gtk)"; ...
* </pre>
*
+ * @see #BUNDLE_NATIVECODE
* @since 1.3
*/
public final static String SELECTION_FILTER_ATTRIBUTE = "selection-filter";
/**
- * Manifest header (named "Bundle-ManifestVersion") identifying
- * the bundle manifest version. A bundle manifest may express the version of
- * the syntax in which it is written by specifying a bundle manifest
- * version. Bundles exploiting OSGi R4, or later, syntax must specify a
- * bundle manifest version.
+ * Manifest header identifying the bundle manifest version. A bundle
+ * manifest may express the version of the syntax in which it is written by
+ * specifying a bundle manifest version. Bundles exploiting OSGi Release 4,
+ * or later, syntax must specify a bundle manifest version.
* <p>
- * The bundle manifest version defined by OSGi R4 or, more specifically, by
- * V1.3 of the OSGi Framework Specification is "2".
+ * The bundle manifest version defined by OSGi Release 4 or, more
+ * specifically, by version 1.3 of the OSGi Core Specification is "2".
*
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
@@ -779,9 +517,8 @@
public final static String BUNDLE_MANIFESTVERSION = "Bundle-ManifestVersion";
/**
- * Manifest header attribute (named "version") identifying the
- * version of a package specified in the Export-Package or Import-Package
- * manifest header.
+ * Manifest header attribute identifying the version of a package specified
+ * in the Export-Package or Import-Package manifest header.
*
* <p>
* The attribute value is encoded in the Export-Package or Import-Package
@@ -791,14 +528,15 @@
* Import-Package: org.osgi.framework; version="1.1"
* </pre>
*
+ * @see #EXPORT_PACKAGE
+ * @see #IMPORT_PACKAGE
* @since 1.3
*/
public final static String VERSION_ATTRIBUTE = "version";
/**
- * Manifest header attribute (named "bundle-symbolic-name")
- * identifying the symbolic name of a bundle that exports a package
- * specified in the Import-Package manifest header.
+ * Manifest header attribute identifying the symbolic name of a bundle that
+ * exports a package specified in the Import-Package manifest header.
*
* <p>
* The attribute value is encoded in the Import-Package manifest header
@@ -808,13 +546,15 @@
* Import-Package: org.osgi.framework; bundle-symbolic-name="com.acme.module.test"
* </pre>
*
+ * @see #IMPORT_PACKAGE
* @since 1.3
*/
public final static String BUNDLE_SYMBOLICNAME_ATTRIBUTE = "bundle-symbolic-name";
/**
- * Manifest header directive (named "resolution") identifying the
- * resolution type in the Import-Package or Require-Bundle manifest header.
+ * Manifest header directive identifying the resolution type in the
+ * Import-Package or Require-Bundle manifest header. The default value is
+ * {@link #RESOLUTION_MANDATORY mandatory}.
*
* <p>
* The directive value is encoded in the Import-Package or Require-Bundle
@@ -825,18 +565,19 @@
* Require-Bundle: com.acme.module.test; resolution:="optional"
* </pre>
*
- * @see Constants#RESOLUTION_MANDATORY
- * @see Constants#RESOLUTION_OPTIONAL
+ * @see #IMPORT_PACKAGE
+ * @see #REQUIRE_BUNDLE
+ * @see #RESOLUTION_MANDATORY
+ * @see #RESOLUTION_OPTIONAL
* @since 1.3
*/
public final static String RESOLUTION_DIRECTIVE = "resolution";
/**
- * Manifest header directive value (named "mandatory") identifying
- * a mandatory resolution type. A mandatory resolution type indicates that
- * the import package or require bundle must be resolved when the bundle is
- * resolved. If such an import or require bundle cannot be resolved, the
- * module fails to resolve.
+ * Manifest header directive value identifying a mandatory resolution type.
+ * A mandatory resolution type indicates that the import package or require
+ * bundle must be resolved when the bundle is resolved. If such an import or
+ * require bundle cannot be resolved, the module fails to resolve.
*
* <p>
* The directive value is encoded in the Import-Package or Require-Bundle
@@ -847,18 +588,18 @@
* Require-Bundle: com.acme.module.test; resolution:="manditory"
* </pre>
*
- * @see Constants#RESOLUTION_DIRECTIVE
+ * @see #RESOLUTION_DIRECTIVE
* @since 1.3
*/
public final static String RESOLUTION_MANDATORY = "mandatory";
/**
- * Manifest header directive value (named "optional") identifying
- * an optional resolution type. An optional resolution type indicates that
- * the import or require bundle is optional and the bundle may be resolved
- * without the import or require bundle being resolved. If the import or
- * require bundle is not resolved when the bundle is resolved, the import or
- * require bundle may not be resolved before the bundle is refreshed.
+ * Manifest header directive value identifying an optional resolution type.
+ * An optional resolution type indicates that the import or require bundle
+ * is optional and the bundle may be resolved without the import or require
+ * bundle being resolved. If the import or require bundle is not resolved
+ * when the bundle is resolved, the import or require bundle may not be
+ * resolved before the bundle is refreshed.
*
* <p>
* The directive value is encoded in the Import-Package or Require-Bundle
@@ -869,14 +610,14 @@
* Require-Bundle: com.acme.module.test; resolution:="optional"
* </pre>
*
- * @see Constants#RESOLUTION_DIRECTIVE
+ * @see #RESOLUTION_DIRECTIVE
* @since 1.3
*/
public final static String RESOLUTION_OPTIONAL = "optional";
/**
- * Manifest header directive (named "uses") identifying a list of
- * packages that an exported package uses.
+ * Manifest header directive identifying a list of packages that an exported
+ * package uses.
*
* <p>
* The directive value is encoded in the Export-Package manifest header
@@ -886,20 +627,23 @@
* Export-Package: org.osgi.util.tracker; uses:="org.osgi.framework"
* </pre>
*
+ * @see #EXPORT_PACKAGE
* @since 1.3
*/
public final static String USES_DIRECTIVE = "uses";
/**
- * Manifest header directive (named "include").
+ * Manifest header directive identifying a list of classes to include in the
+ * exported package.
+ *
* <p>
- * This directive is used by the Import-Package manifest header to identify
+ * This directive is used by the Export-Package manifest header to identify
* a list of classes of the specified package which must be allowed to be
- * exported. The directive value is encoded in the Import-Package manifest
+ * exported. The directive value is encoded in the Export-Package manifest
* header like:
*
* <pre>
- * Import-Package: org.osgi.framework; include:="MyClass*"
+ * Export-Package: org.osgi.framework; include:="MyClass*"
* </pre>
*
* <p>
@@ -912,12 +656,15 @@
* 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 (named "exclude").
+ * Manifest header directive identifying a list of classes to exclude in the
+ * exported package..
* <p>
* This directive is used by the Export-Package manifest header to identify
* a list of classes of the specified package which must not be allowed to
@@ -938,14 +685,16 @@
* Bundle-ActivationPolicy: lazy; exclude:="org.osgi.framework"
* </pre>
*
+ * @see #EXPORT_PACKAGE
+ * @see #BUNDLE_ACTIVATIONPOLICY
* @since 1.3
*/
public final static String EXCLUDE_DIRECTIVE = "exclude";
/**
- * Manifest header directive (named "mandatory") identifying names
- * of matching attributes which must be specified by matching Import-Package
- * statements in the Export-Package manifest header.
+ * Manifest header directive identifying names of matching attributes which
+ * must be specified by matching Import-Package statements in the
+ * Export-Package manifest header.
*
* <p>
* The directive value is encoded in the Export-Package manifest header
@@ -955,13 +704,15 @@
* Export-Package: org.osgi.framework; mandatory:="bundle-symbolic-name"
* </pre>
*
+ * @see #EXPORT_PACKAGE
* @since 1.3
*/
public final static String MANDATORY_DIRECTIVE = "mandatory";
/**
- * Manifest header directive (named "visibility") identifying the
- * visibility of a reqiured bundle in the Require-Bundle manifest header.
+ * Manifest header directive identifying the visibility of a required bundle
+ * in the Require-Bundle manifest header. The default value is
+ * {@link #VISIBILITY_PRIVATE private}.
*
* <p>
* The directive value is encoded in the Require-Bundle manifest header
@@ -971,17 +722,18 @@
* Require-Bundle: com.acme.module.test; visibility:="reexport"
* </pre>
*
- * @see Constants#VISIBILITY_PRIVATE
- * @see Constants#VISIBILITY_REEXPORT
+ * @see #REQUIRE_BUNDLE
+ * @see #VISIBILITY_PRIVATE
+ * @see #VISIBILITY_REEXPORT
* @since 1.3
*/
public final static String VISIBILITY_DIRECTIVE = "visibility";
/**
- * Manifest header directive value (named "private") identifying a
- * private visibility type. A private visibility type indicates that any
- * packages that are exported by the required bundle are not made visible on
- * the export signature of the requiring bundle.
+ * Manifest header directive value identifying a private visibility type. A
+ * private visibility type indicates that any packages that are exported by
+ * the required bundle are not made visible on the export signature of the
+ * requiring bundle.
*
* <p>
* The directive value is encoded in the Require-Bundle manifest header
@@ -991,17 +743,17 @@
* Require-Bundle: com.acme.module.test; visibility:="private"
* </pre>
*
- * @see Constants#VISIBILITY_DIRECTIVE
+ * @see #VISIBILITY_DIRECTIVE
* @since 1.3
*/
public final static String VISIBILITY_PRIVATE = "private";
/**
- * Manifest header directive value (named "reexport") identifying
- * a reexport visibility type. A reexport visibility type indicates any
- * packages that are exported by the required bundle are re-exported by the
- * requiring bundle. Any arbitrary arbitrary matching attributes with which
- * they were exported by the required bundle are deleted.
+ * Manifest header directive value identifying a reexport visibility type. A
+ * reexport visibility type indicates any packages that are exported by the
+ * required bundle are re-exported by the requiring bundle. Any arbitrary
+ * arbitrary matching attributes with which they were exported by the
+ * required bundle are deleted.
*
* <p>
* The directive value is encoded in the Require-Bundle manifest header
@@ -1011,13 +763,13 @@
* Require-Bundle: com.acme.module.test; visibility:="reexport"
* </pre>
*
- * @see Constants#VISIBILITY_DIRECTIVE
+ * @see #VISIBILITY_DIRECTIVE
* @since 1.3
*/
public final static String VISIBILITY_REEXPORT = "reexport";
+
/**
- * Manifest header directive (named "extension") identifying the
- * type of the extension fragment.
+ * Manifest header directive identifying the type of the extension fragment.
*
* <p>
* The directive value is encoded in the Fragment-Host manifest header like:
@@ -1026,17 +778,17 @@
* Fragment-Host: system.bundle; extension:="framework"
* </pre>
*
- * @see Constants#EXTENSION_FRAMEWORK
- * @see Constants#EXTENSION_BOOTCLASSPATH
+ * @see #FRAGMENT_HOST
+ * @see #EXTENSION_FRAMEWORK
+ * @see #EXTENSION_BOOTCLASSPATH
* @since 1.3
*/
public final static String EXTENSION_DIRECTIVE = "extension";
/**
- * Manifest header directive value (named "framework") identifying
- * the type of extension fragment. An extension fragment type of framework
- * indicates that the extension fragment is to be loaded by the framework's
- * class loader.
+ * Manifest header directive value identifying the type of extension
+ * fragment. An extension fragment type of framework indicates that the
+ * extension fragment is to be loaded by the framework's class loader.
*
* <p>
* The directive value is encoded in the Fragment-Host manifest header like:
@@ -1045,16 +797,15 @@
* Fragment-Host: system.bundle; extension:="framework"
* </pre>
*
- * @see Constants#EXTENSION_DIRECTIVE
+ * @see #EXTENSION_DIRECTIVE
* @since 1.3
*/
public final static String EXTENSION_FRAMEWORK = "framework";
/**
- * Manifest header directive value (named "bootclasspath")
- * identifying the type of extension fragment. An extension fragment type of
- * bootclasspath indicates that the extension fragment is to be loaded by
- * the boot class loader.
+ * Manifest header directive value identifying the type of extension
+ * fragment. An extension fragment type of bootclasspath indicates that the
+ * extension fragment is to be loaded by the boot class loader.
*
* <p>
* The directive value is encoded in the Fragment-Host manifest header like:
@@ -1063,34 +814,33 @@
* Fragment-Host: system.bundle; extension:="bootclasspath"
* </pre>
*
- * @see Constants#EXTENSION_DIRECTIVE
+ * @see #EXTENSION_DIRECTIVE
* @since 1.3
*/
public final static String EXTENSION_BOOTCLASSPATH = "bootclasspath";
/**
- * Manifest header (named "Bundle-ActivationPolicy") identifying
- * the bundle's activation policy.
+ * Manifest header identifying the bundle's activation policy.
* <p>
* The attribute value may be retrieved from the <code>Dictionary</code>
* object returned by the <code>Bundle.getHeaders</code> method.
*
* @since 1.4
- * @see Constants#ACTIVATION_LAZY
- * @see Constants#INCLUDE_DIRECTIVE
- * @see Constants#EXCLUDE_DIRECTIVE
+ * @see #ACTIVATION_LAZY
+ * @see #INCLUDE_DIRECTIVE
+ * @see #EXCLUDE_DIRECTIVE
*/
public final static String BUNDLE_ACTIVATIONPOLICY = "Bundle-ActivationPolicy";
/**
- * Bundle activation policy (named "lazy") declaring the bundle
- * must be activated when the first class load is made from the bundle.
+ * Bundle activation policy declaring the bundle must be activated when the
+ * first class load is made from the bundle.
* <p>
* A bundle with the lazy activation policy that is started with the
* {@link Bundle#START_ACTIVATION_POLICY START_ACTIVATION_POLICY} option
* will wait in the {@link Bundle#STARTING STARTING} state until the first
* class load from the bundle occurs. The bundle will then be activated
- * before the class is returned to the requestor.
+ * before the class is returned to the requester.
* <p>
* The activation policy value is specified as in the
* Bundle-ActivationPolicy manifest header like:
@@ -1099,11 +849,464 @@
* Bundle-ActivationPolicy: lazy
* </pre>
*
- * @see Constants#BUNDLE_ACTIVATIONPOLICY
+ * @see #BUNDLE_ACTIVATIONPOLICY
* @see Bundle#start(int)
* @see Bundle#START_ACTIVATION_POLICY
* @since 1.4
*/
public final static String ACTIVATION_LAZY = "lazy";
-}
\ No newline at end of file
+ /**
+ * Framework environment property identifying the Framework version.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_VERSION = "org.osgi.framework.version";
+
+ /**
+ * Framework environment property identifying the Framework implementation
+ * vendor.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_VENDOR = "org.osgi.framework.vendor";
+
+ /**
+ * Framework environment property identifying the Framework implementation
+ * language (see ISO 639 for possible values).
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_LANGUAGE = "org.osgi.framework.language";
+
+ /**
+ * Framework environment property identifying the Framework host-computer's
+ * operating system.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_OS_NAME = "org.osgi.framework.os.name";
+
+ /**
+ * Framework environment property identifying the Framework host-computer's
+ * operating system version number.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_OS_VERSION = "org.osgi.framework.os.version";
+
+ /**
+ * Framework environment property identifying the Framework host-computer's
+ * processor name.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ */
+ public static final String FRAMEWORK_PROCESSOR = "org.osgi.framework.processor";
+
+ /**
+ * Framework environment property identifying execution environments
+ * provided by the Framework.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.2
+ */
+ public static final String FRAMEWORK_EXECUTIONENVIRONMENT = "org.osgi.framework.executionenvironment";
+
+ /**
+ * Framework environment property identifying packages for which the
+ * Framework must delegate class loading to the parent class loader of the
+ * bundle.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @see #FRAMEWORK_BUNDLE_PARENT
+ * @since 1.3
+ */
+ public static final String FRAMEWORK_BOOTDELEGATION = "org.osgi.framework.bootdelegation";
+
+ /**
+ * Framework environment property identifying packages which the system
+ * bundle must export.
+ *
+ * <p>
+ * If this property is not specified then the framework must calculate a
+ * reasonable default value for the current execution environment.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.3
+ */
+ public static final String FRAMEWORK_SYSTEMPACKAGES = "org.osgi.framework.system.packages";
+
+ /**
+ * Framework environment property identifying extra packages which the
+ * system bundle must export from the current execution environment.
+ *
+ * <p>
+ * This property is useful for configuring extra system packages in addition
+ * to the system packages calculated by the framework.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @see #FRAMEWORK_SYSTEMPACKAGES
+ * @since 1.5
+ */
+ public static final String FRAMEWORK_SYSTEMPACKAGES_EXTRA = "org.osgi.framework.system.packages.extra";
+
+ /**
+ * Framework environment property identifying whether the Framework supports
+ * framework extension bundles.
+ *
+ * <p>
+ * As of version 1.4, the value of this property must be <code>true</code>.
+ * The Framework must support framework extension bundles.
+ *
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.3
+ */
+ public static final String SUPPORTS_FRAMEWORK_EXTENSION = "org.osgi.supports.framework.extension";
+
+ /**
+ * Framework environment property identifying whether the Framework supports
+ * bootclasspath extension bundles.
+ *
+ * <p>
+ * If the value of this property is <code>true</code>, then the Framework
+ * supports bootclasspath extension bundles. The default value is
+ * <code>false</code>.
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.3
+ */
+ public static final String SUPPORTS_BOOTCLASSPATH_EXTENSION = "org.osgi.supports.bootclasspath.extension";
+
+ /**
+ * Framework environment property identifying whether the Framework supports
+ * fragment bundles.
+ *
+ * <p>
+ * As of version 1.4, the value of this property must be <code>true</code>.
+ * The Framework must support fragment bundles.
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.3
+ */
+ public static final String SUPPORTS_FRAMEWORK_FRAGMENT = "org.osgi.supports.framework.fragment";
+
+ /**
+ * Framework environment property identifying whether the Framework supports
+ * the {@link #REQUIRE_BUNDLE Require-Bundle} manifest header.
+ *
+ * <p>
+ * As of version 1.4, the value of this property must be <code>true</code>.
+ * The Framework must support the <code>Require-Bundle</code> manifest
+ * header.
+ * <p>
+ * The value of this property may be retrieved by calling the
+ * <code>BundleContext.getProperty</code> method.
+ *
+ * @since 1.3
+ */
+ public static final String SUPPORTS_FRAMEWORK_REQUIREBUNDLE = "org.osgi.supports.framework.requirebundle";
+
+ /**
+ * Specifies the type of security manager the framework must use. If not
+ * specified then the framework will not set the VM security manager.
+ *
+ * @see #FRAMEWORK_SECURITY_OSGI
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_SECURITY = "org.osgi.framework.security";
+
+ /**
+ * Specifies that a security manager that supports all security aspects of
+ * the OSGi core specification including postponed conditions must be
+ * installed.
+ *
+ * <p>
+ * If this value is specified and there is a security manager already
+ * installed, then a <code>SecurityException</code> must be thrown when the
+ * Framework is initialized.
+ *
+ * @see #FRAMEWORK_SECURITY
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_SECURITY_OSGI = "osgi";
+
+ /**
+ * Specified the persistent storage area used by the framework. The value of
+ * this property must be a valid file path in the file system to a
+ * directory. If the specified directory does not exist then the framework
+ * will create the directory. If the specified path exists but is not a
+ * directory or if the framework fails to create the storage directory, then
+ * framework initialization must fail. The framework is free to use this
+ * directory as it sees fit. This area can not be shared with anything else.
+ * <p>
+ * If this property is not set, the framework should use a reasonable
+ * platform default for the persistent storage area.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_STORAGE = "org.osgi.framework.storage";
+
+ /**
+ * Specifies if and when the persistent storage area for the framework
+ * should be cleaned. If this property is not set, then the framework
+ * storage area must not be cleaned.
+ *
+ * @see #FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_STORAGE_CLEAN = "org.osgi.framework.storage.clean";
+
+ /**
+ * Specifies that the framework storage area must be cleaned before the
+ * framework is initialized for the first time. Subsequent inits, starts or
+ * updates of the framework will not result in cleaning the framework
+ * storage area.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT = "onFirstInit";
+
+ /**
+ * Specifies a comma separated list of additional library file extensions
+ * that must be used when a bundle's class loader is searching for native
+ * libraries. If this property is not set, then only the library name
+ * returned by <code>System.mapLibraryName(String)</code> will be used to
+ * search. This is needed for certain operating systems which allow more
+ * than one extension for a library. For example, AIX allows library
+ * extensions of <code>.a</code> and <code>.so</code>, but
+ * <code>System.mapLibraryName(String)</code> will only return names with
+ * the <code>.a</code> extension.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_LIBRARY_EXTENSIONS = "org.osgi.framework.library.extensions";
+
+ /**
+ * Specifies an optional OS specific command to set file permissions on
+ * extracted native code. On some operating systems, it is required that
+ * native libraries be set to executable. This optional property allows you
+ * to specify the command. For example, on a UNIX style OS, this property
+ * could have the following value.
+ *
+ * <pre>
+ * chmod +rx ${abspath}
+ * </pre>
+ *
+ * The <code>${abspath}</code> is used by the framework to substitute the
+ * actual absolute file path.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_EXECPERMISSION = "org.osgi.framework.command.execpermission";
+
+ /**
+ * Specifies the trust repositories used by the framework. The value is a
+ * <code>java.io.File.pathSeparator</code> separated list of valid file
+ * paths to files that contain key stores of type <code>JKS</code>. The
+ * framework will use the key stores as trust repositories to authenticate
+ * certificates of trusted signers. The key stores are only used as
+ * read-only trust repositories to access public keys. No passwords are
+ * required to access the key stores' public keys.
+ * <p>
+ * Note that framework implementations are allowed to use other trust
+ * repositories in addition to the trust repositories specified by this
+ * property. How these other trust repositories are configured and populated
+ * is implementation specific.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_TRUST_REPOSITORIES = "org.osgi.framework.trust.repositories";
+
+ /**
+ * Specifies the current windowing system. The framework should provide a
+ * reasonable default if this is not set.
+ *
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_WINDOWSYSTEM = "org.osgi.framework.windowsystem";
+
+ /**
+ * Specifies the beginning start level of the framework.
+ *
+ * @see "Core Specification, section 8.2.3."
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_BEGINNING_STARTLEVEL = "org.osgi.framework.startlevel.beginning";
+
+ /**
+ * Specifies the parent class loader type for all bundle class loaders.
+ * Default value is {@link #FRAMEWORK_BUNDLE_PARENT_BOOT boot}.
+ *
+ * @see #FRAMEWORK_BUNDLE_PARENT_BOOT
+ * @see #FRAMEWORK_BUNDLE_PARENT_EXT
+ * @see #FRAMEWORK_BUNDLE_PARENT_APP
+ * @see #FRAMEWORK_BUNDLE_PARENT_FRAMEWORK
+ * @since 1.5
+ */
+ public final static String FRAMEWORK_BUNDLE_PARENT = "org.osgi.framework.bundle.parent";
+
+ /**
+ * Specifies to use of the boot class loader as the parent class loader for
+ * all bundle class loaders.
+ *
+ * @since 1.5
+ * @see #FRAMEWORK_BUNDLE_PARENT
+ */
+ public final static String FRAMEWORK_BUNDLE_PARENT_BOOT = "boot";
+
+ /**
+ * Specifies to use the extension class loader as the parent class loader
+ * for all bundle class loaders.
+ *
+ * @since 1.5
+ * @see #FRAMEWORK_BUNDLE_PARENT
+ */
+ public final static String FRAMEWORK_BUNDLE_PARENT_EXT = "ext";
+
+ /**
+ * Specifies to use the application class loader as the parent class loader
+ * for all bundle class loaders. Depending on how the framework is
+ * launched, this may refer to the same class loader as
+ * {@link #FRAMEWORK_BUNDLE_PARENT_FRAMEWORK}.
+ *
+ * @since 1.5
+ * @see #FRAMEWORK_BUNDLE_PARENT
+ */
+ public final static String FRAMEWORK_BUNDLE_PARENT_APP = "app";
+
+ /**
+ * Specifies to use the framework class loader as the parent class loader
+ * for all bundle class loaders. The framework class loader is the class
+ * loader used to load the framework implementation. Depending on how the
+ * framework is launched, this may refer to the same class loader as
+ * {@link #FRAMEWORK_BUNDLE_PARENT_APP}.
+ *
+ * @since 1.5
+ * @see #FRAMEWORK_BUNDLE_PARENT
+ */
+ public final static String FRAMEWORK_BUNDLE_PARENT_FRAMEWORK = "framework";
+
+ /*
+ * Service properties.
+ */
+
+ /**
+ * Service property identifying all of the class names under which a service
+ * was registered in the Framework. The value of this property must be of
+ * type <code>String[]</code>.
+ *
+ * <p>
+ * This property is set by the Framework when a service is registered.
+ */
+ public static final String OBJECTCLASS = "objectClass";
+
+ /**
+ * Service property identifying a service's registration number. The value
+ * of this property must be of type <code>Long</code>.
+ *
+ * <p>
+ * The value of this property is assigned by the Framework when a service is
+ * registered. The Framework assigns a unique value that is larger than all
+ * previously assigned values since the Framework was started. These values
+ * are NOT persistent across restarts of the Framework.
+ */
+ public static final String SERVICE_ID = "service.id";
+
+ /**
+ * Service property identifying a service's persistent identifier.
+ *
+ * <p>
+ * This property may be supplied in the <code>properties</code>
+ * <code>Dictionary</code> object passed to the
+ * <code>BundleContext.registerService</code> method. The value of this
+ * property must be of type <code>String</code>, <code>String[]</code>, or
+ * <code>Collection</code> of <code>String</code>.
+ *
+ * <p>
+ * A service's persistent identifier uniquely identifies the service and
+ * persists across multiple Framework invocations.
+ *
+ * <p>
+ * By convention, every bundle has its own unique namespace, starting with
+ * the bundle's identifier (see {@link Bundle#getBundleId}) and followed by
+ * a dot (.). A bundle may use this as the prefix of the persistent
+ * identifiers for the services it registers.
+ */
+ public static final String SERVICE_PID = "service.pid";
+
+ /**
+ * Service property identifying a service's ranking number.
+ *
+ * <p>
+ * This property may be supplied in the <code>properties
+ * Dictionary</code> object passed to the
+ * <code>BundleContext.registerService</code> method. The value of this
+ * property must be of type <code>Integer</code>.
+ *
+ * <p>
+ * The service ranking is used by the Framework to determine the <i>natural
+ * order</i> of services, see {@link ServiceReference#compareTo(Object)},
+ * and the <i>default</i> service to be returned from a call to the
+ * {@link BundleContext#getServiceReference} method.
+ *
+ * <p>
+ * The default ranking is zero (0). A service with a ranking of
+ * <code>Integer.MAX_VALUE</code> is very likely to be returned as the
+ * default service, whereas a service with a ranking of
+ * <code>Integer.MIN_VALUE</code> is very unlikely to be returned.
+ *
+ * <p>
+ * If the supplied property value is not of type <code>Integer</code>, it is
+ * deemed to have a ranking value of zero.
+ */
+ public static final String SERVICE_RANKING = "service.ranking";
+
+ /**
+ * Service property identifying a service's vendor.
+ *
+ * <p>
+ * This property may be supplied in the properties <code>Dictionary</code>
+ * object passed to the <code>BundleContext.registerService</code> method.
+ */
+ public static final String SERVICE_VENDOR = "service.vendor";
+
+ /**
+ * Service property identifying a service's description.
+ *
+ * <p>
+ * This property may be supplied in the properties <code>Dictionary</code>
+ * object passed to the <code>BundleContext.registerService</code> method.
+ */
+ public static final String SERVICE_DESCRIPTION = "service.description";
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/Filter.java b/org.osgi.core/src/main/java/org/osgi/framework/Filter.java
index 41b7cfa..81c3e5b 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/Filter.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/Filter.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/Filter.java,v 1.16 2007/02/21 16:49:05 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,12 +20,13 @@
/**
* An RFC 1960-based Filter.
* <p>
- * <code>Filter</code> objects can be created by calling
- * {@link BundleContext#createFilter} with the chosen filter string.
+ * <code>Filter</code>s can be created by calling
+ * {@link BundleContext#createFilter} or {@link FrameworkUtil#createFilter} with
+ * a filter string.
* <p>
- * A <code>Filter</code> object can be used numerous times to determine if the
- * match argument matches the filter string that was used to create the
- * <code>Filter</code> object.
+ * A <code>Filter</code> can be used numerous times to determine if the match
+ * argument matches the filter string that was used to create the
+ * <code>Filter</code>.
* <p>
* Some examples of LDAP filters are:
*
@@ -39,86 +38,85 @@
* </pre>
*
* @since 1.1
- * @see "Core Specification, section 5.5, for a description of the filter string
- * syntax."
+ * @see "Core Specification, section 5.5, for a description of the filter string syntax."
* @ThreadSafe
- * @version $Revision: 1.16 $
+ * @version $Revision: 6860 $
*/
public interface Filter {
/**
* Filter using a service's properties.
* <p>
- * The filter is executed using the keys and values of the referenced
- * service's properties. The keys are case insensitively matched with the
- * filter.
+ * This <code>Filter</code> is executed using the keys and values of the
+ * referenced service's properties. The keys are case insensitively matched
+ * with this <code>Filter</code>.
*
* @param reference The reference to the service whose properties are used
* in the match.
- *
* @return <code>true</code> if the service's properties match this
- * filter; <code>false</code> otherwise.
+ * <code>Filter</code>; <code>false</code> otherwise.
*/
public boolean match(ServiceReference reference);
/**
- * Filter using a <code>Dictionary</code> object. The Filter is executed
- * using the <code>Dictionary</code> object's keys and values. The keys
- * are case insensitively matched with the filter.
+ * Filter using a <code>Dictionary</code>. This <code>Filter</code> is
+ * executed using the specified <code>Dictionary</code>'s keys and values.
+ * The keys are case insensitively matched with this <code>Filter</code>.
*
- * @param dictionary The <code>Dictionary</code> object whose keys are
- * used in the match.
- *
- * @return <code>true</code> if the <code>Dictionary</code> object's
- * keys and values match this filter; <code>false</code>
- * otherwise.
- *
- * @throws IllegalArgumentException If <code>dictionary</code> contains
- * case variants of the same key name.
+ * @param dictionary The <code>Dictionary</code> whose keys are used in the
+ * match.
+ * @return <code>true</code> if the <code>Dictionary</code>'s keys and
+ * values match this filter; <code>false</code> otherwise.
+ * @throws IllegalArgumentException If <code>dictionary</code> contains case
+ * variants of the same key name.
*/
public boolean match(Dictionary dictionary);
/**
- * Returns this <code>Filter</code> object's filter string.
+ * Returns this <code>Filter</code>'s filter string.
* <p>
* The filter string is normalized by removing whitespace which does not
* affect the meaning of the filter.
*
- * @return Filter string.
+ * @return This <code>Filter</code>'s filter string.
*/
public String toString();
/**
- * Compares this <code>Filter</code> object to another object.
+ * Compares this <code>Filter</code> to another <code>Filter</code>.
*
- * @param obj The object to compare against this <code>Filter</code>
- * object.
+ * <p>
+ * This method returns the result of calling
+ * <code>this.toString().equals(obj.toString())</code>.
*
- * @return If the other object is a <code>Filter</code> object, then
- * returns <code>this.toString().equals(obj.toString()</code>;<code>false</code>
- * otherwise.
+ * @param obj The object to compare against this <code>Filter</code>.
+ * @return If the other object is a <code>Filter</code> object, then returns
+ * the result of calling
+ * <code>this.toString().equals(obj.toString())</code>;
+ * <code>false</code> otherwise.
*/
public boolean equals(Object obj);
/**
- * Returns the hashCode for this <code>Filter</code> object.
+ * Returns the hashCode for this <code>Filter</code>.
*
- * @return The hashCode of the filter string; that is,
- * <code>this.toString().hashCode()</code>.
+ * <p>
+ * This method returns the result of calling
+ * <code>this.toString().hashCode()</code>.
+ *
+ * @return The hashCode of this <code>Filter</code>.
*/
public int hashCode();
/**
- * Filter with case sensitivity using a <code>Dictionary</code> object.
- * The Filter is executed using the <code>Dictionary</code> object's keys
- * and values. The keys are case sensitively matched with the filter.
+ * Filter with case sensitivity using a <code>Dictionary</code>. This
+ * <code>Filter</code> is executed using the specified
+ * <code>Dictionary</code>'s keys and values. The keys are case sensitively
+ * matched with this <code>Filter</code>.
*
- * @param dictionary The <code>Dictionary</code> object whose keys are
- * used in the match.
- *
- * @return <code>true</code> if the <code>Dictionary</code> object's
- * keys and values match this filter; <code>false</code>
- * otherwise.
- *
+ * @param dictionary The <code>Dictionary</code> whose keys are used in the
+ * match.
+ * @return <code>true</code> if the <code>Dictionary</code>'s keys and
+ * values match this filter; <code>false</code> otherwise.
* @since 1.3
*/
public boolean matchCase(Dictionary dictionary);
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkEvent.java b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkEvent.java
index c3da54f..747b249 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkEvent.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkEvent.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/FrameworkEvent.java,v 1.15 2007/02/20 00:14:12 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,8 +23,8 @@
*
* <p>
* <code>FrameworkEvent</code> objects are delivered to
- * <code>FrameworkListener</code>s when a general event occurs within the
- * OSGi environment. A type code is used to identify the event type for future
+ * <code>FrameworkListener</code>s when a general event occurs within the OSGi
+ * environment. A type code is used to identify the event type for future
* extendability.
*
* <p>
@@ -34,11 +32,11 @@
*
* @Immutable
* @see FrameworkListener
- * @version $Revision: 1.15 $
+ * @version $Revision: 6542 $
*/
public class FrameworkEvent extends EventObject {
- static final long serialVersionUID = 207051004521261705L;
+ static final long serialVersionUID = 207051004521261705L;
/**
* Bundle related to the event.
*/
@@ -60,25 +58,20 @@
* <p>
* This event is fired when the Framework has started after all installed
* bundles that are marked to be started have been started and the Framework
- * has reached the intitial start level.
+ * has reached the initial start level. The source of this event is the
+ * System Bundle.
*
- * <p>
- * The value of <code>STARTED</code> is 0x00000001.
- *
- * @see "<code>StartLevel</code>"
+ * @see "The Start Level Service"
*/
- public final static int STARTED = 0x00000001;
+ public final static int STARTED = 0x00000001;
/**
* An error has occurred.
*
* <p>
* There was an error associated with a bundle.
- *
- * <p>
- * The value of <code>ERROR</code> is 0x00000002.
*/
- public final static int ERROR = 0x00000002;
+ public final static int ERROR = 0x00000002;
/**
* A PackageAdmin.refreshPackage operation has completed.
@@ -86,14 +79,12 @@
* <p>
* This event is fired when the Framework has completed the refresh packages
* operation initiated by a call to the PackageAdmin.refreshPackages method.
- *
- * <p>
- * The value of <code>PACKAGES_REFRESHED</code> is 0x00000004.
+ * The source of this event is the System Bundle.
*
* @since 1.2
* @see "<code>PackageAdmin.refreshPackages</code>"
*/
- public final static int PACKAGES_REFRESHED = 0x00000004;
+ public final static int PACKAGES_REFRESHED = 0x00000004;
/**
* A StartLevel.setStartLevel operation has completed.
@@ -101,14 +92,12 @@
* <p>
* This event is fired when the Framework has completed changing the active
* start level initiated by a call to the StartLevel.setStartLevel method.
- *
- * <p>
- * The value of <code>STARTLEVEL_CHANGED</code> is 0x00000008.
+ * The source of this event is the System Bundle.
*
* @since 1.2
- * @see "<code>StartLevel</code>"
+ * @see "The Start Level Service"
*/
- public final static int STARTLEVEL_CHANGED = 0x00000008;
+ public final static int STARTLEVEL_CHANGED = 0x00000008;
/**
* A warning has occurred.
@@ -116,12 +105,9 @@
* <p>
* There was a warning associated with a bundle.
*
- * <p>
- * The value of <code>WARNING</code> is 0x00000010.
- *
* @since 1.3
*/
- public final static int WARNING = 0x00000010;
+ public final static int WARNING = 0x00000010;
/**
* An informational event has occurred.
@@ -129,12 +115,56 @@
* <p>
* There was an informational event associated with a bundle.
*
- * <p>
- * The value of <code>INFO</code> is 0x00000020.
- *
* @since 1.3
*/
- public final static int INFO = 0x00000020;
+ public final static int INFO = 0x00000020;
+
+ /**
+ * The Framework has stopped.
+ *
+ * <p>
+ * This event is fired when the Framework has been stopped because of a stop
+ * operation on the system bundle. The source of this event is the System
+ * Bundle.
+ *
+ * @since 1.5
+ */
+ public final static int STOPPED = 0x00000040;
+
+ /**
+ * The Framework has stopped during update.
+ *
+ * <p>
+ * This event is fired when the Framework has been stopped because of an
+ * update operation on the system bundle. The Framework will be restarted
+ * after this event is fired. The source of this event is the System Bundle.
+ *
+ * @since 1.5
+ */
+ public final static int STOPPED_UPDATE = 0x00000080;
+
+ /**
+ * The Framework has stopped and the boot class path has changed.
+ *
+ * <p>
+ * This event is fired when the Framework has been stopped because of a stop
+ * operation on the system bundle and a bootclasspath extension bundle has
+ * been installed or updated. The source of this event is the System Bundle.
+ *
+ * @since 1.5
+ */
+ public final static int STOPPED_BOOTCLASSPATH_MODIFIED = 0x00000100;
+
+ /**
+ * The Framework did not stop before the wait timeout expired.
+ *
+ * <p>
+ * This event is fired when the Framework did not stop before the wait
+ * timeout expired. The source of this event is the System Bundle.
+ *
+ * @since 1.5
+ */
+ public final static int WAIT_TIMEDOUT = 0x00000200;
/**
* Creates a Framework event.
@@ -197,6 +227,10 @@
* <li>{@link #INFO}
* <li>{@link #PACKAGES_REFRESHED}
* <li>{@link #STARTLEVEL_CHANGED}
+ * <li>{@link #STOPPED}
+ * <li>{@link #STOPPED_BOOTCLASSPATH_MODIFIED}
+ * <li>{@link #STOPPED_UPDATE}
+ * <li>{@link #WAIT_TIMEDOUT}
* </ul>
*
* @return The type of state change.
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkListener.java b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkListener.java
index 29c934d..c96c490 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkListener.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkListener.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/FrameworkListener.java,v 1.12 2007/02/21 16:49:05 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,7 +35,7 @@
*
* @see FrameworkEvent
* @NotThreadSafe
- * @version $Revision: 1.12 $
+ * @version $Revision: 5673 $
*/
public interface FrameworkListener extends EventListener {
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkUtil.java b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkUtil.java
index fdefc52..13391ca 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/FrameworkUtil.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/FrameworkUtil.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/FrameworkUtil.java,v 1.10 2007/02/21 16:49:05 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2005, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,9 +16,19 @@
package org.osgi.framework;
-import java.lang.reflect.*;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
/**
* Framework Utility class.
@@ -31,117 +39,2117 @@
*
* @since 1.3
* @ThreadSafe
- * @version $Revision: 1.10 $
+ * @version $Revision: 6888 $
*/
public class FrameworkUtil {
- /*
- * NOTE: A framework implementor may also choose to replace this class in
- * their distribution with a class that directly interfaces with the
- * framework implementation.
+ /**
+ * FrameworkUtil objects may not be constructed.
*/
-
- /*
- * This class will load the FrameworkUtil class in the package named by the
- * org.osgi.vendor.framework package. For each instance of this class, an
- * instance of the vendor FrameworkUtil class will be created and this class
- * will delegate method calls to the vendor FrameworkUtil instance.
- */
-
- private static class ImplHolder implements PrivilegedAction {
- private static final String packageProperty = "org.osgi.vendor.framework";
-
- /*
- * This is the delegate method used by createFilter.
- */
- static final Method createFilter;
-
- static {
- createFilter = (Method) AccessController.doPrivileged(new ImplHolder());
- }
-
- private ImplHolder() {
- }
-
- public Object run() {
- String packageName = System
- .getProperty(packageProperty);
- if (packageName == null) {
- throw new NoClassDefFoundError(packageProperty
- + " property not set");
- }
-
- Class delegateClass;
- try {
- delegateClass = Class.forName(packageName
- + ".FrameworkUtil");
- }
- catch (ClassNotFoundException e) {
- throw new NoClassDefFoundError(e.toString());
- }
-
- Method result;
- try {
- result = delegateClass.getMethod("createFilter",
- new Class[] {String.class});
- }
- catch (NoSuchMethodException e) {
- throw new NoSuchMethodError(e.toString());
- }
-
- if (!Modifier.isStatic(result.getModifiers())) {
- throw new NoSuchMethodError(
- "createFilter method must be static");
- }
-
- return result;
- }
+ private FrameworkUtil() {
+ // private empty constructor to prevent construction
}
-
/**
- * FrameworkUtil objects may not be constructed.
- */
- private FrameworkUtil() {}
-
- /**
- * Creates a <code>Filter</code> object. This <code>Filter</code> object
- * may be used to match a <code>ServiceReference</code> object or a
+ * Creates a <code>Filter</code> object. This <code>Filter</code> object may
+ * be used to match a <code>ServiceReference</code> object or a
* <code>Dictionary</code> object.
*
* <p>
* If the filter cannot be parsed, an {@link InvalidSyntaxException} will be
* thrown with a human readable message where the filter became unparsable.
*
+ * <p>
+ * This method returns a Filter implementation which may not perform as well
+ * as the framework implementation-specific Filter implementation returned
+ * by {@link BundleContext#createFilter(String)}.
+ *
* @param filter The filter string.
* @return A <code>Filter</code> object encapsulating the filter string.
- * @throws InvalidSyntaxException If <code>filter</code> contains an
- * invalid filter string that cannot be parsed.
+ * @throws InvalidSyntaxException If <code>filter</code> contains an invalid
+ * filter string that cannot be parsed.
* @throws NullPointerException If <code>filter</code> is null.
*
* @see Filter
*/
public static Filter createFilter(String filter)
throws InvalidSyntaxException {
- try {
+ return FilterImpl.newInstance(filter);
+ }
+
+ /**
+ * Match a Distinguished Name (DN) chain against a pattern. DNs can be
+ * matched using wildcards. A wildcard ('*' \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, new ArrayList(dnChain));
+ }
+
+ /**
+ * Return a <code>Bundle</code> for the specified bundle class. The returned
+ * <code>Bundle</code> is the bundle associated with the bundle class loader
+ * which defined the specified class.
+ *
+ * @param classFromBundle A class defined by a bundle class loader.
+ * @return A <code>Bundle</code> for the specified bundle class or
+ * <code>null</code> if the specified class was not defined by a
+ * bundle class loader.
+ * @since 1.5
+ */
+ public static Bundle getBundle(final Class classFromBundle) {
+ // We use doPriv since the caller may not have permission
+ // to call getClassLoader.
+ Object cl = AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return classFromBundle.getClassLoader();
+ }
+ });
+
+ if (cl instanceof BundleReference) {
+ return ((BundleReference) cl).getBundle();
+ }
+ return null;
+ }
+
+ /**
+ * RFC 1960-based Filter. Filter objects can be created by calling the
+ * constructor with the desired filter string. A Filter object can be called
+ * numerous times to determine if the match argument matches the filter
+ * string that was used to create the Filter object.
+ *
+ * <p>
+ * The syntax of a filter string is the string representation of LDAP search
+ * filters as defined in RFC 1960: <i>A String Representation of LDAP Search
+ * Filters</i> (available at http://www.ietf.org/rfc/rfc1960.txt). It should
+ * be noted that RFC 2254: <i>A String Representation of LDAP Search
+ * Filters</i> (available at http://www.ietf.org/rfc/rfc2254.txt) supersedes
+ * RFC 1960 but only adds extensible matching and is not applicable for this
+ * API.
+ *
+ * <p>
+ * The string representation of an LDAP search filter is defined by the
+ * following grammar. It uses a prefix format.
+ *
+ * <pre>
+ * <filter> ::= '(' <filtercomp> ')'
+ * <filtercomp> ::= <and> | <or> | <not> | <item>
+ * <and> ::= '&' <filterlist>
+ * <or> ::= '|' <filterlist>
+ * <not> ::= '!' <filter>
+ * <filterlist> ::= <filter> | <filter> <filterlist>
+ * <item> ::= <simple> | <present> | <substring>
+ * <simple> ::= <attr> <filtertype> <value>
+ * <filtertype> ::= <equal> | <approx> | <greater> | <less>
+ * <equal> ::= '='
+ * <approx> ::= '˜='
+ * <greater> ::= '>='
+ * <less> ::= '<='
+ * <present> ::= <attr> '=*'
+ * <substring> ::= <attr> '=' <initial> <any> <final>
+ * <initial> ::= NULL | <value>
+ * <any> ::= '*' <starval>
+ * <starval> ::= NULL | <value> '*' <starval>
+ * <final> ::= NULL | <value>
+ * </pre>
+ *
+ * <code><attr></code> is a string representing an attribute, or key,
+ * in the properties objects of the registered services. Attribute names are
+ * not case sensitive; that is cn and CN both refer to the same attribute.
+ * <code><value></code> is a string representing the value, or part of
+ * one, of a key in the properties objects of the registered services. If a
+ * <code><value></code> must contain one of the characters '
+ * <code>*</code>' or '<code>(</code>' or '<code>)</code>', these characters
+ * should be escaped by preceding them with the backslash '<code>\</code>'
+ * character. Note that although both the <code><substring></code> and
+ * <code><present></code> productions can produce the <code>'attr=*'</code>
+ * construct, this construct is used only to denote a presence filter.
+ *
+ * <p>
+ * Examples of LDAP filters are:
+ *
+ * <pre>
+ * "(cn=Babs Jensen)"
+ * "(!(cn=Tim Howes))"
+ * "(&(" + Constants.OBJECTCLASS + "=Person)(|(sn=Jensen)(cn=Babs J*)))"
+ * "(o=univ*of*mich*)"
+ * </pre>
+ *
+ * <p>
+ * The approximate match (<code>~=</code>) is implementation specific but
+ * should at least ignore case and white space differences. Optional are
+ * codes like soundex or other smart "closeness" comparisons.
+ *
+ * <p>
+ * Comparison of values is not straightforward. Strings are compared
+ * differently than numbers and it is possible for a key to have multiple
+ * values. Note that that keys in the match argument must always be strings.
+ * The comparison is defined by the object type of the key's value. The
+ * following rules apply for comparison:
+ *
+ * <blockquote>
+ * <TABLE BORDER=0>
+ * <TR>
+ * <TD><b>Property Value Type </b></TD>
+ * <TD><b>Comparison Type</b></TD>
+ * </TR>
+ * <TR>
+ * <TD>String</TD>
+ * <TD>String comparison</TD>
+ * </TR>
+ * <TR valign=top>
+ * <TD>Integer, Long, Float, Double, Byte, Short, BigInteger, BigDecimal</TD>
+ * <TD>numerical comparison</TD>
+ * </TR>
+ * <TR>
+ * <TD>Character</TD>
+ * <TD>character comparison</TD>
+ * </TR>
+ * <TR>
+ * <TD>Boolean</TD>
+ * <TD>equality comparisons only</TD>
+ * </TR>
+ * <TR>
+ * <TD>[] (array)</TD>
+ * <TD>recursively applied to values</TD>
+ * </TR>
+ * <TR>
+ * <TD>Collection</TD>
+ * <TD>recursively applied to values</TD>
+ * </TR>
+ * </TABLE>
+ * Note: arrays of primitives are also supported. </blockquote>
+ *
+ * A filter matches a key that has multiple values if it matches at least
+ * one of those values. For example,
+ *
+ * <pre>
+ * Dictionary d = new Hashtable();
+ * d.put("cn", new String[] {"a", "b", "c"});
+ * </pre>
+ *
+ * d will match <code>(cn=a)</code> and also <code>(cn=b)</code>
+ *
+ * <p>
+ * A filter component that references a key having an unrecognizable data
+ * type will evaluate to <code>false</code> .
+ */
+ private static class FilterImpl implements Filter {
+ /* filter operators */
+ private static final int EQUAL = 1;
+ private static final int APPROX = 2;
+ private static final int GREATER = 3;
+ private static final int LESS = 4;
+ private static final int PRESENT = 5;
+ private static final int SUBSTRING = 6;
+ private static final int AND = 7;
+ private static final int OR = 8;
+ private static final int NOT = 9;
+
+ /** filter operation */
+ private final int op;
+ /** filter attribute or null if operation AND, OR or NOT */
+ private final String attr;
+ /** filter operands */
+ private final Object value;
+
+ /* normalized filter string for Filter object */
+ private transient volatile String filterString;
+
+ /**
+ * Constructs a {@link FilterImpl} object. This filter object may be
+ * used to match a {@link ServiceReference} or a Dictionary.
+ *
+ * <p>
+ * If the filter cannot be parsed, an {@link InvalidSyntaxException}
+ * will be thrown with a human readable message where the filter became
+ * unparsable.
+ *
+ * @param filterString the filter string.
+ * @exception InvalidSyntaxException If the filter parameter contains an
+ * invalid filter string that cannot be parsed.
+ */
+ static FilterImpl newInstance(String filterString)
+ throws InvalidSyntaxException {
+ return new Parser(filterString).parse();
+ }
+
+ FilterImpl(int operation, String attr, Object value) {
+ this.op = operation;
+ this.attr = attr;
+ this.value = value;
+ }
+
+ /**
+ * Filter using a service's properties.
+ * <p>
+ * This <code>Filter</code> is executed using the keys and values of the
+ * referenced service's properties. The keys are case insensitively
+ * matched with this <code>Filter</code>.
+ *
+ * @param reference The reference to the service whose properties are
+ * used in the match.
+ * @return <code>true</code> if the service's properties match this
+ * <code>Filter</code>; <code>false</code> otherwise.
+ */
+ public boolean match(ServiceReference reference) {
+ return match0(new ServiceReferenceDictionary(reference));
+ }
+
+ /**
+ * Filter using a <code>Dictionary</code>. This <code>Filter</code> is
+ * executed using the specified <code>Dictionary</code>'s keys and
+ * values. The keys are case insensitively matched with this
+ * <code>Filter</code>.
+ *
+ * @param dictionary The <code>Dictionary</code> whose keys are used in
+ * the match.
+ * @return <code>true</code> if the <code>Dictionary</code>'s keys and
+ * values match this filter; <code>false</code> otherwise.
+ * @throws IllegalArgumentException If <code>dictionary</code> contains
+ * case variants of the same key name.
+ */
+ public boolean match(Dictionary dictionary) {
+ return match0(new CaseInsensitiveDictionary(dictionary));
+ }
+
+ /**
+ * Filter with case sensitivity using a <code>Dictionary</code>. This
+ * <code>Filter</code> is executed using the specified
+ * <code>Dictionary</code>'s keys and values. The keys are case
+ * sensitively matched with this <code>Filter</code>.
+ *
+ * @param dictionary The <code>Dictionary</code> whose keys are used in
+ * the match.
+ * @return <code>true</code> if the <code>Dictionary</code>'s keys and
+ * values match this filter; <code>false</code> otherwise.
+ * @since 1.3
+ */
+ public boolean matchCase(Dictionary dictionary) {
+ return match0(dictionary);
+ }
+
+ /**
+ * Returns this <code>Filter</code>'s filter string.
+ * <p>
+ * The filter string is normalized by removing whitespace which does not
+ * affect the meaning of the filter.
+ *
+ * @return This <code>Filter</code>'s filter string.
+ */
+ public String toString() {
+ String result = filterString;
+ if (result == null) {
+ filterString = result = normalize();
+ }
+ return result;
+ }
+
+ /**
+ * Returns this <code>Filter</code>'s normalized filter string.
+ * <p>
+ * The filter string is normalized by removing whitespace which does not
+ * affect the meaning of the filter.
+ *
+ * @return This <code>Filter</code>'s filter string.
+ */
+ private String normalize() {
+ StringBuffer sb = new StringBuffer();
+ sb.append('(');
+
+ switch (op) {
+ case AND : {
+ sb.append('&');
+
+ FilterImpl[] filters = (FilterImpl[]) value;
+ for (int i = 0, size = filters.length; i < size; i++) {
+ sb.append(filters[i].normalize());
+ }
+
+ break;
+ }
+
+ case OR : {
+ sb.append('|');
+
+ FilterImpl[] filters = (FilterImpl[]) value;
+ for (int i = 0, size = filters.length; i < size; i++) {
+ sb.append(filters[i].normalize());
+ }
+
+ break;
+ }
+
+ case NOT : {
+ sb.append('!');
+ FilterImpl filter = (FilterImpl) value;
+ sb.append(filter.normalize());
+
+ break;
+ }
+
+ case SUBSTRING : {
+ sb.append(attr);
+ sb.append('=');
+
+ String[] substrings = (String[]) value;
+
+ for (int i = 0, size = substrings.length; i < size; i++) {
+ String substr = substrings[i];
+
+ if (substr == null) /* * */{
+ sb.append('*');
+ }
+ else /* xxx */{
+ sb.append(encodeValue(substr));
+ }
+ }
+
+ break;
+ }
+ case EQUAL : {
+ sb.append(attr);
+ sb.append('=');
+ sb.append(encodeValue((String) value));
+
+ break;
+ }
+ case GREATER : {
+ sb.append(attr);
+ sb.append(">=");
+ sb.append(encodeValue((String) value));
+
+ break;
+ }
+ case LESS : {
+ sb.append(attr);
+ sb.append("<=");
+ sb.append(encodeValue((String) value));
+
+ break;
+ }
+ case APPROX : {
+ sb.append(attr);
+ sb.append("~=");
+ sb.append(encodeValue(approxString((String) value)));
+
+ break;
+ }
+
+ case PRESENT : {
+ sb.append(attr);
+ sb.append("=*");
+
+ break;
+ }
+ }
+
+ sb.append(')');
+
+ return sb.toString();
+ }
+
+ /**
+ * Compares this <code>Filter</code> to another <code>Filter</code>.
+ *
+ * <p>
+ * This implementation returns the result of calling
+ * <code>this.toString().equals(obj.toString()</code>.
+ *
+ * @param obj The object to compare against this <code>Filter</code>.
+ * @return If the other object is a <code>Filter</code> object, then
+ * returns the result of calling
+ * <code>this.toString().equals(obj.toString()</code>;
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (!(obj instanceof Filter)) {
+ return false;
+ }
+
+ return this.toString().equals(obj.toString());
+ }
+
+ /**
+ * Returns the hashCode for this <code>Filter</code>.
+ *
+ * <p>
+ * This implementation returns the result of calling
+ * <code>this.toString().hashCode()</code>.
+ *
+ * @return The hashCode of this <code>Filter</code>.
+ */
+ public int hashCode() {
+ return this.toString().hashCode();
+ }
+
+ /**
+ * Internal match routine. Dictionary parameter must support
+ * case-insensitive get.
+ *
+ * @param properties A dictionary whose keys are used in the match.
+ * @return If the Dictionary's keys match the filter, return
+ * <code>true</code>. Otherwise, return <code>false</code>.
+ */
+ private boolean match0(Dictionary properties) {
+ switch (op) {
+ case AND : {
+ FilterImpl[] filters = (FilterImpl[]) value;
+ for (int i = 0, size = filters.length; i < size; i++) {
+ if (!filters[i].match0(properties)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ case OR : {
+ FilterImpl[] filters = (FilterImpl[]) value;
+ for (int i = 0, size = filters.length; i < size; i++) {
+ if (filters[i].match0(properties)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ case NOT : {
+ FilterImpl filter = (FilterImpl) value;
+
+ return !filter.match0(properties);
+ }
+
+ case SUBSTRING :
+ case EQUAL :
+ case GREATER :
+ case LESS :
+ case APPROX : {
+ Object prop = (properties == null) ? null : properties
+ .get(attr);
+
+ return compare(op, prop, value);
+ }
+
+ case PRESENT : {
+ Object prop = (properties == null) ? null : properties
+ .get(attr);
+
+ return prop != null;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Encode the value string such that '(', '*', ')' and '\' are escaped.
+ *
+ * @param value unencoded value string.
+ * @return encoded value string.
+ */
+ private static String encodeValue(String value) {
+ boolean encoded = false;
+ int inlen = value.length();
+ int outlen = inlen << 1; /* inlen 2 */
+
+ char[] output = new char[outlen];
+ value.getChars(0, inlen, output, inlen);
+
+ int cursor = 0;
+ for (int i = inlen; i < outlen; i++) {
+ char c = output[i];
+
+ switch (c) {
+ case '(' :
+ case '*' :
+ case ')' :
+ case '\\' : {
+ output[cursor] = '\\';
+ cursor++;
+ encoded = true;
+
+ break;
+ }
+ }
+
+ output[cursor] = c;
+ cursor++;
+ }
+
+ return encoded ? new String(output, 0, cursor) : value;
+ }
+
+ private boolean compare(int operation, Object value1, Object value2) {
+ if (value1 == null) {
+ return false;
+ }
+ if (value1 instanceof String) {
+ return compare_String(operation, (String) value1, value2);
+ }
+
+ Class clazz = value1.getClass();
+ if (clazz.isArray()) {
+ Class type = clazz.getComponentType();
+ if (type.isPrimitive()) {
+ return compare_PrimitiveArray(operation, type, value1,
+ value2);
+ }
+ return compare_ObjectArray(operation, (Object[]) value1, value2);
+ }
+ if (value1 instanceof Collection) {
+ return compare_Collection(operation, (Collection) value1,
+ value2);
+ }
+ if (value1 instanceof Integer) {
+ return compare_Integer(operation,
+ ((Integer) value1).intValue(), value2);
+ }
+ if (value1 instanceof Long) {
+ return compare_Long(operation, ((Long) value1).longValue(),
+ value2);
+ }
+ if (value1 instanceof Byte) {
+ return compare_Byte(operation, ((Byte) value1).byteValue(),
+ value2);
+ }
+ if (value1 instanceof Short) {
+ return compare_Short(operation, ((Short) value1).shortValue(),
+ value2);
+ }
+ if (value1 instanceof Character) {
+ return compare_Character(operation, ((Character) value1)
+ .charValue(), value2);
+ }
+ if (value1 instanceof Float) {
+ return compare_Float(operation, ((Float) value1).floatValue(),
+ value2);
+ }
+ if (value1 instanceof Double) {
+ return compare_Double(operation, ((Double) value1)
+ .doubleValue(), value2);
+ }
+ if (value1 instanceof Boolean) {
+ return compare_Boolean(operation, ((Boolean) value1)
+ .booleanValue(), value2);
+ }
+ if (value1 instanceof Comparable) {
+ return compare_Comparable(operation, (Comparable) value1,
+ value2);
+ }
+ return compare_Unknown(operation, value1, value2); // RFC 59
+ }
+
+ private boolean compare_Collection(int operation,
+ Collection collection, Object value2) {
+ for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
+ if (compare(operation, iterator.next(), value2)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_ObjectArray(int operation, Object[] array,
+ Object value2) {
+ for (int i = 0, size = array.length; i < size; i++) {
+ if (compare(operation, array[i], value2)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_PrimitiveArray(int operation, Class type,
+ Object primarray, Object value2) {
+ if (Integer.TYPE.isAssignableFrom(type)) {
+ int[] array = (int[]) primarray;
+ for (int i = 0, size = array.length; i < size; i++) {
+ if (compare_Integer(operation, array[i], value2)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Long.TYPE.isAssignableFrom(type)) {
+ long[] array = (long[]) primarray;
+ for (int i = 0, size = array.length; i < size; i++) {
+ if (compare_Long(operation, array[i], value2)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Byte.TYPE.isAssignableFrom(type)) {
+ byte[] array = (byte[]) primarray;
+ for (int i = 0, size = array.length; i < size; i++) {
+ if (compare_Byte(operation, array[i], value2)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Short.TYPE.isAssignableFrom(type)) {
+ short[] array = (short[]) primarray;
+ for (int i = 0, size = array.length; i < size; i++) {
+ if (compare_Short(operation, array[i], value2)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Character.TYPE.isAssignableFrom(type)) {
+ char[] array = (char[]) primarray;
+ for (int i = 0, size = array.length; i < size; i++) {
+ if (compare_Character(operation, array[i], value2)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Float.TYPE.isAssignableFrom(type)) {
+ float[] array = (float[]) primarray;
+ for (int i = 0, size = array.length; i < size; i++) {
+ if (compare_Float(operation, array[i], value2)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Double.TYPE.isAssignableFrom(type)) {
+ double[] array = (double[]) primarray;
+ for (int i = 0, size = array.length; i < size; i++) {
+ if (compare_Double(operation, array[i], value2)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Boolean.TYPE.isAssignableFrom(type)) {
+ boolean[] array = (boolean[]) primarray;
+ for (int i = 0, size = array.length; i < size; i++) {
+ if (compare_Boolean(operation, array[i], value2)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return false;
+ }
+
+ private boolean compare_String(int operation, String string,
+ Object value2) {
+ switch (operation) {
+ case SUBSTRING : {
+ String[] substrings = (String[]) value2;
+ int pos = 0;
+ for (int i = 0, size = substrings.length; i < size; i++) {
+ String substr = substrings[i];
+
+ if (i + 1 < size) /* if this is not that last substr */{
+ if (substr == null) /* * */{
+ String substr2 = substrings[i + 1];
+
+ if (substr2 == null) /* ** */
+ continue; /* ignore first star */
+ /* xxx */
+ int index = string.indexOf(substr2, pos);
+ if (index == -1) {
+ return false;
+ }
+
+ pos = index + substr2.length();
+ if (i + 2 < size) // if there are more
+ // substrings, increment
+ // over the string we just
+ // matched; otherwise need
+ // to do the last substr
+ // check
+ i++;
+ }
+ else /* xxx */{
+ int len = substr.length();
+ if (string.regionMatches(pos, substr, 0, len)) {
+ pos += len;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+ else /* last substr */{
+ if (substr == null) /* * */{
+ return true;
+ }
+ /* xxx */
+ return string.endsWith(substr);
+ }
+ }
+
+ return true;
+ }
+ case EQUAL : {
+ return string.equals(value2);
+ }
+ case APPROX : {
+ string = approxString(string);
+ String string2 = approxString((String) value2);
+
+ return string.equalsIgnoreCase(string2);
+ }
+ case GREATER : {
+ return string.compareTo((String) value2) >= 0;
+ }
+ case LESS : {
+ return string.compareTo((String) value2) <= 0;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_Integer(int operation, int intval, Object value2) {
+ if (operation == SUBSTRING) {
+ return false;
+ }
+ int intval2 = Integer.parseInt(((String) value2).trim());
+ switch (operation) {
+ case APPROX :
+ case EQUAL : {
+ return intval == intval2;
+ }
+ case GREATER : {
+ return intval >= intval2;
+ }
+ case LESS : {
+ return intval <= intval2;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_Long(int operation, long longval, Object value2) {
+ if (operation == SUBSTRING) {
+ return false;
+ }
+ long longval2 = Long.parseLong(((String) value2).trim());
+ switch (operation) {
+ case APPROX :
+ case EQUAL : {
+ return longval == longval2;
+ }
+ case GREATER : {
+ return longval >= longval2;
+ }
+ case LESS : {
+ return longval <= longval2;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_Byte(int operation, byte byteval, Object value2) {
+ if (operation == SUBSTRING) {
+ return false;
+ }
+ byte byteval2 = Byte.parseByte(((String) value2).trim());
+ switch (operation) {
+ case APPROX :
+ case EQUAL : {
+ return byteval == byteval2;
+ }
+ case GREATER : {
+ return byteval >= byteval2;
+ }
+ case LESS : {
+ return byteval <= byteval2;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_Short(int operation, short shortval,
+ Object value2) {
+ if (operation == SUBSTRING) {
+ return false;
+ }
+ short shortval2 = Short.parseShort(((String) value2).trim());
+ switch (operation) {
+ case APPROX :
+ case EQUAL : {
+ return shortval == shortval2;
+ }
+ case GREATER : {
+ return shortval >= shortval2;
+ }
+ case LESS : {
+ return shortval <= shortval2;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_Character(int operation, char charval,
+ Object value2) {
+ if (operation == SUBSTRING) {
+ return false;
+ }
+ char charval2 = (((String) value2).trim()).charAt(0);
+ switch (operation) {
+ case EQUAL : {
+ return charval == charval2;
+ }
+ case APPROX : {
+ return (charval == charval2)
+ || (Character.toUpperCase(charval) == Character
+ .toUpperCase(charval2))
+ || (Character.toLowerCase(charval) == Character
+ .toLowerCase(charval2));
+ }
+ case GREATER : {
+ return charval >= charval2;
+ }
+ case LESS : {
+ return charval <= charval2;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_Boolean(int operation, boolean boolval,
+ Object value2) {
+ if (operation == SUBSTRING) {
+ return false;
+ }
+ boolean boolval2 = Boolean.valueOf(((String) value2).trim())
+ .booleanValue();
+ switch (operation) {
+ case APPROX :
+ case EQUAL :
+ case GREATER :
+ case LESS : {
+ return boolval == boolval2;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_Float(int operation, float floatval,
+ Object value2) {
+ if (operation == SUBSTRING) {
+ return false;
+ }
+ float floatval2 = Float.parseFloat(((String) value2).trim());
+ switch (operation) {
+ case APPROX :
+ case EQUAL : {
+ return Float.compare(floatval, floatval2) == 0;
+ }
+ case GREATER : {
+ return Float.compare(floatval, floatval2) >= 0;
+ }
+ case LESS : {
+ return Float.compare(floatval, floatval2) <= 0;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_Double(int operation, double doubleval,
+ Object value2) {
+ if (operation == SUBSTRING) {
+ return false;
+ }
+ double doubleval2 = Double.parseDouble(((String) value2).trim());
+ switch (operation) {
+ case APPROX :
+ case EQUAL : {
+ return Double.compare(doubleval, doubleval2) == 0;
+ }
+ case GREATER : {
+ return Double.compare(doubleval, doubleval2) >= 0;
+ }
+ case LESS : {
+ return Double.compare(doubleval, doubleval2) <= 0;
+ }
+ }
+ return false;
+ }
+
+ private static final Class[] constructorType = new Class[] {String.class};
+
+ private boolean compare_Comparable(int operation, Comparable value1,
+ Object value2) {
+ if (operation == SUBSTRING) {
+ return false;
+ }
+ Constructor constructor;
try {
- return (Filter) ImplHolder.createFilter
- .invoke(null, new Object[] {filter});
+ constructor = value1.getClass().getConstructor(constructorType);
+ }
+ catch (NoSuchMethodException e) {
+ return false;
+ }
+ try {
+ if (!constructor.isAccessible())
+ AccessController.doPrivileged(new SetAccessibleAction(
+ constructor));
+ value2 = constructor
+ .newInstance(new Object[] {((String) value2).trim()});
+ }
+ catch (IllegalAccessException e) {
+ return false;
}
catch (InvocationTargetException e) {
- throw e.getTargetException();
+ return false;
+ }
+ catch (InstantiationException e) {
+ return false;
+ }
+
+ switch (operation) {
+ case APPROX :
+ case EQUAL : {
+ return value1.compareTo(value2) == 0;
+ }
+ case GREATER : {
+ return value1.compareTo(value2) >= 0;
+ }
+ case LESS : {
+ return value1.compareTo(value2) <= 0;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_Unknown(int operation, Object value1,
+ Object value2) {
+ if (operation == SUBSTRING) {
+ return false;
+ }
+ Constructor constructor;
+ try {
+ constructor = value1.getClass().getConstructor(constructorType);
+ }
+ catch (NoSuchMethodException e) {
+ return false;
+ }
+ try {
+ if (!constructor.isAccessible())
+ AccessController.doPrivileged(new SetAccessibleAction(
+ constructor));
+ value2 = constructor
+ .newInstance(new Object[] {((String) value2).trim()});
+ }
+ catch (IllegalAccessException e) {
+ return false;
+ }
+ catch (InvocationTargetException e) {
+ return false;
+ }
+ catch (InstantiationException e) {
+ return false;
+ }
+
+ switch (operation) {
+ case APPROX :
+ case EQUAL :
+ case GREATER :
+ case LESS : {
+ return value1.equals(value2);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Map a string for an APPROX (~=) comparison.
+ *
+ * This implementation removes white spaces. This is the minimum
+ * implementation allowed by the OSGi spec.
+ *
+ * @param input Input string.
+ * @return String ready for APPROX comparison.
+ */
+ private static String approxString(String input) {
+ boolean changed = false;
+ char[] output = input.toCharArray();
+ int cursor = 0;
+ for (int i = 0, length = output.length; i < length; i++) {
+ char c = output[i];
+
+ if (Character.isWhitespace(c)) {
+ changed = true;
+ continue;
+ }
+
+ output[cursor] = c;
+ cursor++;
+ }
+
+ return changed ? new String(output, 0, cursor) : input;
+ }
+
+ /**
+ * Parser class for OSGi filter strings. This class parses the complete
+ * filter string and builds a tree of Filter objects rooted at the
+ * parent.
+ */
+ private static class Parser {
+ private final String filterstring;
+ private final char[] filterChars;
+ private int pos;
+
+ Parser(String filterstring) {
+ this.filterstring = filterstring;
+ filterChars = filterstring.toCharArray();
+ pos = 0;
+ }
+
+ FilterImpl parse() throws InvalidSyntaxException {
+ FilterImpl filter;
+ try {
+ filter = parse_filter();
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ throw new InvalidSyntaxException("Filter ended abruptly",
+ filterstring);
+ }
+
+ if (pos != filterChars.length) {
+ throw new InvalidSyntaxException(
+ "Extraneous trailing characters: "
+ + filterstring.substring(pos), filterstring);
+ }
+ return filter;
+ }
+
+ private FilterImpl parse_filter() throws InvalidSyntaxException {
+ FilterImpl filter;
+ skipWhiteSpace();
+
+ if (filterChars[pos] != '(') {
+ throw new InvalidSyntaxException("Missing '(': "
+ + filterstring.substring(pos), filterstring);
+ }
+
+ pos++;
+
+ filter = parse_filtercomp();
+
+ skipWhiteSpace();
+
+ if (filterChars[pos] != ')') {
+ throw new InvalidSyntaxException("Missing ')': "
+ + filterstring.substring(pos), filterstring);
+ }
+
+ pos++;
+
+ skipWhiteSpace();
+
+ return filter;
+ }
+
+ private FilterImpl parse_filtercomp() throws InvalidSyntaxException {
+ skipWhiteSpace();
+
+ char c = filterChars[pos];
+
+ switch (c) {
+ case '&' : {
+ pos++;
+ return parse_and();
+ }
+ case '|' : {
+ pos++;
+ return parse_or();
+ }
+ case '!' : {
+ pos++;
+ return parse_not();
+ }
+ }
+ return parse_item();
+ }
+
+ private FilterImpl parse_and() throws InvalidSyntaxException {
+ skipWhiteSpace();
+
+ if (filterChars[pos] != '(') {
+ throw new InvalidSyntaxException("Missing '(': "
+ + filterstring.substring(pos), filterstring);
+ }
+
+ List operands = new ArrayList(10);
+
+ while (filterChars[pos] == '(') {
+ FilterImpl child = parse_filter();
+ operands.add(child);
+ }
+
+ return new FilterImpl(FilterImpl.AND, null, operands
+ .toArray(new FilterImpl[operands.size()]));
+ }
+
+ private FilterImpl parse_or() throws InvalidSyntaxException {
+ skipWhiteSpace();
+
+ if (filterChars[pos] != '(') {
+ throw new InvalidSyntaxException("Missing '(': "
+ + filterstring.substring(pos), filterstring);
+ }
+
+ List operands = new ArrayList(10);
+
+ while (filterChars[pos] == '(') {
+ FilterImpl child = parse_filter();
+ operands.add(child);
+ }
+
+ return new FilterImpl(FilterImpl.OR, null, operands
+ .toArray(new FilterImpl[operands.size()]));
+ }
+
+ private FilterImpl parse_not() throws InvalidSyntaxException {
+ skipWhiteSpace();
+
+ if (filterChars[pos] != '(') {
+ throw new InvalidSyntaxException("Missing '(': "
+ + filterstring.substring(pos), filterstring);
+ }
+
+ FilterImpl child = parse_filter();
+
+ return new FilterImpl(FilterImpl.NOT, null, child);
+ }
+
+ private FilterImpl parse_item() throws InvalidSyntaxException {
+ String attr = parse_attr();
+
+ skipWhiteSpace();
+
+ switch (filterChars[pos]) {
+ case '~' : {
+ if (filterChars[pos + 1] == '=') {
+ pos += 2;
+ return new FilterImpl(FilterImpl.APPROX, attr,
+ parse_value());
+ }
+ break;
+ }
+ case '>' : {
+ if (filterChars[pos + 1] == '=') {
+ pos += 2;
+ return new FilterImpl(FilterImpl.GREATER, attr,
+ parse_value());
+ }
+ break;
+ }
+ case '<' : {
+ if (filterChars[pos + 1] == '=') {
+ pos += 2;
+ return new FilterImpl(FilterImpl.LESS, attr,
+ parse_value());
+ }
+ break;
+ }
+ case '=' : {
+ if (filterChars[pos + 1] == '*') {
+ int oldpos = pos;
+ pos += 2;
+ skipWhiteSpace();
+ if (filterChars[pos] == ')') {
+ return new FilterImpl(FilterImpl.PRESENT, attr,
+ null);
+ }
+ pos = oldpos;
+ }
+
+ pos++;
+ Object string = parse_substring();
+
+ if (string instanceof String) {
+ return new FilterImpl(FilterImpl.EQUAL, attr,
+ string);
+ }
+ return new FilterImpl(FilterImpl.SUBSTRING, attr,
+ string);
+ }
+ }
+
+ throw new InvalidSyntaxException("Invalid operator: "
+ + filterstring.substring(pos), filterstring);
+ }
+
+ private String parse_attr() throws InvalidSyntaxException {
+ skipWhiteSpace();
+
+ int begin = pos;
+ int end = pos;
+
+ char c = filterChars[pos];
+
+ while (c != '~' && c != '<' && c != '>' && c != '=' && c != '('
+ && c != ')') {
+ pos++;
+
+ if (!Character.isWhitespace(c)) {
+ end = pos;
+ }
+
+ c = filterChars[pos];
+ }
+
+ int length = end - begin;
+
+ if (length == 0) {
+ throw new InvalidSyntaxException("Missing attr: "
+ + filterstring.substring(pos), filterstring);
+ }
+
+ return new String(filterChars, begin, length);
+ }
+
+ private String parse_value() throws InvalidSyntaxException {
+ StringBuffer sb = new StringBuffer(filterChars.length - pos);
+
+ parseloop: while (true) {
+ char c = filterChars[pos];
+
+ switch (c) {
+ case ')' : {
+ break parseloop;
+ }
+
+ case '(' : {
+ throw new InvalidSyntaxException("Invalid value: "
+ + filterstring.substring(pos), filterstring);
+ }
+
+ case '\\' : {
+ pos++;
+ c = filterChars[pos];
+ /* fall through into default */
+ }
+
+ default : {
+ sb.append(c);
+ pos++;
+ break;
+ }
+ }
+ }
+
+ if (sb.length() == 0) {
+ throw new InvalidSyntaxException("Missing value: "
+ + filterstring.substring(pos), filterstring);
+ }
+
+ return sb.toString();
+ }
+
+ private Object parse_substring() throws InvalidSyntaxException {
+ StringBuffer sb = new StringBuffer(filterChars.length - pos);
+
+ List operands = new ArrayList(10);
+
+ parseloop: while (true) {
+ char c = filterChars[pos];
+
+ switch (c) {
+ case ')' : {
+ if (sb.length() > 0) {
+ operands.add(sb.toString());
+ }
+
+ break parseloop;
+ }
+
+ case '(' : {
+ throw new InvalidSyntaxException("Invalid value: "
+ + filterstring.substring(pos), filterstring);
+ }
+
+ case '*' : {
+ if (sb.length() > 0) {
+ operands.add(sb.toString());
+ }
+
+ sb.setLength(0);
+
+ operands.add(null);
+ pos++;
+
+ break;
+ }
+
+ case '\\' : {
+ pos++;
+ c = filterChars[pos];
+ /* fall through into default */
+ }
+
+ default : {
+ sb.append(c);
+ pos++;
+ break;
+ }
+ }
+ }
+
+ int size = operands.size();
+
+ if (size == 0) {
+ throw new InvalidSyntaxException("Missing value: "
+ + filterstring.substring(pos), filterstring);
+ }
+
+ if (size == 1) {
+ Object single = operands.get(0);
+
+ if (single != null) {
+ return single;
+ }
+ }
+
+ return operands.toArray(new String[size]);
+ }
+
+ private void skipWhiteSpace() {
+ for (int length = filterChars.length; (pos < length)
+ && Character.isWhitespace(filterChars[pos]);) {
+ pos++;
+ }
}
}
- catch (InvalidSyntaxException e) {
- throw e;
+ }
+
+ /**
+ * This Dictionary is used for case-insensitive key lookup during filter
+ * evaluation. This Dictionary implementation only supports the get
+ * operation using a String key as no other operations are used by the
+ * Filter implementation.
+ */
+ private static class CaseInsensitiveDictionary extends Dictionary {
+ private final Dictionary dictionary;
+ private final String[] keys;
+
+ /**
+ * Create a case insensitive dictionary from the specified dictionary.
+ *
+ * @param dictionary
+ * @throws IllegalArgumentException If <code>dictionary</code> contains
+ * case variants of the same key name.
+ */
+ CaseInsensitiveDictionary(Dictionary dictionary) {
+ if (dictionary == null) {
+ this.dictionary = null;
+ this.keys = new String[0];
+ return;
+ }
+ this.dictionary = dictionary;
+ List keyList = new ArrayList(dictionary.size());
+ for (Enumeration e = dictionary.keys(); e.hasMoreElements();) {
+ Object k = e.nextElement();
+ if (k instanceof String) {
+ String key = (String) k;
+ for (Iterator i = keyList.iterator(); i.hasNext();) {
+ if (key.equalsIgnoreCase((String) i.next())) {
+ throw new IllegalArgumentException();
+ }
+ }
+ keyList.add(key);
+ }
+ }
+ this.keys = (String[]) keyList.toArray(new String[keyList.size()]);
}
- catch (Error e) {
- throw e;
+
+ public Object get(Object o) {
+ String k = (String) o;
+ for (int i = 0, length = keys.length; i < length; i++) {
+ String key = keys[i];
+ if (key.equalsIgnoreCase(k)) {
+ return dictionary.get(key);
+ }
+ }
+ return null;
}
- catch (RuntimeException e) {
- throw e;
+
+ public boolean isEmpty() {
+ throw new UnsupportedOperationException();
}
- catch (Throwable e) {
- throw new RuntimeException(e.toString());
+
+ public Enumeration keys() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Enumeration elements() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object put(Object key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int size() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * This Dictionary is used for key lookup from a ServiceReference during
+ * filter evaluation. This Dictionary implementation only supports the get
+ * operation using a String key as no other operations are used by the
+ * Filter implementation.
+ */
+ private static class ServiceReferenceDictionary extends Dictionary {
+ private final ServiceReference reference;
+
+ ServiceReferenceDictionary(ServiceReference reference) {
+ this.reference = reference;
+ }
+
+ public Object get(Object key) {
+ if (reference == null) {
+ return null;
+ }
+ return reference.getProperty((String) key);
+ }
+
+ public boolean isEmpty() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Enumeration keys() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Enumeration elements() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object put(Object key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int size() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private static class SetAccessibleAction implements PrivilegedAction {
+ private final AccessibleObject accessible;
+
+ SetAccessibleAction(AccessibleObject accessible) {
+ this.accessible = accessible;
+ }
+
+ public Object run() {
+ accessible.setAccessible(true);
+ return null;
+ }
+ }
+
+ /**
+ * This class contains a method to match a distinguished name (DN) chain
+ * against and DN chain pattern.
+ * <p>
+ * The format of DNs are given in RFC 2253. We represent a signature chain
+ * for an X.509 certificate as a semicolon separated list of DNs. This is
+ * what we refer to as the DN chain. Each DN is made up of relative
+ * distinguished names (RDN) which in turn are made up of key value pairs.
+ * For example:
+ *
+ * <pre>
+ * cn=ben+ou=research,o=ACME,c=us;ou=Super CA,c=CA
+ * </pre>
+ *
+ * is made up of two DNs: "<code>cn=ben+ou=research,o=ACME,c=us</code>
+ * " and " <code>ou=Super CA,c=CA</code>
+ * ". The first DN is made of of three RDNs: "
+ * <code>cn=ben+ou=research</code>" and "<code>o=ACME</code>" and "
+ * <code>c=us</code>". The first RDN has two name value pairs: "
+ * <code>cn=ben</code>" and "<code>ou=research</code>".
+ * <p>
+ * A chain pattern makes use of wildcards ('*' or '-') to match against DNs,
+ * and wildcards ('*') to match againts DN prefixes, and value. If a DN in a
+ * match pattern chain is made up of a wildcard ("*"), that wildcard will
+ * match zero or one DNs in the chain. If a DN in a match pattern chain is
+ * made up of a wildcard ("-"), that wildcard will match zero or more DNs in
+ * the chain. If the first RDN of a DN is the wildcard ("*"), that DN will
+ * match any other DN with the same suffix (the DN with the wildcard RDN
+ * removed). If a value of a name/value pair is a wildcard ("*"), the value
+ * will match any value for that name.
+ */
+ private static class DNChainMatching {
+ private static final String MINUS_WILDCARD = "-";
+ private static final String STAR_WILDCARD = "*";
+
+ /**
+ * Check the name/value pairs of the rdn against the pattern.
+ *
+ * @param rdn ArrayList of name value pairs for a given RDN.
+ * @param rdnPattern ArrayList of name value pattern pairs.
+ * @return true if the list of name value pairs match the pattern.
+ */
+ private static boolean rdnmatch(ArrayList rdn, ArrayList rdnPattern) {
+ if (rdn.size() != rdnPattern.size()) {
+ return false;
+ }
+ for (int i = 0; i < rdn.size(); i++) {
+ String rdnNameValue = (String) rdn.get(i);
+ String patNameValue = (String) rdnPattern.get(i);
+ int rdnNameEnd = rdnNameValue.indexOf('=');
+ int patNameEnd = patNameValue.indexOf('=');
+ if (rdnNameEnd != patNameEnd
+ || !rdnNameValue.regionMatches(0, patNameValue, 0,
+ rdnNameEnd)) {
+ return false;
+ }
+ String patValue = patNameValue.substring(patNameEnd);
+ String rdnValue = rdnNameValue.substring(rdnNameEnd);
+ if (!rdnValue.equals(patValue) && !patValue.equals("=*")
+ && !patValue.equals("=#16012a")) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean dnmatch(ArrayList dn, ArrayList dnPattern) {
+ int dnStart = 0;
+ int patStart = 0;
+ int patLen = dnPattern.size();
+ if (patLen == 0) {
+ return false;
+ }
+ if (dnPattern.get(0).equals(STAR_WILDCARD)) {
+ patStart = 1;
+ patLen--;
+ }
+ if (dn.size() < patLen) {
+ return false;
+ }
+ else {
+ if (dn.size() > patLen) {
+ if (!dnPattern.get(0).equals(STAR_WILDCARD)) {
+ // If the number of rdns do not match we must have a
+ // prefix
+ // map
+ return false;
+ }
+ // The rdnPattern and rdn must have the same number of
+ // elements
+ dnStart = dn.size() - patLen;
+ }
+ }
+ for (int i = 0; i < patLen; i++) {
+ if (!rdnmatch((ArrayList) dn.get(i + dnStart),
+ (ArrayList) dnPattern.get(i + patStart))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Parses a distinguished name chain pattern and returns an ArrayList
+ * where each element represents a distinguished name (DN) in the chain
+ * of DNs. Each element will be either a String, if the element
+ * represents a wildcard ("*" or "-"), or an ArrayList representing an
+ * RDN. Each element in the RDN ArrayList will be a String, if the
+ * element represents a wildcard ("*"), or an ArrayList of Strings, each
+ * String representing a name/value pair in the RDN.
+ *
+ * @param dnChain
+ * @return a list of DNs.
+ * @throws IllegalArgumentException
+ */
+ private static ArrayList parseDNchainPattern(String dnChain) {
+ if (dnChain == null) {
+ throw new IllegalArgumentException(
+ "The DN chain must not be null.");
+ }
+ ArrayList parsed = new ArrayList();
+ int startIndex = 0;
+ startIndex = skipSpaces(dnChain, startIndex);
+ while (startIndex < dnChain.length()) {
+ int endIndex = startIndex;
+ boolean inQuote = false;
+ out: while (endIndex < dnChain.length()) {
+ char c = dnChain.charAt(endIndex);
+ switch (c) {
+ case '"' :
+ inQuote = !inQuote;
+ break;
+ case '\\' :
+ endIndex++; // skip the escaped char
+ break;
+ case ';' :
+ if (!inQuote)
+ break out;
+ }
+ endIndex++;
+ }
+ if (endIndex > dnChain.length()) {
+ throw new IllegalArgumentException("unterminated escape");
+ }
+ parsed.add(dnChain.substring(startIndex, endIndex));
+ startIndex = endIndex + 1;
+ startIndex = skipSpaces(dnChain, startIndex);
+ }
+ parseDNchain(parsed);
+ return parsed;
+ }
+
+ private static List parseDNchain(List chain) {
+ if (chain == null) {
+ throw new IllegalArgumentException("DN chain must not be null.");
+ }
+ // Now we parse is a list of strings, lets make ArrayList of rdn out
+ // of
+ // them
+ for (int i = 0; i < chain.size(); i++) {
+ String dn = (String) chain.get(i);
+ if (dn.equals(STAR_WILDCARD) || dn.equals(MINUS_WILDCARD)) {
+ continue;
+ }
+ ArrayList rdns = new ArrayList();
+ if (dn.charAt(0) == '*') {
+ if (dn.charAt(1) != ',') {
+ throw new IllegalArgumentException(
+ "invalid wildcard prefix");
+ }
+ rdns.add(STAR_WILDCARD);
+ dn = new X500Principal(dn.substring(2))
+ .getName(X500Principal.CANONICAL);
+ }
+ else {
+ dn = new X500Principal(dn).getName(X500Principal.CANONICAL);
+ }
+ // Now dn is a nice CANONICAL DN
+ parseDN(dn, rdns);
+ chain.set(i, rdns);
+ }
+ if (chain.size() == 0) {
+ throw new IllegalArgumentException("empty DN chain");
+ }
+ return chain;
+ }
+
+ /**
+ * Increment startIndex until the end of dnChain is hit or until it is
+ * the index of a non-space character.
+ */
+ private static int skipSpaces(String dnChain, int startIndex) {
+ while (startIndex < dnChain.length()
+ && dnChain.charAt(startIndex) == ' ') {
+ startIndex++;
+ }
+ return startIndex;
+ }
+
+ /**
+ * Takes a distinguished name in canonical form and fills in the
+ * rdnArray with the extracted RDNs.
+ *
+ * @param dn the distinguished name in canonical form.
+ * @param rdnArray the array to fill in with RDNs extracted from the dn
+ * @throws IllegalArgumentException if a formatting error is found.
+ */
+ private static void parseDN(String dn, ArrayList rdnArray) {
+ int startIndex = 0;
+ char c = '\0';
+ ArrayList nameValues = new ArrayList();
+ while (startIndex < dn.length()) {
+ int endIndex;
+ for (endIndex = startIndex; endIndex < dn.length(); endIndex++) {
+ c = dn.charAt(endIndex);
+ if (c == ',' || c == '+') {
+ break;
+ }
+ if (c == '\\') {
+ endIndex++; // skip the escaped char
+ }
+ }
+ if (endIndex > dn.length()) {
+ throw new IllegalArgumentException("unterminated escape "
+ + dn);
+ }
+ nameValues.add(dn.substring(startIndex, endIndex));
+ if (c != '+') {
+ rdnArray.add(nameValues);
+ if (endIndex != dn.length()) {
+ nameValues = new ArrayList();
+ }
+ else {
+ nameValues = null;
+ }
+ }
+ startIndex = endIndex + 1;
+ }
+ if (nameValues != null) {
+ throw new IllegalArgumentException("improperly terminated DN "
+ + dn);
+ }
+ }
+
+ /**
+ * This method will return an 'index' which points to a non-wildcard DN
+ * or the end-of-arraylist.
+ */
+ private static int skipWildCards(List dnChainPattern,
+ int dnChainPatternIndex) {
+ int i;
+ for (i = dnChainPatternIndex; i < dnChainPattern.size(); i++) {
+ Object dnPattern = dnChainPattern.get(i);
+ if (dnPattern instanceof String) {
+ if (!dnPattern.equals(STAR_WILDCARD)
+ && !dnPattern.equals(MINUS_WILDCARD)) {
+ throw new IllegalArgumentException(
+ "expected wildcard in DN pattern");
+ }
+ // otherwise continue skipping over wild cards
+ }
+ else {
+ if (dnPattern instanceof ArrayList) {
+ // if its an arraylist then we have our 'non-wildcard'
+ // DN
+ break;
+ }
+ else {
+ // unknown member of the DNChainPattern
+ throw new IllegalArgumentException(
+ "expected String or Arraylist in DN Pattern");
+ }
+ }
+ }
+ // i either points to end-of-arraylist, or to the first
+ // non-wildcard
+ // pattern
+ // after dnChainPatternIndex
+ return i;
+ }
+
+ /**
+ * recursively attempt to match the DNChain, and the DNChainPattern
+ * where DNChain is of the format: "DN;DN;DN;" and DNChainPattern is of
+ * the format: "DNPattern;*;DNPattern" (or combinations of this)
+ */
+ private static boolean dnChainMatch(List dnChain, int dnChainIndex,
+ List dnChainPattern, int dnChainPatternIndex)
+ throws IllegalArgumentException {
+ if (dnChainIndex >= dnChain.size()) {
+ return false;
+ }
+ if (dnChainPatternIndex >= dnChainPattern.size()) {
+ return false;
+ }
+ // check to see what the pattern starts with
+ Object dnPattern = dnChainPattern.get(dnChainPatternIndex);
+ if (dnPattern instanceof String) {
+ if (!dnPattern.equals(STAR_WILDCARD)
+ && !dnPattern.equals(MINUS_WILDCARD)) {
+ throw new IllegalArgumentException(
+ "expected wildcard in DN pattern");
+ }
+ // here we are processing a wild card as the first DN
+ // skip all wildcard DN's
+ if (dnPattern.equals(MINUS_WILDCARD)) {
+ dnChainPatternIndex = skipWildCards(dnChainPattern,
+ dnChainPatternIndex);
+ }
+ else {
+ dnChainPatternIndex++; // only skip the '*' wildcard
+ }
+ if (dnChainPatternIndex >= dnChainPattern.size()) {
+ // return true iff the wild card is '-' or if we are at the
+ // end of the chain
+ return dnPattern.equals(MINUS_WILDCARD) ? true : dnChain
+ .size() - 1 == dnChainIndex;
+ }
+ //
+ // we will now recursively call to see if the rest of the
+ // DNChainPattern
+ // matches increasingly smaller portions of the rest of the
+ // DNChain
+ //
+ if (dnPattern.equals(STAR_WILDCARD)) {
+ // '*' option: only wildcard on 0 or 1
+ return dnChainMatch(dnChain, dnChainIndex, dnChainPattern,
+ dnChainPatternIndex)
+ || dnChainMatch(dnChain, dnChainIndex + 1,
+ dnChainPattern, dnChainPatternIndex);
+ }
+ for (int i = dnChainIndex; i < dnChain.size(); i++) {
+ // '-' option: wildcard 0 or more
+ if (dnChainMatch(dnChain, i, dnChainPattern,
+ dnChainPatternIndex)) {
+ return true;
+ }
+ }
+ // if we are here, then we didn't find a match.. fall through to
+ // failure
+ }
+ else {
+ if (dnPattern instanceof ArrayList) {
+ // here we have to do a deeper check for each DN in the
+ // pattern
+ // until we hit a wild card
+ do {
+ if (!dnmatch((ArrayList) dnChain.get(dnChainIndex),
+ (ArrayList) dnPattern)) {
+ return false;
+ }
+ // go to the next set of DN's in both chains
+ dnChainIndex++;
+ dnChainPatternIndex++;
+ // if we finished the pattern then it all matched
+ if ((dnChainIndex >= dnChain.size())
+ && (dnChainPatternIndex >= dnChainPattern
+ .size())) {
+ return true;
+ }
+ // if the DN Chain is finished, but the pattern isn't
+ // finished
+ // then if the rest of the pattern is not wildcard then
+ // we
+ // are
+ // done
+ if (dnChainIndex >= dnChain.size()) {
+ dnChainPatternIndex = skipWildCards(dnChainPattern,
+ dnChainPatternIndex);
+ // return TRUE iff the pattern index moved past the
+ // array-size
+ // (implying that the rest of the pattern is all
+ // wildcards)
+ return dnChainPatternIndex >= dnChainPattern.size();
+ }
+ // if the pattern finished, but the chain continues then
+ // we
+ // have
+ // a mis-match
+ if (dnChainPatternIndex >= dnChainPattern.size()) {
+ return false;
+ }
+ // get the next DN Pattern
+ dnPattern = dnChainPattern.get(dnChainPatternIndex);
+ if (dnPattern instanceof String) {
+ if (!dnPattern.equals(STAR_WILDCARD)
+ && !dnPattern.equals(MINUS_WILDCARD)) {
+ throw new IllegalArgumentException(
+ "expected wildcard in DN pattern");
+ }
+ // if the next DN is a 'wildcard', then we will
+ // recurse
+ return dnChainMatch(dnChain, dnChainIndex,
+ dnChainPattern, dnChainPatternIndex);
+ }
+ else {
+ if (!(dnPattern instanceof ArrayList)) {
+ throw new IllegalArgumentException(
+ "expected String or Arraylist in DN Pattern");
+ }
+ }
+ // if we are here, then we will just continue to the
+ // match
+ // the
+ // next set of DN's from the DNChain, and the
+ // DNChainPattern
+ // since both are array-lists
+ } while (true);
+ // should never reach here?
+ }
+ else {
+ throw new IllegalArgumentException(
+ "expected String or Arraylist in DN Pattern");
+ }
+ }
+ // if we get here, the the default return is 'mis-match'
+ return false;
+ }
+
+ /**
+ * Matches a distinguished name chain against a pattern of a
+ * distinguished name chain.
+ *
+ * @param dnChain
+ * @param pattern the pattern of distinguished name (DN) chains to match
+ * against the dnChain. Wildcards ("*" or "-") can be used in
+ * three cases:
+ * <ol>
+ * <li>As a DN. In this case, the DN will consist of just the "*"
+ * or "-". When "*" is used it will match zero or one DNs. When
+ * "-" is used it will match zero or more DNs. For example,
+ * "cn=me,c=US;*;cn=you" will match
+ * "cn=me,c=US";cn=you" and "cn=me,c=US;cn=her;cn=you". The
+ * pattern "cn=me,c=US;-;cn=you" will match "cn=me,c=US";cn=you"
+ * and "cn=me,c=US;cn=her;cn=him;cn=you".
+ * <li>As a DN prefix. In this case, the DN must start with "*,".
+ * The wild card will match zero or more RDNs at the start of a
+ * DN. For example, "*,cn=me,c=US;cn=you" will match
+ * "cn=me,c=US";cn=you" and
+ * "ou=my org unit,o=my org,cn=me,c=US;cn=you"</li>
+ * <li>As a value. In this case the value of a name value pair in
+ * an RDN will be a "*". The wildcard will match any value for
+ * the given name. For example, "cn=*,c=US;cn=you" will match
+ * "cn=me,c=US";cn=you" and "cn=her,c=US;cn=you", but it will not
+ * match "ou=my org unit,c=US;cn=you". If the wildcard does not
+ * occur by itself in the value, it will not be used as a
+ * wildcard. In other words, "cn=m*,c=US;cn=you" represents the
+ * common name of "m*" not any common name starting with "m".</li>
+ * </ol>
+ * @return true if dnChain matches the pattern.
+ * @throws IllegalArgumentException
+ */
+ static boolean match(String pattern, List/* <String> */dnChain) {
+ List parsedDNChain;
+ List parsedDNPattern;
+ try {
+ parsedDNChain = parseDNchain(dnChain);
+ }
+ catch (IllegalArgumentException e) {
+ throw (IllegalArgumentException) new IllegalArgumentException(
+ "Invalid DN chain: " + toString(dnChain)).initCause(e);
+ }
+ try {
+ parsedDNPattern = parseDNchainPattern(pattern);
+ }
+ catch (IllegalArgumentException e) {
+ throw (IllegalArgumentException) new IllegalArgumentException(
+ "Invalid match pattern: " + pattern).initCause(e);
+ }
+ return dnChainMatch(parsedDNChain, 0, parsedDNPattern, 0);
+ }
+
+ private static String toString(List dnChain) {
+ if (dnChain == null) {
+ return null;
+ }
+ StringBuffer sb = new StringBuffer();
+ for (Iterator iChain = dnChain.iterator(); iChain.hasNext();) {
+ sb.append(iChain.next());
+ if (iChain.hasNext()) {
+ sb.append("; ");
+ }
+ }
+ return sb.toString();
}
}
}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/InvalidSyntaxException.java b/org.osgi.core/src/main/java/org/osgi/framework/InvalidSyntaxException.java
index b69c120..f67fd43 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/InvalidSyntaxException.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/InvalidSyntaxException.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/InvalidSyntaxException.java,v 1.16 2007/02/20 00:15:00 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,10 +26,9 @@
* {@link Filter} for a description of the filter string syntax.
*
* <p>
- * This exception is updated to conform to the general purpose exception
- * chaining mechanism.
+ * This exception conforms to the general purpose exception chaining mechanism.
*
- * @version $Revision: 1.16 $
+ * @version $Revision: 6083 $
*/
public class InvalidSyntaxException extends Exception {
@@ -40,10 +37,6 @@
* The invalid filter string.
*/
private final String filter;
- /**
- * Nested exception.
- */
- private final Throwable cause;
/**
* Creates an exception of type <code>InvalidSyntaxException</code>.
@@ -59,7 +52,6 @@
public InvalidSyntaxException(String msg, String filter) {
super(msg);
this.filter = filter;
- this.cause = null;
}
/**
@@ -76,9 +68,8 @@
* @since 1.3
*/
public InvalidSyntaxException(String msg, String filter, Throwable cause) {
- super(msg);
+ super(msg, cause);
this.filter = filter;
- this.cause = cause;
}
/**
@@ -94,28 +85,29 @@
}
/**
- * Returns the cause of this exception or <code>null</code> if no cause
- * was specified when this exception was created.
+ * Returns the cause of this exception or <code>null</code> if no cause was
+ * set.
*
- * @return The cause of this exception or <code>null</code> if no cause
- * was specified.
+ * @return The cause of this exception or <code>null</code> if no cause was
+ * set.
* @since 1.3
*/
public Throwable getCause() {
- return cause;
+ return super.getCause();
}
/**
- * The cause of this exception can only be set when constructed.
+ * Initializes the cause of this exception to the specified value.
*
- * @param cause Cause of the exception.
- * @return This object.
- * @throws java.lang.IllegalStateException This method will always throw an
- * <code>IllegalStateException</code> since the cause of this
- * exception can only be set when constructed.
+ * @param cause The cause of this exception.
+ * @return This exception.
+ * @throws IllegalArgumentException If the specified cause is this
+ * exception.
+ * @throws IllegalStateException If the cause of this exception has already
+ * been set.
* @since 1.3
*/
public Throwable initCause(Throwable cause) {
- throw new IllegalStateException();
+ return super.initCause(cause);
}
}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/PackagePermission.java b/org.osgi.core/src/main/java/org/osgi/framework/PackagePermission.java
index 762bce1..fc319e8 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/PackagePermission.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/PackagePermission.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/PackagePermission.java,v 1.14 2006/06/16 16:31:18 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,9 +17,25 @@
package org.osgi.framework;
import java.io.IOException;
-import java.security.*;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.security.AccessController;
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
/**
* A bundle's authority to import or export a package.
@@ -33,54 +47,90 @@
* For example:
*
* <pre>
- * <code>
* org.osgi.service.http
- * </code>
* </pre>
*
* <p>
- * <code>PackagePermission</code> has two actions: <code>EXPORT</code> and
- * <code>IMPORT</code>. The <code>EXPORT</code> action implies the
- * <code>IMPORT</code> action.
+ * <code>PackagePermission</code> has three actions: <code>exportonly</code>,
+ * <code>import</code> and <code>export</code>. The <code>export</code> action,
+ * which is deprecated, implies the <code>import</code> action.
*
- * @version $Revision: 1.14 $
+ * @ThreadSafe
+ * @version $Revision: 6530 $
*/
public final class PackagePermission extends BasicPermission {
- static final long serialVersionUID = -5107705877071099135L;
+ static final long serialVersionUID = -5107705877071099135L;
+
/**
- * The action string <code>export</code>.
+ * The action string <code>export</code>. The <code>export</code> action
+ * implies the <code>import</code> action.
+ *
+ * @deprecated Since 1.5. Use <code>exportonly</code> instead.
*/
- public final static String EXPORT = "export";
+ public final static String EXPORT = "export";
+
+ /**
+ * The action string <code>exportonly</code>. The <code>exportonly</code>
+ * action does not imply the <code>import</code> action.
+ *
+ * @since 1.5
+ */
+ public final static String EXPORTONLY = "exportonly";
/**
* The action string <code>import</code>.
*/
- public final static String IMPORT = "import";
+ public final static String IMPORT = "import";
- private final static int ACTION_EXPORT = 0x00000001;
- private final static int ACTION_IMPORT = 0x00000002;
- private final static int ACTION_ALL = ACTION_EXPORT
- | ACTION_IMPORT;
- private final static int ACTION_NONE = 0;
+ private final static int ACTION_EXPORT = 0x00000001;
+ private final static int ACTION_IMPORT = 0x00000002;
+ private final static int ACTION_ALL = ACTION_EXPORT
+ | ACTION_IMPORT;
+ final static int ACTION_NONE = 0;
+
/**
* The actions mask.
*/
- private transient int action_mask = ACTION_NONE;
+ transient int action_mask;
/**
* The actions in canonical form.
*
* @serial
*/
- private String actions = null;
+ private volatile String actions = null;
/**
- * Defines the authority to import and/or export a package within the OSGi
- * environment.
+ * The bundle used by this PackagePermission.
+ */
+ transient final Bundle bundle;
+
+ /**
+ * If this PackagePermission was constructed with a filter, this holds a
+ * Filter matching object used to evaluate the filter in implies.
+ */
+ transient Filter filter;
+
+ /**
+ * This dictionary holds the properties of the permission, used to match a
+ * filter in implies. This is not initialized until necessary, and then
+ * cached in this object.
+ */
+ private transient volatile Dictionary properties;
+
+ /**
+ * Creates a new <code>PackagePermission</code> object.
+ *
* <p>
* The name is specified as a normal Java package name: a dot-separated
- * string. Wildcards may be used. For example:
+ * string. Wildcards may be used.
+ *
+ * <pre>
+ * name ::= <package name> | <package name ending in ".*"> | *
+ * </pre>
+ *
+ * Examples:
*
* <pre>
* org.osgi.service.http
@@ -88,34 +138,85 @@
* *
* </pre>
*
+ * For the <code>import</code> action, the name can also be a filter
+ * expression. The filter gives access to the following attributes:
+ * <ul>
+ * <li>signer - A Distinguished Name chain used to sign the exporting
+ * bundle. Wildcards in a DN are not matched according to the filter string
+ * rules, but according to the rules defined for a DN chain.</li>
+ * <li>location - The location of the exporting bundle.</li>
+ * <li>id - The bundle ID of the exporting bundle.</li>
+ * <li>name - The symbolic name of the exporting bundle.</li>
+ * <li>package.name - The name of the requested package.</li>
+ * </ul>
+ * Filter attribute names are processed in a case sensitive manner.
+ *
* <p>
* Package Permissions are granted over all possible versions of a package.
*
* A bundle that needs to export a package must have the appropriate
- * <code>PackagePermission</code> for that package; similarly, a bundle
- * that needs to import a package must have the appropriate
+ * <code>PackagePermission</code> for that package; similarly, a bundle that
+ * needs to import a package must have the appropriate
* <code>PackagePermssion</code> for that package.
* <p>
* Permission is granted for both classes and resources.
*
- * @param name Package name.
- * @param actions <code>EXPORT</code>,<code>IMPORT</code> (canonical
+ * @param name Package name or filter expression. A filter expression can
+ * only be specified if the specified action is <code>import</code>.
+ * @param actions <code>exportonly</code>,<code>import</code> (canonical
* order).
+ * @throw IllegalArgumentException If the specified name is a filter
+ * expression and either the specified action is not
+ * <code>import</code> or the filter has an invalid syntax.
*/
-
public PackagePermission(String name, String actions) {
- this(name, getMask(actions));
+ this(name, parseActions(actions));
+ if ((filter != null)
+ && ((action_mask & ACTION_ALL) != ACTION_IMPORT)) {
+ throw new IllegalArgumentException(
+ "invalid action string for filter expression");
+ }
+ }
+
+ /**
+ * Creates a new requested <code>PackagePermission</code> object to be used
+ * by code that must perform <code>checkPermission</code> for the
+ * <code>import</code> action. <code>PackagePermission</code> objects
+ * created with this constructor cannot be added to a
+ * <code>PackagePermission</code> permission collection.
+ *
+ * @param name The name of the requested package to import.
+ * @param exportingBundle The bundle exporting the requested package.
+ * @param actions The action <code>import</code>.
+ * @throw IllegalArgumentException If the specified action is not
+ * <code>import</code> or the name is a filter expression.
+ * @since 1.5
+ */
+ public PackagePermission(String name, Bundle exportingBundle, String actions) {
+ super(name);
+ setTransients(name, parseActions(actions));
+ this.bundle = exportingBundle;
+ if (exportingBundle == null) {
+ throw new IllegalArgumentException("bundle must not be null");
+ }
+ if (filter != null) {
+ throw new IllegalArgumentException("invalid name");
+ }
+ if ((action_mask & ACTION_ALL) != ACTION_IMPORT) {
+ throw new IllegalArgumentException("invalid action string");
+ }
}
/**
* Package private constructor used by PackagePermissionCollection.
*
- * @param name class name
+ * @param name package name
* @param mask action mask
*/
PackagePermission(String name, int mask) {
super(name);
- init(mask);
+ setTransients(name, mask);
+ this.bundle = null;
}
/**
@@ -123,12 +224,12 @@
*
* @param mask action mask
*/
- private void init(int mask) {
+ private void setTransients(String name, int mask) {
if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
throw new IllegalArgumentException("invalid action string");
}
-
action_mask = mask;
+ filter = parseFilter(name);
}
/**
@@ -137,20 +238,20 @@
* @param actions Action string.
* @return action mask.
*/
- private static int getMask(String actions) {
+ private static int parseActions(String actions) {
boolean seencomma = false;
int mask = ACTION_NONE;
if (actions == null) {
- return (mask);
+ return mask;
}
char[] a = actions.toCharArray();
int i = a.length - 1;
if (i < 0)
- return (mask);
+ return mask;
while (i != -1) {
char c;
@@ -186,9 +287,25 @@
}
else {
- // parse error
- throw new IllegalArgumentException("invalid permission: "
- + actions);
+ if (i >= 9 && (a[i - 9] == 'e' || a[i - 9] == 'E')
+ && (a[i - 8] == 'x' || a[i - 8] == 'X')
+ && (a[i - 7] == 'p' || a[i - 7] == 'P')
+ && (a[i - 6] == 'o' || a[i - 6] == 'O')
+ && (a[i - 5] == 'r' || a[i - 5] == 'R')
+ && (a[i - 4] == 't' || a[i - 4] == 'T')
+ && (a[i - 3] == 'o' || a[i - 3] == 'O')
+ && (a[i - 2] == 'n' || a[i - 2] == 'N')
+ && (a[i - 1] == 'l' || a[i - 1] == 'L')
+ && (a[i] == 'y' || a[i] == 'Y')) {
+ matchlen = 10;
+ mask |= ACTION_EXPORT;
+
+ }
+ else {
+ // parse error
+ throw new IllegalArgumentException(
+ "invalid permission: " + actions);
+ }
}
// make sure we didn't just match the tail of a word
@@ -198,7 +315,7 @@
switch (a[i - matchlen]) {
case ',' :
seencomma = true;
- /* FALLTHROUGH */
+ /* FALLTHROUGH */
case ' ' :
case '\r' :
case '\n' :
@@ -220,7 +337,32 @@
throw new IllegalArgumentException("invalid permission: " + actions);
}
- return (mask);
+ return mask;
+ }
+
+ /**
+ * Parse filter string into a Filter object.
+ *
+ * @param filterString The filter string to parse.
+ * @return a Filter for this bundle. If the specified filterString is not a
+ * filter expression, then <code>null</code> is returned.
+ * @throws IllegalArgumentException If the filter syntax is invalid.
+ */
+ private static Filter parseFilter(String filterString) {
+ filterString = filterString.trim();
+ if (filterString.charAt(0) != '(') {
+ return null;
+ }
+
+ try {
+ return FrameworkUtil.createFilter(filterString);
+ }
+ catch (InvalidSyntaxException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "invalid filter");
+ iae.initCause(e);
+ throw iae;
+ }
}
/**
@@ -242,21 +384,49 @@
* x.y,"export" -> x.y.z, "export" is false
* </pre>
*
- * @param p The target permission to interrogate.
- * @return <code>true</code> if the specified
- * <code>PackagePermission</code> action is implied by this
+ * @param p The requested permission.
+ * @return <code>true</code> if the specified permission is implied by this
* object; <code>false</code> otherwise.
*/
-
public boolean implies(Permission p) {
- if (p instanceof PackagePermission) {
- PackagePermission target = (PackagePermission) p;
-
- return (((action_mask & target.action_mask) == target.action_mask) && super
- .implies(p));
+ if (!(p instanceof PackagePermission)) {
+ return false;
}
+ PackagePermission requested = (PackagePermission) p;
+ if (bundle != null) {
+ return false;
+ }
+ // if requested permission has a filter, then it is an invalid argument
+ if (requested.filter != null) {
+ return false;
+ }
+ return implies0(requested, ACTION_NONE);
+ }
- return (false);
+ /**
+ * Internal implies method. Used by the implies and the permission
+ * collection implies methods.
+ *
+ * @param requested The requested PackagePermission which has already be
+ * validated as a proper argument. The requested PackagePermission
+ * must not have a filter expression.
+ * @param effective The effective actions with which to start.
+ * @return <code>true</code> if the specified permission is implied by this
+ * object; <code>false</code> otherwise.
+ */
+ boolean implies0(PackagePermission requested, int effective) {
+ /* check actions first - much faster */
+ effective |= action_mask;
+ final int desired = requested.action_mask;
+ if ((effective & desired) != desired) {
+ return false;
+ }
+ /* Get filter if any */
+ Filter f = filter;
+ if (f == null) {
+ return super.implies(requested);
+ }
+ return f.matchCase(requested.getProperties());
}
/**
@@ -265,32 +435,32 @@
*
* <p>
* Always returns present <code>PackagePermission</code> actions in the
- * following order: <code>EXPORT</code>,<code>IMPORT</code>.
+ * following order: <code>EXPORTONLY</code>,<code>IMPORT</code>.
*
* @return Canonical string representation of the
* <code>PackagePermission</code> actions.
*/
-
public String getActions() {
- if (actions == null) {
+ String result = actions;
+ if (result == null) {
StringBuffer sb = new StringBuffer();
boolean comma = false;
- if ((action_mask & ACTION_EXPORT) == ACTION_EXPORT) {
- sb.append(EXPORT);
+ int mask = action_mask;
+ if ((mask & ACTION_EXPORT) == ACTION_EXPORT) {
+ sb.append(EXPORTONLY);
comma = true;
}
- if ((action_mask & ACTION_IMPORT) == ACTION_IMPORT) {
+ if ((mask & ACTION_IMPORT) == ACTION_IMPORT) {
if (comma)
sb.append(',');
sb.append(IMPORT);
}
- actions = sb.toString();
+ actions = result = sb.toString();
}
-
- return (actions);
+ return result;
}
/**
@@ -300,7 +470,7 @@
* @return A new <code>PermissionCollection</code> object.
*/
public PermissionCollection newPermissionCollection() {
- return (new PackagePermissionCollection());
+ return new PackagePermissionCollection();
}
/**
@@ -313,22 +483,25 @@
* @param obj The object to test for equality with this
* <code>PackagePermission</code> object.
* @return <code>true</code> if <code>obj</code> is a
- * <code>PackagePermission</code>, and has the same package name
- * and actions as this <code>PackagePermission</code> object;
+ * <code>PackagePermission</code>, and has the same package name and
+ * actions as this <code>PackagePermission</code> object;
* <code>false</code> otherwise.
*/
public boolean equals(Object obj) {
if (obj == this) {
- return (true);
+ return true;
}
if (!(obj instanceof PackagePermission)) {
- return (false);
+ return false;
}
- PackagePermission p = (PackagePermission) obj;
+ PackagePermission pp = (PackagePermission) obj;
- return ((action_mask == p.action_mask) && getName().equals(p.getName()));
+ return (action_mask == pp.action_mask)
+ && getName().equals(pp.getName())
+ && ((bundle == pp.bundle) || ((bundle != null) && bundle
+ .equals(pp.bundle)));
}
/**
@@ -336,20 +509,13 @@
*
* @return A hash code value for this object.
*/
-
public int hashCode() {
- return (getName().hashCode() ^ getActions().hashCode());
- }
-
- /**
- * Returns the current action mask.
- * <p>
- * Used by the PackagePermissionCollection class.
- *
- * @return Current action mask.
- */
- int getMask() {
- return (action_mask);
+ int h = 31 * 17 + getName().hashCode();
+ h = 31 * h + getActions().hashCode();
+ if (bundle != null) {
+ h = 31 * h + bundle.hashCode();
+ }
+ return h;
}
/**
@@ -357,9 +523,11 @@
* stream. The actions are serialized, and the superclass takes care of the
* name.
*/
-
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws IOException {
+ if (bundle != null) {
+ throw new NotSerializableException("cannot serialize");
+ }
// Write out the actions. The superclass takes care of the name
// call getActions to make sure actions field is initialized
if (actions == null)
@@ -375,7 +543,41 @@
throws IOException, ClassNotFoundException {
// Read in the action, then initialize the rest
s.defaultReadObject();
- init(getMask(actions));
+ setTransients(getName(), parseActions(actions));
+ }
+
+ /**
+ * Called by <code><@link PackagePermission#implies(Permission)></code>.
+ *
+ * @return a dictionary of properties for this permission.
+ */
+ private Dictionary getProperties() {
+ Dictionary result = properties;
+ if (result != null) {
+ return result;
+ }
+ final Dictionary dict = new Hashtable(5);
+ if (filter == null) {
+ dict.put("package.name", getName());
+ }
+ if (bundle != null) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ dict.put("id", new Long(bundle.getBundleId()));
+ dict.put("location", bundle.getLocation());
+ String name = bundle.getSymbolicName();
+ if (name != null) {
+ dict.put("name", name);
+ }
+ SignerProperty signer = new SignerProperty(bundle);
+ if (signer.isBundleSigned()) {
+ dict.put("signer", signer);
+ }
+ return null;
+ }
+ });
+ }
+ return properties = dict;
}
}
@@ -388,73 +590,100 @@
*/
final class PackagePermissionCollection extends PermissionCollection {
- static final long serialVersionUID = -3350758995234427603L;
+ static final long serialVersionUID = -3350758995234427603L;
/**
- * Table of permissions.
+ * Table of permissions with names.
*
- * @serial
+ * @GuardedBy this
*/
- private Hashtable permissions;
+ private transient Map permissions;
/**
* Boolean saying if "*" is in the collection.
*
* @serial
+ * @GuardedBy this
*/
- private boolean all_allowed;
+ private boolean all_allowed;
+
+ /**
+ * Table of permissions with filter expressions.
+ *
+ * @serial
+ * @GuardedBy this
+ */
+ private Map filterPermissions;
/**
* Create an empty PackagePermissions object.
*/
-
public PackagePermissionCollection() {
- permissions = new Hashtable();
+ permissions = new HashMap();
all_allowed = false;
}
/**
- * Adds a permission to the <code>PackagePermission</code> objects. The
- * key for the hash is the name.
+ * Adds a permission to this permission collection.
*
* @param permission The <code>PackagePermission</code> object to add.
- *
- * @throws IllegalArgumentException If the permission is not a
- * <code>PackagePermission</code> instance.
- *
+ * @throws IllegalArgumentException If the specified permission is not a
+ * <code>PackagePermission</code> instance or was constructed with a
+ * Bundle object.
* @throws SecurityException If this
* <code>PackagePermissionCollection</code> object has been marked
* read-only.
*/
-
- public void add(Permission permission) {
- if (!(permission instanceof PackagePermission))
+ public void add(final Permission permission) {
+ if (!(permission instanceof PackagePermission)) {
throw new IllegalArgumentException("invalid permission: "
+ permission);
- if (isReadOnly())
+ }
+ if (isReadOnly()) {
throw new SecurityException("attempt to add a Permission to a "
+ "readonly PermissionCollection");
+ }
- PackagePermission pp = (PackagePermission) permission;
- String name = pp.getName();
+ final PackagePermission pp = (PackagePermission) permission;
+ if (pp.bundle != null) {
+ throw new IllegalArgumentException("cannot add to collection: "
+ + pp);
+ }
- PackagePermission existing = (PackagePermission) permissions.get(name);
-
- if (existing != null) {
- int oldMask = existing.getMask();
- int newMask = pp.getMask();
- if (oldMask != newMask) {
- permissions.put(name, new PackagePermission(name, oldMask
- | newMask));
-
+ final String name = pp.getName();
+ final Filter f = pp.filter;
+ synchronized (this) {
+ /* select the bucket for the permission */
+ Map pc;
+ if (f != null) {
+ pc = filterPermissions;
+ if (pc == null) {
+ filterPermissions = pc = new HashMap();
+ }
}
- }
- else {
- permissions.put(name, permission);
- }
+ else {
+ pc = permissions;
+ }
+
+ final PackagePermission existing = (PackagePermission) pc.get(name);
+ if (existing != null) {
+ final int oldMask = existing.action_mask;
+ final int newMask = pp.action_mask;
+ if (oldMask != newMask) {
+ pc
+ .put(name, new PackagePermission(name, oldMask
+ | newMask));
- if (!all_allowed) {
- if (name.equals("*"))
- all_allowed = true;
+ }
+ }
+ else {
+ pc.put(name, pp);
+ }
+
+ if (!all_allowed) {
+ if (name.equals("*")) {
+ all_allowed = true;
+ }
+ }
}
}
@@ -464,68 +693,80 @@
*
* @param permission The Permission object to compare with this
* <code>PackagePermission</code> object.
- *
- * @return <code>true</code> if <code>permission</code> is a proper
- * subset of a permission in the set; <code>false</code>
- * otherwise.
+ * @return <code>true</code> if <code>permission</code> is a proper subset
+ * of a permission in the set; <code>false</code> otherwise.
*/
+ public boolean implies(final Permission permission) {
+ if (!(permission instanceof PackagePermission)) {
+ return false;
+ }
+ final PackagePermission requested = (PackagePermission) permission;
+ /* if requested permission has a filter, then it is an invalid argument */
+ if (requested.filter != null) {
+ return false;
+ }
+ String requestedName = requested.getName();
+ final int desired = requested.action_mask;
+ int effective = PackagePermission.ACTION_NONE;
- public boolean implies(Permission permission) {
- if (!(permission instanceof PackagePermission))
- return (false);
-
- PackagePermission pp = (PackagePermission) permission;
- PackagePermission x;
-
- int desired = pp.getMask();
- int effective = 0;
-
- // short circuit if the "*" Permission was added
- if (all_allowed) {
- x = (PackagePermission) permissions.get("*");
- if (x != null) {
- effective |= x.getMask();
- if ((effective & desired) == desired)
- return (true);
+ Collection perms;
+ synchronized (this) {
+ Map pc = permissions;
+ PackagePermission pp;
+ /* short circuit if the "*" Permission was added */
+ if (all_allowed) {
+ pp = (PackagePermission) pc.get("*");
+ if (pp != null) {
+ effective |= pp.action_mask;
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ }
+ /*
+ * strategy: Check for full match first. Then work our way up the
+ * name looking for matches on a.b.*
+ */
+ pp = (PackagePermission) pc.get(requestedName);
+ if (pp != null) {
+ /* we have a direct hit! */
+ effective |= pp.action_mask;
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ /* work our way up the tree... */
+ int last;
+ int offset = requestedName.length() - 1;
+ while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+ requestedName = requestedName.substring(0, last + 1) + "*";
+ pp = (PackagePermission) pc.get(requestedName);
+ if (pp != null) {
+ effective |= pp.action_mask;
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ offset = last - 1;
+ }
+ /*
+ * we don't have to check for "*" as it was already checked before
+ * we were called.
+ */
+ pc = filterPermissions;
+ if (pc == null) {
+ return false;
+ }
+ perms = pc.values();
+ }
+ /* iterate one by one over filteredPermissions */
+ for (Iterator iter = perms.iterator(); iter.hasNext();) {
+ if (((PackagePermission) iter.next())
+ .implies0(requested, effective)) {
+ return true;
}
}
-
- // strategy:
- // Check for full match first. Then work our way up the
- // name looking for matches on a.b.*
-
- String name = pp.getName();
-
- x = (PackagePermission) permissions.get(name);
-
- if (x != null) {
- // we have a direct hit!
- effective |= x.getMask();
- if ((effective & desired) == desired)
- return (true);
- }
-
- // work our way up the tree...
- int last, offset;
-
- offset = name.length() - 1;
-
- while ((last = name.lastIndexOf(".", offset)) != -1) {
-
- name = name.substring(0, last + 1) + "*";
- x = (PackagePermission) permissions.get(name);
-
- if (x != null) {
- effective |= x.getMask();
- if ((effective & desired) == desired)
- return (true);
- }
- offset = last - 1;
- }
-
- // we don't have to check for "*" as it was already checked
- // at the top (all_allowed), so we just return false
- return (false);
+ return false;
}
/**
@@ -534,8 +775,37 @@
*
* @return Enumeration of all <code>PackagePermission</code> objects.
*/
+ public synchronized Enumeration elements() {
+ List all = new ArrayList(permissions.values());
+ Map pc = filterPermissions;
+ if (pc != null) {
+ all.addAll(pc.values());
+ }
+ return Collections.enumeration(all);
+ }
- public Enumeration elements() {
- return (permissions.elements());
+ /* serialization logic */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("permissions", Hashtable.class),
+ new ObjectStreamField("all_allowed", Boolean.TYPE),
+ new ObjectStreamField("filterPermissions", HashMap.class) };
+
+ private synchronized void writeObject(ObjectOutputStream out)
+ throws IOException {
+ Hashtable hashtable = new Hashtable(permissions);
+ ObjectOutputStream.PutField pfields = out.putFields();
+ pfields.put("permissions", hashtable);
+ pfields.put("all_allowed", all_allowed);
+ pfields.put("filterPermissions", filterPermissions);
+ out.writeFields();
+ }
+
+ private synchronized void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ ObjectInputStream.GetField gfields = in.readFields();
+ Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+ permissions = new HashMap(hashtable);
+ all_allowed = gfields.get("all_allowed", false);
+ filterPermissions = (HashMap) gfields.get("filterPermissions", null);
}
}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceEvent.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceEvent.java
index 6f76863..b7c9928 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServiceEvent.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceEvent.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServiceEvent.java,v 1.15 2007/02/20 00:14:12 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,14 +16,15 @@
package org.osgi.framework;
+import java.util.Dictionary;
import java.util.EventObject;
/**
* An event from the Framework describing a service lifecycle change.
* <p>
* <code>ServiceEvent</code> objects are delivered to
- * <code>ServiceListener</code>s and <code>AllServiceListener</code>s when
- * a change occurs in this service's lifecycle. A type code is used to identify
+ * <code>ServiceListener</code>s and <code>AllServiceListener</code>s when a
+ * change occurs in this service's lifecycle. A type code is used to identify
* the event type for future extendability.
*
* <p>
@@ -34,7 +33,7 @@
* @Immutable
* @see ServiceListener
* @see AllServiceListener
- * @version $Revision: 1.15 $
+ * @version $Revision: 6542 $
*/
public class ServiceEvent extends EventObject {
@@ -55,10 +54,7 @@
* This event is synchronously delivered <strong>after</strong> the service
* has been registered with the Framework.
*
- * <p>
- * The value of <code>REGISTERED</code> is 0x00000001.
- *
- * @see BundleContext#registerService(String[],Object,java.util.Dictionary)
+ * @see BundleContext#registerService(String[],Object,Dictionary)
*/
public final static int REGISTERED = 0x00000001;
@@ -68,9 +64,6 @@
* This event is synchronously delivered <strong>after</strong> the service
* properties have been modified.
*
- * <p>
- * The value of <code>MODIFIED</code> is 0x00000002.
- *
* @see ServiceRegistration#setProperties
*/
public final static int MODIFIED = 0x00000002;
@@ -78,8 +71,8 @@
/**
* This service is in the process of being unregistered.
* <p>
- * This event is synchronously delivered <strong>before</strong> the
- * service has completed unregistering.
+ * This event is synchronously delivered <strong>before</strong> the service
+ * has completed unregistering.
*
* <p>
* If a bundle is using a service that is <code>UNREGISTERING</code>, the
@@ -88,20 +81,32 @@
* this event, the Framework will automatically release the bundle's use of
* the service while completing the service unregistration operation.
*
- * <p>
- * The value of UNREGISTERING is 0x00000004.
- *
* @see ServiceRegistration#unregister
* @see BundleContext#ungetService
*/
public final static int UNREGISTERING = 0x00000004;
/**
+ * The properties of a registered service have been modified and the new
+ * properties no longer match the listener's filter.
+ * <p>
+ * This event is synchronously delivered <strong>after</strong> the service
+ * properties have been modified. This event is only delivered to listeners
+ * which were added with a non-<code>null</code> filter where the filter
+ * matched the service properties prior to the modification but the filter
+ * does not match the modified service properties.
+ *
+ * @see ServiceRegistration#setProperties
+ * @since 1.5
+ */
+ public final static int MODIFIED_ENDMATCH = 0x00000008;
+
+ /**
* Creates a new service event object.
*
* @param type The event type.
* @param reference A <code>ServiceReference</code> object to the service
- * that had a lifecycle change.
+ * that had a lifecycle change.
*/
public ServiceEvent(int type, ServiceReference reference) {
super(reference);
@@ -124,9 +129,10 @@
/**
* Returns the type of event. The event type values are:
* <ul>
- * <li>{@link #REGISTERED}
- * <li>{@link #MODIFIED}
- * <li>{@link #UNREGISTERING}
+ * <li>{@link #REGISTERED} </li>
+ * <li>{@link #MODIFIED} </li>
+ * <li>{@link #MODIFIED_ENDMATCH} </li>
+ * <li>{@link #UNREGISTERING} </li>
* </ul>
*
* @return Type of service lifecycle change.
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceException.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceException.java
new file mode 100644
index 0000000..4cf04a0
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceException.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) OSGi Alliance (2007, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+/**
+ * A service exception used to indicate that a service problem occurred.
+ *
+ * <p>
+ * A <code>ServiceException</code> object is created by the Framework or
+ * service implementation to denote an exception condition in the service. A
+ * type code is used to identify the exception type for future extendability.
+ * Service implementations may also create subclasses of
+ * <code>ServiceException</code>. When subclassing, the subclass should set
+ * the type to {@link #SUBCLASSED} to indicate that
+ * <code>ServiceException</code> has been subclassed.
+ *
+ * <p>
+ * This exception conforms to the general purpose exception chaining mechanism.
+ *
+ * @version $Revision: 6518 $
+ * @since 1.5
+ */
+
+public class ServiceException extends RuntimeException {
+ static final long serialVersionUID = 3038963223712959631L;
+
+ /**
+ * Type of service exception.
+ */
+ private final int type;
+
+ /**
+ * No exception type is unspecified.
+ */
+ public static final int UNSPECIFIED = 0;
+ /**
+ * The service has been unregistered.
+ */
+ public static final int UNREGISTERED = 1;
+ /**
+ * The service factory produced an invalid service object.
+ */
+ public static final int FACTORY_ERROR = 2;
+ /**
+ * The service factory threw an exception.
+ */
+ public static final int FACTORY_EXCEPTION = 3;
+ /**
+ * The exception is a subclass of ServiceException. The subclass should be
+ * examined for the type of the exception.
+ */
+ public static final int SUBCLASSED = 4;
+ /**
+ * An error occurred invoking a remote service.
+ */
+ public static final int REMOTE = 5;
+
+ /**
+ * Creates a <code>ServiceException</code> with the specified message and
+ * exception cause.
+ *
+ * @param msg The associated message.
+ * @param cause The cause of this exception.
+ */
+ public ServiceException(String msg, Throwable cause) {
+ this(msg, UNSPECIFIED, cause);
+ }
+
+ /**
+ * Creates a <code>ServiceException</code> with the specified message.
+ *
+ * @param msg The message.
+ */
+ public ServiceException(String msg) {
+ this(msg, UNSPECIFIED);
+ }
+
+ /**
+ * Creates a <code>ServiceException</code> with the specified message,
+ * type and exception cause.
+ *
+ * @param msg The associated message.
+ * @param type The type for this exception.
+ * @param cause The cause of this exception.
+ */
+ public ServiceException(String msg, int type, Throwable cause) {
+ super(msg, cause);
+ this.type = type;
+ }
+
+ /**
+ * Creates a <code>ServiceException</code> with the specified message and
+ * type.
+ *
+ * @param msg The message.
+ * @param type The type for this exception.
+ */
+ public ServiceException(String msg, int type) {
+ super(msg);
+ this.type = type;
+ }
+
+ /**
+ * Returns the type for this exception or <code>UNSPECIFIED</code> if the
+ * type was unspecified or unknown.
+ *
+ * @return The type of this exception.
+ */
+ public int getType() {
+ return type;
+ }
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceFactory.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceFactory.java
index 1a3b3d2..c8f6bf3 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServiceFactory.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceFactory.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServiceFactory.java,v 1.10 2007/02/20 00:16:30 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,7 +46,7 @@
*
* @see BundleContext#getService
* @ThreadSafe
- * @version $Revision: 1.10 $
+ * @version $Revision: 5967 $
*/
public interface ServiceFactory {
@@ -65,7 +63,9 @@
* <p>
* The Framework caches the value returned (unless it is <code>null</code>),
* and will return the same service object on any future call to
- * <code>BundleContext.getService</code> from the same bundle.
+ * <code>BundleContext.getService</code> for the same bundle. This means the
+ * Framework must not allow this method to be concurrently called for the
+ * same bundle.
*
* <p>
* The Framework will check if the returned service object is an instance of
@@ -75,8 +75,8 @@
* @param bundle The bundle using the service.
* @param registration The <code>ServiceRegistration</code> object for the
* service.
- * @return A service object that <strong>must </strong> be an instance of
- * all the classes named when the service was registered.
+ * @return A service object that <strong>must</strong> be an instance of all
+ * the classes named when the service was registered.
* @see BundleContext#getService
*/
public Object getService(Bundle bundle, ServiceRegistration registration);
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceListener.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceListener.java
index 8d9464e..ec08560 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServiceListener.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceListener.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServiceListener.java,v 1.15 2007/02/20 00:16:30 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -53,7 +51,7 @@
* @see ServiceEvent
* @see ServicePermission
* @ThreadSafe
- * @version $Revision: 1.15 $
+ * @version $Revision: 5673 $
*/
public interface ServiceListener extends EventListener {
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServicePermission.java b/org.osgi.core/src/main/java/org/osgi/framework/ServicePermission.java
index 4f10f09..d1fb70f 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServicePermission.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServicePermission.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServicePermission.java,v 1.15 2007/02/20 00:06:02 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,34 +17,51 @@
package org.osgi.framework;
import java.io.IOException;
-import java.security.*;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.security.AccessController;
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
/**
* A bundle's authority to register or get a service.
* <ul>
- * <li>The <code>ServicePermission.REGISTER</code> action allows a bundle to
- * register a service on the specified names.
- * <li>The <code>ServicePermission.GET</code> action allows a bundle to
- * detect a service and get it.
+ * <li>The <code>register</code> action allows a bundle to register a service on
+ * the specified names.
+ * <li>The <code>get</code> action allows a bundle to detect a service and get
+ * it.
* </ul>
* Permission to get a service is required in order to detect events regarding
* the service. Untrusted bundles should not be able to detect the presence of
* certain services unless they have the appropriate
* <code>ServicePermission</code> to get the specific service.
*
- * @version $Revision: 1.15 $
+ * @ThreadSafe
+ * @version $Revision: 6530 $
*/
-final public class ServicePermission extends BasicPermission {
+public final class ServicePermission extends BasicPermission {
static final long serialVersionUID = -7662148639076511574L;
/**
- * The action string <code>get</code> (Value is "get").
+ * The action string <code>get</code>.
*/
public final static String GET = "get";
/**
- * The action string <code>register</code> (Value is "register").
+ * The action string <code>register</code>.
*/
public final static String REGISTER = "register";
@@ -54,27 +69,65 @@
private final static int ACTION_REGISTER = 0x00000002;
private final static int ACTION_ALL = ACTION_GET
| ACTION_REGISTER;
- private final static int ACTION_NONE = 0;
+ final static int ACTION_NONE = 0;
+
/**
* The actions mask.
*/
- private transient int action_mask = ACTION_NONE;
+ transient int action_mask;
/**
* The actions in canonical form.
*
* @serial
*/
- private String actions = null;
+ private volatile String actions = null;
+
+ /**
+ * The service used by this ServicePermission. Must be null if not
+ * constructed with a service.
+ */
+ transient final ServiceReference service;
+
+ /**
+ * The object classes for this ServicePermission. Must be null if not
+ * constructed with a service.
+ */
+ transient final String[] objectClass;
+
+ /**
+ * If this ServicePermission was constructed with a filter, this holds a
+ * Filter matching object used to evaluate the filter in implies.
+ */
+ transient Filter filter;
+
+ /**
+ * This dictionary holds the properties of the permission, used to match a
+ * filter in implies. This is not initialized until necessary, and then
+ * cached in this object.
+ */
+ private transient volatile Dictionary properties;
+
+ /**
+ * True if constructed with a name and the name is "*" or ends with ".*".
+ */
+ private transient boolean wildcard;
+
+ /**
+ * If constructed with a name and the name ends with ".*", this contains the
+ * name without the final "*".
+ */
+ private transient String prefix;
/**
* Create a new ServicePermission.
*
* <p>
* The name of the service is specified as a fully qualified class name.
+ * Wildcards may be used.
*
* <pre>
- * ClassName ::= <class name> | <class name ending in ".*">
+ * name ::= <class name> | <class name ending in ".*"> | *
* </pre>
*
* Examples:
@@ -82,23 +135,88 @@
* <pre>
* org.osgi.service.http.HttpService
* org.osgi.service.http.*
- * org.osgi.service.snmp.*
+ * *
* </pre>
*
+ * For the <code>get</code> action, the name can also be a filter
+ * expression. The filter gives access to the service properties as well as
+ * the following attributes:
+ * <ul>
+ * <li>signer - A Distinguished Name chain used to sign the bundle
+ * publishing the service. Wildcards in a DN are not matched according to
+ * the filter string rules, but according to the rules defined for a DN
+ * chain.</li>
+ * <li>location - The location of the bundle publishing the service.</li>
+ * <li>id - The bundle ID of the bundle publishing the service.</li>
+ * <li>name - The symbolic name of the bundle publishing the service.</li>
+ * </ul>
+ * Since the above attribute names may conflict with service property names
+ * used by a service, you can prefix an attribute name with '@' in the
+ * filter expression to match against the service property and not one of
+ * the above attributes. Filter attribute names are processed in a case
+ * sensitive manner unless the attribute references a service property.
+ * Service properties names are case insensitive.
+ *
* <p>
* There are two possible actions: <code>get</code> and
- * <code>register</code>. The <code>get</code> permission allows the
- * owner of this permission to obtain a service with this name. The
- * <code>register</code> permission allows the bundle to register a
- * service under that name.
+ * <code>register</code>. The <code>get</code> permission allows the owner
+ * of this permission to obtain a service with this name. The
+ * <code>register</code> permission allows the bundle to register a service
+ * under that name.
*
- * @param name class name
- * @param actions <code>get</code>,<code>register</code> (canonical
- * order)
+ * @param name The service class name
+ * @param actions <code>get</code>,<code>register</code> (canonical order)
+ * @throw IllegalArgumentException If the specified name is a filter
+ * expression and either the specified action is not <code>get</code>
+ * or the filter has an invalid syntax.
*/
-
public ServicePermission(String name, String actions) {
- this(name, getMask(actions));
+ this(name, parseActions(actions));
+ if ((filter != null)
+ && ((action_mask & ACTION_ALL) != ACTION_GET)) {
+ throw new IllegalArgumentException(
+ "invalid action string for filter expression");
+ }
+ }
+
+ /**
+ * Creates a new requested <code>ServicePermission</code> object to be used
+ * by code that must perform <code>checkPermission</code> for the
+ * <code>get</code> action. <code>ServicePermission</code> objects created
+ * with this constructor cannot be added to a <code>ServicePermission</code>
+ * permission collection.
+ *
+ * @param reference The requested service.
+ * @param actions The action <code>get</code>.
+ * @throw IllegalArgumentException If the specified action is not
+ * <code>get</code> or reference is <code>null</code>.
+ * @since 1.5
+ */
+ public ServicePermission(ServiceReference reference, String actions) {
+ super(createName(reference));
+ setTransients(null, parseActions(actions));
+ this.service = reference;
+ this.objectClass = (String[]) reference
+ .getProperty(Constants.OBJECTCLASS);
+ if ((action_mask & ACTION_ALL) != ACTION_GET) {
+ throw new IllegalArgumentException("invalid action string");
+ }
+ }
+
+ /**
+ * Create a permission name from a ServiceReference
+ *
+ * @param reference ServiceReference to use to create permission name.
+ * @return permission name.
+ */
+ private static String createName(ServiceReference reference) {
+ if (reference == null) {
+ throw new IllegalArgumentException("reference must not be null");
+ }
+ StringBuffer sb = new StringBuffer("(service.id=");
+ sb.append(reference.getProperty(Constants.SERVICE_ID));
+ sb.append(")");
+ return sb.toString();
}
/**
@@ -109,8 +227,9 @@
*/
ServicePermission(String name, int mask) {
super(name);
-
- init(mask);
+ setTransients(parseFilter(name), mask);
+ this.service = null;
+ this.objectClass = null;
}
/**
@@ -118,12 +237,22 @@
*
* @param mask action mask
*/
- private void init(int mask) {
+ private void setTransients(Filter f, int mask) {
if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
throw new IllegalArgumentException("invalid action string");
}
-
action_mask = mask;
+ filter = f;
+ if (f == null) {
+ String name = getName();
+ int l = name.length();
+ /* if "*" or endsWith ".*" */
+ wildcard = ((name.charAt(l - 1) == '*') && ((l == 1) || (name
+ .charAt(l - 2) == '.')));
+ if (wildcard && (l > 1)) {
+ prefix = name.substring(0, l - 1);
+ }
+ }
}
/**
@@ -132,7 +261,7 @@
* @param actions Action string.
* @return action mask.
*/
- private static int getMask(String actions) {
+ private static int parseActions(String actions) {
boolean seencomma = false;
int mask = ACTION_NONE;
@@ -218,23 +347,105 @@
}
/**
+ * Parse filter string into a Filter object.
+ *
+ * @param filterString The filter string to parse.
+ * @return a Filter for this bundle. If the specified filterString is not a
+ * filter expression, then <code>null</code> is returned.
+ * @throws IllegalArgumentException If the filter syntax is invalid.
+ */
+ private static Filter parseFilter(String filterString) {
+ filterString = filterString.trim();
+ if (filterString.charAt(0) != '(') {
+ return null;
+ }
+
+ try {
+ return FrameworkUtil.createFilter(filterString);
+ }
+ catch (InvalidSyntaxException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "invalid filter");
+ iae.initCause(e);
+ throw iae;
+ }
+ }
+
+ /**
* Determines if a <code>ServicePermission</code> object "implies" the
* specified permission.
*
* @param p The target permission to check.
- * @return <code>true</code> if the specified permission is implied by
- * this object; <code>false</code> otherwise.
+ * @return <code>true</code> if the specified permission is implied by this
+ * object; <code>false</code> otherwise.
*/
-
public boolean implies(Permission p) {
- if (p instanceof ServicePermission) {
- ServicePermission target = (ServicePermission) p;
-
- return (((action_mask & target.action_mask) == target.action_mask) && super
- .implies(p));
+ if (!(p instanceof ServicePermission)) {
+ return false;
}
+ ServicePermission requested = (ServicePermission) p;
+ if (service != null) {
+ return false;
+ }
+ // if requested permission has a filter, then it is an invalid argument
+ if (requested.filter != null) {
+ return false;
+ }
+ return implies0(requested, ACTION_NONE);
+ }
- return (false);
+ /**
+ * Internal implies method. Used by the implies and the permission
+ * collection implies methods.
+ *
+ * @param requested The requested ServicePermission which has already be
+ * validated as a proper argument. The requested ServicePermission
+ * must not have a filter expression.
+ * @param effective The effective actions with which to start.
+ * @return <code>true</code> if the specified permission is implied by this
+ * object; <code>false</code> otherwise.
+ */
+ boolean implies0(ServicePermission requested, int effective) {
+ /* check actions first - much faster */
+ effective |= action_mask;
+ final int desired = requested.action_mask;
+ if ((effective & desired) != desired) {
+ return false;
+ }
+ /* we have name of "*" */
+ if (wildcard && (prefix == null)) {
+ return true;
+ }
+ /* if we have a filter */
+ Filter f = filter;
+ if (f != null) {
+ return f.matchCase(requested.getProperties());
+ }
+ /* if requested permission not created with ServiceReference */
+ String[] requestedNames = requested.objectClass;
+ if (requestedNames == null) {
+ return super.implies(requested);
+ }
+ /* requested permission created with ServiceReference */
+ if (wildcard) {
+ int pl = prefix.length();
+ for (int i = 0, l = requestedNames.length; i < l; i++) {
+ String requestedName = requestedNames[i];
+ if ((requestedName.length() > pl)
+ && requestedName.startsWith(prefix)) {
+ return true;
+ }
+ }
+ }
+ else {
+ String name = getName();
+ for (int i = 0, l = requestedNames.length; i < l; i++) {
+ if (requestedNames[i].equals(name)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
/**
@@ -245,25 +456,27 @@
* @return The canonical string representation of the actions.
*/
public String getActions() {
- if (actions == null) {
+ String result = actions;
+ if (result == null) {
StringBuffer sb = new StringBuffer();
boolean comma = false;
- if ((action_mask & ACTION_GET) == ACTION_GET) {
+ int mask = action_mask;
+ if ((mask & ACTION_GET) == ACTION_GET) {
sb.append(GET);
comma = true;
}
- if ((action_mask & ACTION_REGISTER) == ACTION_REGISTER) {
+ if ((mask & ACTION_REGISTER) == ACTION_REGISTER) {
if (comma)
sb.append(',');
sb.append(REGISTER);
}
- actions = sb.toString();
+ actions = result = sb.toString();
}
- return (actions);
+ return result;
}
/**
@@ -274,33 +487,35 @@
* <code>ServicePermission</code> objects.
*/
public PermissionCollection newPermissionCollection() {
- return (new ServicePermissionCollection());
+ return new ServicePermissionCollection();
}
/**
- * Determines the equalty of two ServicePermission objects.
+ * Determines the equality of two ServicePermission objects.
*
* Checks that specified object has the same class name and action as this
* <code>ServicePermission</code>.
*
* @param obj The object to test for equality.
- * @return true if obj is a <code>ServicePermission</code>, and has the
- * same class name and actions as this
- * <code>ServicePermission</code> object; <code>false</code>
- * otherwise.
+ * @return true if obj is a <code>ServicePermission</code>, and has the same
+ * class name and actions as this <code>ServicePermission</code>
+ * object; <code>false</code> otherwise.
*/
public boolean equals(Object obj) {
if (obj == this) {
- return (true);
+ return true;
}
if (!(obj instanceof ServicePermission)) {
- return (false);
+ return false;
}
- ServicePermission p = (ServicePermission) obj;
+ ServicePermission sp = (ServicePermission) obj;
- return ((action_mask == p.action_mask) && getName().equals(p.getName()));
+ return (action_mask == sp.action_mask)
+ && getName().equals(sp.getName())
+ && ((service == sp.service) || ((service != null) && (service
+ .compareTo(sp.service) == 0)));
}
/**
@@ -308,28 +523,24 @@
*
* @return Hash code value for this object.
*/
-
public int hashCode() {
- return (getName().hashCode() ^ getActions().hashCode());
- }
-
- /**
- * Returns the current action mask. Used by the ServicePermissionCollection
- * object.
- *
- * @return The actions mask.
- */
- int getMask() {
- return (action_mask);
+ int h = 31 * 17 + getName().hashCode();
+ h = 31 * h + getActions().hashCode();
+ if (service != null) {
+ h = 31 * h + service.hashCode();
+ }
+ return h;
}
/**
* WriteObject is called to save the state of this permission to a stream.
* The actions are serialized, and the superclass takes care of the name.
*/
-
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws IOException {
+ if (service != null) {
+ throw new NotSerializableException("cannot serialize");
+ }
// Write out the actions. The superclass takes care of the name
// call getActions to make sure actions field is initialized
if (actions == null)
@@ -345,7 +556,123 @@
throws IOException, ClassNotFoundException {
// Read in the action, then initialize the rest
s.defaultReadObject();
- init(getMask(actions));
+ setTransients(parseFilter(getName()), parseActions(actions));
+ }
+ /**
+ * Called by <code><@link ServicePermission#implies(Permission)></code>.
+ *
+ * @return a dictionary of properties for this permission.
+ */
+ private Dictionary getProperties() {
+ Dictionary result = properties;
+ if (result != null) {
+ return result;
+ }
+ if (service == null) {
+ result = new Hashtable(1);
+ if (filter == null) {
+ result.put(Constants.OBJECTCLASS, new String[] {getName()});
+ }
+ return properties = result;
+ }
+ final Map props = new HashMap(4);
+ final Bundle bundle = service.getBundle();
+ if (bundle != null) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ props.put("id", new Long(bundle.getBundleId()));
+ props.put("location", bundle.getLocation());
+ String name = bundle.getSymbolicName();
+ if (name != null) {
+ props.put("name", name);
+ }
+ SignerProperty signer = new SignerProperty(bundle);
+ if (signer.isBundleSigned()) {
+ props.put("signer", signer);
+ }
+ return null;
+ }
+ });
+ }
+ return properties = new Properties(props, service);
+ }
+
+ private static class Properties extends Dictionary {
+ private final Map properties;
+ private final ServiceReference service;
+
+ Properties(Map properties, ServiceReference service) {
+ this.properties = properties;
+ this.service = service;
+ }
+
+ public Object get(Object k) {
+ if (!(k instanceof String)) {
+ return null;
+ }
+ String key = (String) k;
+ if (key.charAt(0) == '@') {
+ return service.getProperty(key.substring(1));
+ }
+ Object value = properties.get(key);
+ if (value != null) { // fall back to service properties
+ return value;
+ }
+ return service.getProperty(key);
+ }
+
+ public int size() {
+ return properties.size() + service.getPropertyKeys().length;
+ }
+
+ public boolean isEmpty() {
+ // we can return false because this must never be empty
+ return false;
+ }
+
+ public Enumeration keys() {
+ Collection pk = properties.keySet();
+ String spk[] = service.getPropertyKeys();
+ List all = new ArrayList(pk.size() + spk.length);
+ all.addAll(pk);
+ add:
+ for (int i = 0, length = spk.length; i < length; i++) {
+ String key = spk[i];
+ for (Iterator iter = pk.iterator(); iter.hasNext();) {
+ if (key.equalsIgnoreCase((String) iter.next())) {
+ continue add;
+ }
+ }
+ all.add(key);
+ }
+ return Collections.enumeration(all);
+ }
+
+ public Enumeration elements() {
+ Collection pk = properties.keySet();
+ String spk[] = service.getPropertyKeys();
+ List all = new ArrayList(pk.size() + spk.length);
+ all.addAll(properties.values());
+ add:
+ for (int i = 0, length = spk.length; i < length; i++) {
+ String key = spk[i];
+ for (Iterator iter = pk.iterator(); iter.hasNext();) {
+ if (key.equalsIgnoreCase((String) iter.next())) {
+ continue add;
+ }
+ }
+ all.add(service.getProperty(key));
+ }
+ return Collections.enumeration(all);
+ }
+
+ public Object put(Object key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
}
}
@@ -356,73 +683,99 @@
* @see java.security.Permissions
* @see java.security.PermissionCollection
*/
-
final class ServicePermissionCollection extends PermissionCollection {
static final long serialVersionUID = 662615640374640621L;
/**
* Table of permissions.
*
- * @serial
+ * @GuardedBy this
*/
- private Hashtable permissions;
+ private transient Map permissions;
/**
* Boolean saying if "*" is in the collection.
*
* @serial
+ * @GuardedBy this
*/
private boolean all_allowed;
/**
+ * Table of permissions with filter expressions.
+ *
+ * @serial
+ * @GuardedBy this
+ */
+ private Map filterPermissions;
+
+ /**
* Creates an empty ServicePermissions object.
*/
-
public ServicePermissionCollection() {
- permissions = new Hashtable();
+ permissions = new HashMap();
all_allowed = false;
}
/**
- * Adds a permission to the <code>ServicePermission</code> objects using
- * the key for the hash as the name.
+ * Adds a permission to this permission collection.
*
* @param permission The Permission object to add.
- *
- * @throws IllegalArgumentException If the permission is not a
+ * @throws IllegalArgumentException If the specified permission is not a
* ServicePermission object.
* @throws SecurityException If this
* <code>ServicePermissionCollection</code> object has been marked
* read-only.
*/
-
- public void add(Permission permission) {
- if (!(permission instanceof ServicePermission))
+ public void add(final Permission permission) {
+ if (!(permission instanceof ServicePermission)) {
throw new IllegalArgumentException("invalid permission: "
+ permission);
- if (isReadOnly())
+ }
+ if (isReadOnly()) {
throw new SecurityException("attempt to add a Permission to a "
+ "readonly PermissionCollection");
+ }
- ServicePermission sp = (ServicePermission) permission;
- String name = sp.getName();
-
- ServicePermission existing = (ServicePermission) permissions.get(name);
-
- if (existing != null) {
- int oldMask = existing.getMask();
- int newMask = sp.getMask();
- if (oldMask != newMask) {
- permissions.put(name, new ServicePermission(name, oldMask
- | newMask));
+ final ServicePermission sp = (ServicePermission) permission;
+ if (sp.service != null) {
+ throw new IllegalArgumentException("cannot add to collection: "
+ + sp);
+ }
+
+ final String name = sp.getName();
+ final Filter f = sp.filter;
+ synchronized (this) {
+ /* select the bucket for the permission */
+ Map pc;
+ if (f != null) {
+ pc = filterPermissions;
+ if (pc == null) {
+ filterPermissions = pc = new HashMap();
+ }
}
- }
- else {
- permissions.put(name, permission);
- }
-
- if (!all_allowed) {
- if (name.equals("*"))
- all_allowed = true;
+ else {
+ pc = permissions;
+ }
+ final ServicePermission existing = (ServicePermission) pc.get(name);
+
+ if (existing != null) {
+ final int oldMask = existing.action_mask;
+ final int newMask = sp.action_mask;
+ if (oldMask != newMask) {
+ pc
+ .put(name, new ServicePermission(name, oldMask
+ | newMask));
+ }
+ }
+ else {
+ pc.put(name, sp);
+ }
+
+ if (!all_allowed) {
+ if (name.equals("*")) {
+ all_allowed = true;
+ }
+ }
}
}
@@ -431,78 +784,149 @@
* <code>permission</code>.
*
* @param permission The Permission object to compare.
- *
* @return <code>true</code> if <code>permission</code> is a proper
* subset of a permission in the set; <code>false</code>
* otherwise.
*/
-
- public boolean implies(Permission permission) {
- if (!(permission instanceof ServicePermission))
- return (false);
-
- ServicePermission sp = (ServicePermission) permission;
- ServicePermission x;
-
- int desired = sp.getMask();
- int effective = 0;
-
- // short circuit if the "*" Permission was added
- if (all_allowed) {
- x = (ServicePermission) permissions.get("*");
- if (x != null) {
- effective |= x.getMask();
- if ((effective & desired) == desired)
- return (true);
- }
+ public boolean implies(final Permission permission) {
+ if (!(permission instanceof ServicePermission)) {
+ return false;
+ }
+ final ServicePermission requested = (ServicePermission) permission;
+ /* if requested permission has a filter, then it is an invalid argument */
+ if (requested.filter != null) {
+ return false;
}
+ int effective = ServicePermission.ACTION_NONE;
+ Collection perms;
+ synchronized (this) {
+ final int desired = requested.action_mask;
+ /* short circuit if the "*" Permission was added */
+ if (all_allowed) {
+ ServicePermission sp = (ServicePermission) permissions.get("*");
+ if (sp != null) {
+ effective |= sp.action_mask;
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ }
+
+ String[] requestedNames = requested.objectClass;
+ /* if requested permission not created with ServiceReference */
+ if (requestedNames == null) {
+ effective |= effective(requested.getName(), desired, effective);
+ if ((effective & desired) == desired) {
+ return true;
+ }
+ }
+ /* requested permission created with ServiceReference */
+ else {
+ for (int i = 0, l = requestedNames.length; i < l; i++) {
+ if ((effective(requestedNames[i], desired, effective) & desired) == desired) {
+ return true;
+ }
+ }
+ }
+ Map pc = filterPermissions;
+ if (pc == null) {
+ return false;
+ }
+ perms = pc.values();
+ }
+
+ /* iterate one by one over filteredPermissions */
+ for (Iterator iter = perms.iterator(); iter.hasNext();) {
+ if (((ServicePermission) iter.next())
+ .implies0(requested, effective)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Consult permissions map to compute the effective permission for the
+ * requested permission name.
+ *
+ * @param requestedName The requested service name.
+ * @param desired The desired actions.
+ * @param effective The effective actions.
+ * @return The new effective actions.
+ */
+ private int effective(String requestedName, final int desired,
+ int effective) {
+ final Map pc = permissions;
+ ServicePermission sp = (ServicePermission) pc.get(requestedName);
// strategy:
// Check for full match first. Then work our way up the
// name looking for matches on a.b.*
-
- String name = sp.getName();
-
- x = (ServicePermission) permissions.get(name);
-
- if (x != null) {
+ if (sp != null) {
// we have a direct hit!
- effective |= x.getMask();
- if ((effective & desired) == desired)
- return (true);
+ effective |= sp.action_mask;
+ if ((effective & desired) == desired) {
+ return effective;
+ }
}
-
// work our way up the tree...
- int last, offset;
-
- offset = name.length() - 1;
-
- while ((last = name.lastIndexOf(".", offset)) != -1) {
-
- name = name.substring(0, last + 1) + "*";
- x = (ServicePermission) permissions.get(name);
-
- if (x != null) {
- effective |= x.getMask();
- if ((effective & desired) == desired)
- return (true);
+ int last;
+ int offset = requestedName.length() - 1;
+ while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+ requestedName = requestedName.substring(0, last + 1) + "*";
+ sp = (ServicePermission) pc.get(requestedName);
+ if (sp != null) {
+ effective |= sp.action_mask;
+ if ((effective & desired) == desired) {
+ return effective;
+ }
}
offset = last - 1;
}
-
- // we don't have to check for "*" as it was already checked
- // at the top (all_allowed), so we just return false
- return (false);
+ /*
+ * we don't have to check for "*" as it was already checked before we
+ * were called.
+ */
+ return effective;
}
-
+
/**
* Returns an enumeration of all the <code>ServicePermission</code>
* objects in the container.
*
* @return Enumeration of all the ServicePermission objects.
*/
+ public synchronized Enumeration elements() {
+ List all = new ArrayList(permissions.values());
+ Map pc = filterPermissions;
+ if (pc != null) {
+ all.addAll(pc.values());
+ }
+ return Collections.enumeration(all);
+ }
+
+ /* serialization logic */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("permissions", Hashtable.class),
+ new ObjectStreamField("all_allowed", Boolean.TYPE),
+ new ObjectStreamField("filterPermissions", HashMap.class) };
- public Enumeration elements() {
- return (permissions.elements());
+ private synchronized void writeObject(ObjectOutputStream out)
+ throws IOException {
+ Hashtable hashtable = new Hashtable(permissions);
+ ObjectOutputStream.PutField pfields = out.putFields();
+ pfields.put("permissions", hashtable);
+ pfields.put("all_allowed", all_allowed);
+ pfields.put("filterPermissions", filterPermissions);
+ out.writeFields();
+ }
+
+ private synchronized void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ ObjectInputStream.GetField gfields = in.readFields();
+ Hashtable hashtable = (Hashtable) gfields.get("permissions", null);
+ permissions = new HashMap(hashtable);
+ all_allowed = gfields.get("all_allowed", false);
+ filterPermissions = (HashMap) gfields.get("filterPermissions", null);
}
}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceReference.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceReference.java
index a24461c..a6dd9bd 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServiceReference.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceReference.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServiceReference.java,v 1.20 2007/02/21 16:49:05 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +16,8 @@
package org.osgi.framework;
+import java.util.Dictionary;
+
/**
* A reference to a service.
*
@@ -46,7 +46,7 @@
* @see BundleContext#getServiceReferences
* @see BundleContext#getService
* @ThreadSafe
- * @version $Revision: 1.20 $
+ * @version $Revision: 6374 $
*/
public interface ServiceReference extends Comparable {
@@ -85,8 +85,8 @@
* This method is <i>case-preserving </i>; this means that every key in the
* returned array must have the same case as the corresponding key in the
* properties <code>Dictionary</code> that was passed to the
- * {@link BundleContext#registerService(String[],Object,java.util.Dictionary)}
- * or {@link ServiceRegistration#setProperties} methods.
+ * {@link BundleContext#registerService(String[],Object,Dictionary)} or
+ * {@link ServiceRegistration#setProperties} methods.
*
* @return An array of property keys.
*/
@@ -102,9 +102,9 @@
* unregistered.
*
* @return The bundle that registered the service referenced by this
- * <code>ServiceReference</code> object; <code>null</code> if
- * that service has already been unregistered.
- * @see BundleContext#registerService(String[],Object,java.util.Dictionary)
+ * <code>ServiceReference</code> object; <code>null</code> if that
+ * service has already been unregistered.
+ * @see BundleContext#registerService(String[],Object,Dictionary)
*/
public Bundle getBundle();
@@ -146,7 +146,9 @@
* referenced by this <code>ServiceReference</code> and the
* specified bundle use the same source for the package of the
* specified class name. Otherwise <code>false</code> is returned.
- *
+ * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+ * not created by the same framework instance as this
+ * <code>ServiceReference</code>.
* @since 1.3
*/
public boolean isAssignableTo(Bundle bundle, String className);
@@ -157,10 +159,9 @@
*
* <p>
* If this <code>ServiceReference</code> and the specified
- * <code>ServiceReference</code> have the same
- * {@link Constants#SERVICE_ID service id} they are equal. This
- * <code>ServiceReference</code> is less than the specified
- * <code>ServiceReference</code> if it has a lower
+ * <code>ServiceReference</code> have the same {@link Constants#SERVICE_ID
+ * service id} they are equal. This <code>ServiceReference</code> is less
+ * than the specified <code>ServiceReference</code> if it has a lower
* {@link Constants#SERVICE_RANKING service ranking} and greater if it has a
* higher service ranking. Otherwise, if this <code>ServiceReference</code>
* and the specified <code>ServiceReference</code> have the same
@@ -172,8 +173,11 @@
*
* @param reference The <code>ServiceReference</code> to be compared.
* @return Returns a negative integer, zero, or a positive integer if this
- * <code>ServiceReference</code> is less than, equal to, or
- * greater than the specified <code>ServiceReference</code>.
+ * <code>ServiceReference</code> is less than, equal to, or greater
+ * than the specified <code>ServiceReference</code>.
+ * @throws IllegalArgumentException If the specified
+ * <code>ServiceReference</code> was not created by the same
+ * framework instance as this <code>ServiceReference</code>.
* @since 1.4
*/
public int compareTo(Object reference);
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/ServiceRegistration.java b/org.osgi.core/src/main/java/org/osgi/framework/ServiceRegistration.java
index 3239364..9186cf7 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/ServiceRegistration.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/ServiceRegistration.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/ServiceRegistration.java,v 1.14 2007/02/21 16:49:05 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +32,7 @@
*
* @see BundleContext#registerService(String[],Object,Dictionary)
* @ThreadSafe
- * @version $Revision: 1.14 $
+ * @version $Revision: 6361 $
*/
public interface ServiceRegistration {
@@ -45,7 +43,7 @@
* The <code>ServiceReference</code> object may be shared with other
* bundles.
*
- * @throws java.lang.IllegalStateException If this
+ * @throws IllegalStateException If this
* <code>ServiceRegistration</code> object has already been
* unregistered.
* @return <code>ServiceReference</code> object.
@@ -64,8 +62,7 @@
* The following steps are required to modify service properties:
* <ol>
* <li>The service's properties are replaced with the provided properties.
- * <li>A service event of type {@link ServiceEvent#MODIFIED} is
- * fired.
+ * <li>A service event of type {@link ServiceEvent#MODIFIED} is fired.
* </ol>
*
* @param properties The properties for this service. See {@link Constants}
@@ -84,17 +81,19 @@
* Unregisters a service. Remove a <code>ServiceRegistration</code> object
* from the Framework service registry. All <code>ServiceReference</code>
* objects associated with this <code>ServiceRegistration</code> object
- * can no longer be used to interact with the service.
+ * can no longer be used to interact with the service once unregistration is
+ * complete.
*
* <p>
* The following steps are required to unregister a service:
* <ol>
* <li>The service is removed from the Framework service registry so that
- * it can no longer be used. <code>ServiceReference</code> objects for the
- * service may no longer be used to get a service object for the service.
- * <li>A service event of type {@link ServiceEvent#UNREGISTERING} is
- * fired so that bundles using this service can release their
- * use of it.
+ * it can no longer be obtained.
+ * <li>A service event of type {@link ServiceEvent#UNREGISTERING} is fired
+ * so that bundles using this service can release their use of the service.
+ * Once delivery of the service event is complete, the
+ * <code>ServiceReference</code> objects for the service may no longer be
+ * used to get a service object for the service.
* <li>For each bundle whose use count for this service is greater than
* zero: <br>
* The bundle's use count for this service is set to zero. <br>
@@ -103,7 +102,7 @@
* the service object for the bundle.
* </ol>
*
- * @throws java.lang.IllegalStateException If this
+ * @throws IllegalStateException If this
* <code>ServiceRegistration</code> object has already been
* unregistered.
* @see BundleContext#ungetService
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/SignerProperty.java b/org.osgi.core/src/main/java/org/osgi/framework/SignerProperty.java
new file mode 100644
index 0000000..2ba0389
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/SignerProperty.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Package private class used by permissions for filter matching on signer key
+ * during filter expression evaluation in the permission implies method.
+ *
+ * @Immutable
+ * @version $Revision: 6479 $
+ */
+class SignerProperty {
+ private final Bundle bundle;
+ private final String pattern;
+
+ /**
+ * String constructor used by the filter matching algorithm to construct a
+ * SignerProperty from the attribute value in a filter expression.
+ *
+ * @param pattern Attribute value in the filter expression.
+ */
+ public SignerProperty(String pattern) {
+ this.pattern = pattern;
+ this.bundle = null;
+ }
+
+ /**
+ * Used by the permission implies method to build the properties for a
+ * filter match.
+ *
+ * @param bundle The bundle whose signers are to be matched.
+ */
+ SignerProperty(Bundle bundle) {
+ this.bundle = bundle;
+ this.pattern = null;
+ }
+
+ /**
+ * Used by the filter matching algorithm. This methods does NOT satisfy the
+ * normal equals contract. Since the class is only used in filter expression
+ * evaluations, it only needs to support comparing an instance created with
+ * a Bundle to an instance created with a pattern string from the filter
+ * expression.
+ *
+ * @param o SignerProperty to compare against.
+ * @return true if the DN name chain matches the pattern.
+ */
+ public boolean equals(Object o) {
+ if (!(o instanceof SignerProperty))
+ return false;
+ SignerProperty other = (SignerProperty) o;
+ Bundle matchBundle = bundle != null ? bundle : other.bundle;
+ String matchPattern = bundle != null ? other.pattern : pattern;
+ Map/* <X509Certificate, List<X509Certificate>> */signers = matchBundle
+ .getSignerCertificates(Bundle.SIGNERS_TRUSTED);
+ for (Iterator iSigners = signers.values().iterator(); iSigners
+ .hasNext();) {
+ List/* <X509Certificate> */signerCerts = (List) iSigners.next();
+ List/* <String> */dnChain = new ArrayList(signerCerts.size());
+ for (Iterator iCerts = signerCerts.iterator(); iCerts.hasNext();) {
+ dnChain.add(((X509Certificate) iCerts.next()).getSubjectDN()
+ .getName());
+ }
+ if (FrameworkUtil
+ .matchDistinguishedNameChain(matchPattern, dnChain)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Since the equals method does not obey the general equals contract, this
+ * method cannot generate hash codes which obey the equals contract.
+ */
+ public int hashCode() {
+ return 31;
+ }
+
+ /**
+ * Check if the bundle is signed.
+ *
+ * @return true if constructed with a bundle that is signed.
+ */
+ boolean isBundleSigned() {
+ if (bundle == null) {
+ return false;
+ }
+ Map/* <X509Certificate, List<X509Certificate>> */signers = bundle
+ .getSignerCertificates(Bundle.SIGNERS_TRUSTED);
+ return !signers.isEmpty();
+ }
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/SynchronousBundleListener.java b/org.osgi.core/src/main/java/org/osgi/framework/SynchronousBundleListener.java
index e1ec5d5..9104f04 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/SynchronousBundleListener.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/SynchronousBundleListener.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/SynchronousBundleListener.java,v 1.15 2007/02/20 00:16:30 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2001, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2001, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,7 +45,7 @@
* @since 1.1
* @see BundleEvent
* @ThreadSafe
- * @version $Revision: 1.15 $
+ * @version $Revision: 5673 $
*/
public interface SynchronousBundleListener extends BundleListener {
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/Version.java b/org.osgi.core/src/main/java/org/osgi/framework/Version.java
index 55c8268..7317495 100644
--- a/org.osgi.core/src/main/java/org/osgi/framework/Version.java
+++ b/org.osgi.core/src/main/java/org/osgi/framework/Version.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/Version.java,v 1.17 2007/02/20 00:07:22 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,7 +37,7 @@
*
* @since 1.3
* @Immutable
- * @version $Revision: 1.17 $
+ * @version $Revision: 6860 $
*/
public class Version implements Comparable {
@@ -50,8 +48,7 @@
private static final String SEPARATOR = "."; //$NON-NLS-1$
/**
- * The empty version "0.0.0". Equivalent to calling
- * <code>new Version(0,0,0)</code>.
+ * The empty version "0.0.0".
*/
public static final Version emptyVersion = new Version(0, 0, 0);
@@ -72,14 +69,14 @@
}
/**
- * Creates a version identifier from the specifed components.
+ * Creates a version identifier from the specified components.
*
* @param major Major component of the version identifier.
* @param minor Minor component of the version identifier.
* @param micro Micro component of the version identifier.
* @param qualifier Qualifier component of the version identifier. If
- * <code>null</code> is specified, then the qualifier will be set
- * to the empty string.
+ * <code>null</code> is specified, then the qualifier will be set to
+ * the empty string.
* @throws IllegalArgumentException If the numerical components are negative
* or the qualifier string is invalid.
*/
@@ -118,26 +115,26 @@
* formatted.
*/
public Version(String version) {
- int major = 0;
- int minor = 0;
- int micro = 0;
- String qualifier = ""; //$NON-NLS-1$
+ int maj = 0;
+ int min = 0;
+ int mic = 0;
+ String qual = ""; //$NON-NLS-1$
try {
StringTokenizer st = new StringTokenizer(version, SEPARATOR, true);
- major = Integer.parseInt(st.nextToken());
+ maj = Integer.parseInt(st.nextToken());
if (st.hasMoreTokens()) {
st.nextToken(); // consume delimiter
- minor = Integer.parseInt(st.nextToken());
+ min = Integer.parseInt(st.nextToken());
if (st.hasMoreTokens()) {
st.nextToken(); // consume delimiter
- micro = Integer.parseInt(st.nextToken());
+ mic = Integer.parseInt(st.nextToken());
if (st.hasMoreTokens()) {
st.nextToken(); // consume delimiter
- qualifier = st.nextToken();
+ qual = st.nextToken();
if (st.hasMoreTokens()) {
throw new IllegalArgumentException("invalid format"); //$NON-NLS-1$
@@ -150,10 +147,10 @@
throw new IllegalArgumentException("invalid format"); //$NON-NLS-1$
}
- this.major = major;
- this.minor = minor;
- this.micro = micro;
- this.qualifier = qualifier;
+ major = maj;
+ minor = min;
+ micro = mic;
+ qualifier = qual;
validate();
}
@@ -173,11 +170,23 @@
if (micro < 0) {
throw new IllegalArgumentException("negative micro"); //$NON-NLS-1$
}
- int length = qualifier.length();
- for (int i = 0; i < length; i++) {
- if ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-".indexOf(qualifier.charAt(i)) == -1) { //$NON-NLS-1$
- throw new IllegalArgumentException("invalid qualifier"); //$NON-NLS-1$
+ char[] chars = qualifier.toCharArray();
+ for (int i = 0, length = chars.length; i < length; i++) {
+ char ch = chars[i];
+ if (('A' <= ch) && (ch <= 'Z')) {
+ continue;
}
+ if (('a' <= ch) && (ch <= 'z')) {
+ continue;
+ }
+ if (('0' <= ch) && (ch <= '9')) {
+ continue;
+ }
+ if ((ch == '_') || (ch == '-')) {
+ continue;
+ }
+ throw new IllegalArgumentException(
+ "invalid qualifier: " + qualifier); //$NON-NLS-1$
}
}
@@ -256,13 +265,18 @@
* @return The string representation of this version identifier.
*/
public String toString() {
- String base = major + SEPARATOR + minor + SEPARATOR + micro;
- if (qualifier.length() == 0) { //$NON-NLS-1$
- return base;
+ int q = qualifier.length();
+ StringBuffer result = new StringBuffer(20 + q);
+ result.append(major);
+ result.append(SEPARATOR);
+ result.append(minor);
+ result.append(SEPARATOR);
+ result.append(micro);
+ if (q > 0) {
+ result.append(SEPARATOR);
+ result.append(qualifier);
}
- else {
- return base + SEPARATOR + qualifier;
- }
+ return result.toString();
}
/**
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/EventHook.java b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/EventHook.java
new file mode 100644
index 0000000..fe21fba
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/EventHook.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework.hooks.service;
+
+import java.util.Collection;
+
+import org.osgi.framework.ServiceEvent;
+
+/**
+ * OSGi Framework Service Event Hook Service.
+ *
+ * <p>
+ * Bundles registering this service will be called during framework service
+ * (register, modify, and unregister service) operations.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6860 $
+ */
+
+public interface EventHook {
+ /**
+ * Event hook method. This method is called prior to service event delivery
+ * when a publishing bundle registers, modifies or unregisters a service.
+ * This method can filter the bundles which receive the event.
+ *
+ * @param event The service event to be delivered.
+ * @param contexts A <code>Collection</code> of Bundle Contexts for bundles
+ * which have listeners to which the specified event will be
+ * delivered. The implementation of this method may remove bundle
+ * contexts from the collection to prevent the event from being
+ * delivered to the associated bundles. The collection supports all
+ * the optional <code>Collection</code> operations except
+ * <code>add</code> and <code>addAll</code>. Attempting to add to the
+ * collection will result in an
+ * <code>UnsupportedOperationException</code>. The collection is not
+ * synchronized.
+ */
+ void event(ServiceEvent event,
+ Collection/* <? extends BundleContext> */contexts);
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/FindHook.java b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/FindHook.java
new file mode 100644
index 0000000..02044f3
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/FindHook.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework.hooks.service;
+
+import java.util.Collection;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * OSGi Framework Service Find Hook Service.
+ *
+ * <p>
+ * Bundles registering this service will be called during framework service find
+ * (get service references) operations.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6860 $
+ */
+
+public interface FindHook {
+ /**
+ * Find hook method. This method is called during the service find operation
+ * (for example, {@link BundleContext#getServiceReferences(String, String)}
+ * ). This method can filter the result of the find operation.
+ *
+ * @param context The bundle context of the bundle performing the find
+ * operation.
+ * @param name The class name of the services to find or <code>null</code>
+ * to find all services.
+ * @param filter The filter criteria of the services to find or
+ * <code>null</code> for no filter criteria.
+ * @param allServices <code>true</code> if the find operation is the result
+ * of a call to
+ * {@link BundleContext#getAllServiceReferences(String, String)}
+ * @param references A <code>Collection</code> of Service References to be
+ * returned as a result of the find operation. The implementation of
+ * this method may remove service references from the collection to
+ * prevent the references from being returned to the bundle
+ * performing the find operation. The collection supports all the
+ * optional <code>Collection</code> operations except
+ * <code>add</code> and <code>addAll</code>. Attempting to add to the
+ * collection will result in an
+ * <code>UnsupportedOperationException</code>. The collection is not
+ * synchronized.
+ */
+ void find(BundleContext context, String name, String filter,
+ boolean allServices,
+ Collection/* <? extends ServiceReference> */references);
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/ListenerHook.java b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/ListenerHook.java
new file mode 100644
index 0000000..7ee855b
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/ListenerHook.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework.hooks.service;
+
+import java.util.Collection;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * OSGi Framework Service Listener Hook Service.
+ *
+ * <p>
+ * Bundles registering this service will be called during service listener
+ * addition and removal.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6906 $
+ */
+
+public interface ListenerHook {
+ /**
+ * Added listeners hook method. This method is called to provide the hook
+ * implementation with information on newly added service listeners. This
+ * method will be called as service listeners are added while this hook is
+ * registered. Also, immediately after registration of this hook, this
+ * method will be called to provide the current collection of service
+ * listeners which had been added prior to the hook being registered.
+ *
+ * @param listeners A <code>Collection</code> of {@link ListenerInfo}s for
+ * newly added service listeners which are now listening to service
+ * events. Attempting to add to or remove from the collection will
+ * result in an <code>UnsupportedOperationException</code>. The
+ * collection is not synchronized.
+ */
+ void added(Collection/* <? extends ListenerInfo> */listeners);
+
+ /**
+ * Removed listeners hook method. This method is called to provide the hook
+ * implementation with information on newly removed service listeners. This
+ * method will be called as service listeners are removed while this hook is
+ * registered.
+ *
+ * @param listeners A <code>Collection</code> of {@link ListenerInfo}s for
+ * newly removed service listeners which are no longer listening to
+ * service events. Attempting to add to or remove from the collection
+ * will result in an <code>UnsupportedOperationException</code>. The
+ * collection is not synchronized.
+ */
+ void removed(Collection/* <? extends ListenerInfo> */listeners);
+
+ /**
+ * Information about a Service Listener. This interface describes the bundle
+ * which added the Service Listener and the filter with which it was added.
+ *
+ * @ThreadSafe
+ */
+ public interface ListenerInfo {
+ /**
+ * Return the context of the bundle which added the listener.
+ *
+ * @return The context of the bundle which added the listener.
+ */
+ BundleContext getBundleContext();
+
+ /**
+ * Return the filter string with which the listener was added.
+ *
+ * @return The filter string with which the listener was added. This may
+ * be <code>null</code> if the listener was added without a
+ * filter.
+ */
+ String getFilter();
+
+ /**
+ * Return the state of the listener for this addition and removal life
+ * cycle. Initially this method will return <code>false</code>
+ * indicating the listener has been added but has not been removed.
+ * After the listener has been removed, this method must always return
+ * <code>true</code>.
+ *
+ * <p>
+ * There is an extremely rare case in which removed notification to
+ * {@link ListenerHook}s can be made before added notification if two
+ * threads are racing to add and remove the same service listener.
+ * Because {@link ListenerHook}s are called synchronously during service
+ * listener addition and removal, the Framework cannot guarantee
+ * in-order delivery of added and removed notification for a given
+ * service listener. This method can be used to detect this rare
+ * occurrence.
+ *
+ * @return <code>false</code> if the listener has not been been removed,
+ * <code>true</code> otherwise.
+ */
+ boolean isRemoved();
+
+ /**
+ * Compares this <code>ListenerInfo</code> to another
+ * <code>ListenerInfo</code>. Two <code>ListenerInfo</code>s are equals
+ * if they refer to the same listener for a given addition and removal
+ * life cycle. If the same listener is added again, it must have a
+ * different <code>ListenerInfo</code> which is not equal to this
+ * <code>ListenerInfo</code>.
+ *
+ * @param obj The object to compare against this
+ * <code>ListenerInfo</code>.
+ * @return <code>true</code> if the other object is a
+ * <code>ListenerInfo</code> object and both objects refer to
+ * the same listener for a given addition and removal life
+ * cycle.
+ */
+ boolean equals(Object obj);
+
+ /**
+ * Returns the hash code for this <code>ListenerInfo</code>.
+ *
+ * @return The hash code of this <code>ListenerInfo</code>.
+ */
+ int hashCode();
+ }
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/package.html b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/package.html
new file mode 100644
index 0000000..46d18ac
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6211 $ -->
+<BODY>
+<p>Framework Service Hooks Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework.hooks.service;version="[1.0,2.0)"
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/packageinfo b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/hooks/service/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/launch/Framework.java b/org.osgi.core/src/main/java/org/osgi/framework/launch/Framework.java
new file mode 100644
index 0000000..f7618aa
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/launch/Framework.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework.launch;
+
+import java.io.InputStream;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+
+/**
+ * A Framework instance. A Framework is also known as a System Bundle.
+ *
+ * <p>
+ * Framework instances are created using a {@link FrameworkFactory}. The methods
+ * of this interface can be used to manage and control the created framework
+ * instance.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6542 $
+ */
+public interface Framework extends Bundle {
+
+ /**
+ * Initialize this Framework. After calling this method, this Framework
+ * must:
+ * <ul>
+ * <li>Be in the {@link #STARTING} state.</li>
+ * <li>Have a valid Bundle Context.</li>
+ * <li>Be at start level 0.</li>
+ * <li>Have event handling enabled.</li>
+ * <li>Have reified Bundle objects for all installed bundles.</li>
+ * <li>Have registered any framework services. For example,
+ * <code>PackageAdmin</code>, <code>ConditionalPermissionAdmin</code>,
+ * <code>StartLevel</code>.</li>
+ * </ul>
+ *
+ * <p>
+ * This Framework will not actually be started until {@link #start() start}
+ * is called.
+ *
+ * <p>
+ * This method does nothing if called when this Framework is in the
+ * {@link #STARTING}, {@link #ACTIVE} or {@link #STOPPING} states.
+ *
+ * @throws BundleException If this Framework could not be initialized.
+ * @throws SecurityException If the Java Runtime Environment supports
+ * permissions and the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code> or if there is a
+ * security manager already installed and the
+ * {@link Constants#FRAMEWORK_SECURITY} configuration property is
+ * set.
+ *
+ */
+ void init() throws BundleException;
+
+ /**
+ * Wait until this Framework has completely stopped. The <code>stop</code>
+ * and <code>update</code> methods on a Framework performs an asynchronous
+ * stop of the Framework. This method can be used to wait until the
+ * asynchronous stop of this Framework has completed. This method will only
+ * wait if called when this Framework is in the {@link #STARTING},
+ * {@link #ACTIVE}, or {@link #STOPPING} states. Otherwise it will return
+ * immediately.
+ * <p>
+ * A Framework Event is returned to indicate why this Framework has stopped.
+ *
+ * @param timeout Maximum number of milliseconds to wait until this
+ * Framework has completely stopped. A value of zero will wait
+ * indefinitely.
+ * @return A Framework Event indicating the reason this method returned. The
+ * following <code>FrameworkEvent</code> types may be returned by
+ * this method.
+ * <ul>
+ * <li>{@link FrameworkEvent#STOPPED STOPPED} - This Framework has
+ * been stopped. </li>
+ *
+ * <li>{@link FrameworkEvent#STOPPED_UPDATE STOPPED_UPDATE} - This
+ * Framework has been updated which has shutdown and will now
+ * restart.</li>
+ *
+ * <li> {@link FrameworkEvent#STOPPED_BOOTCLASSPATH_MODIFIED
+ * STOPPED_BOOTCLASSPATH_MODIFIED} - This Framework has been stopped
+ * and a bootclasspath extension bundle has been installed or
+ * updated. The VM must be restarted in order for the changed boot
+ * class path to take affect. </li>
+ *
+ * <li>{@link FrameworkEvent#ERROR ERROR} - The Framework
+ * encountered an error while shutting down or an error has occurred
+ * which forced the framework to shutdown. </li>
+ *
+ * <li> {@link FrameworkEvent#WAIT_TIMEDOUT WAIT_TIMEDOUT} - This
+ * method has timed out and returned before this Framework has
+ * stopped.</li>
+ * </ul>
+ * @throws InterruptedException If another thread interrupted the current
+ * thread before or while the current thread was waiting for this
+ * Framework to completely stop. The <i>interrupted status</i> of
+ * the current thread is cleared when this exception is thrown.
+ * @throws IllegalArgumentException If the value of timeout is negative.
+ */
+ FrameworkEvent waitForStop(long timeout) throws InterruptedException;
+
+ /**
+ * Start this Framework.
+ *
+ * <p>
+ * The following steps are taken to start this Framework:
+ * <ol>
+ * <li>If this Framework is not in the {@link #STARTING} state,
+ * {@link #init() initialize} this Framework.</li>
+ * <li>All installed bundles must be started in accordance with each
+ * bundle's persistent <i>autostart setting</i>. This means some bundles
+ * will not be started, some will be started with <i>eager activation</i>
+ * and some will be started with their <i>declared activation</i> policy. If
+ * this Framework implements the optional <i>Start Level Service
+ * Specification</i>, then the start level of this Framework is moved to the
+ * start level specified by the
+ * {@link Constants#FRAMEWORK_BEGINNING_STARTLEVEL beginning start level}
+ * framework property, as described in the <i>Start Level Service
+ * Specification</i>. If this framework property is not specified, then the
+ * start level of this Framework is moved to start level one (1). Any
+ * exceptions that occur during bundle starting must be wrapped in a
+ * {@link BundleException} and then published as a framework event of type
+ * {@link FrameworkEvent#ERROR}</li>
+ * <li>This Framework's state is set to {@link #ACTIVE}.</li>
+ * <li>A framework event of type {@link FrameworkEvent#STARTED} is fired</li>
+ * </ol>
+ *
+ * @throws BundleException If this Framework could not be started.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @see "Start Level Service Specification"
+ */
+ void start() throws BundleException;
+
+ /**
+ * Start this Framework.
+ *
+ * <p>
+ * Calling this method is the same as calling {@link #start()}. There are no
+ * start options for the Framework.
+ *
+ * @param options Ignored. There are no start options for the Framework.
+ * @throws BundleException If this Framework could not be started.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @see #start()
+ */
+ void start(int options) throws BundleException;
+
+ /**
+ * Stop this Framework.
+ *
+ * <p>
+ * The method returns immediately to the caller after initiating the
+ * following steps to be taken on another thread.
+ * <ol>
+ * <li>This Framework's state is set to {@link #STOPPING}.</li>
+ * <li>All installed bundles must be stopped without changing each bundle's
+ * persistent <i>autostart setting</i>. If this Framework implements the
+ * optional <i>Start Level Service Specification</i>, then the start level
+ * of this Framework is moved to start level zero (0), as described in the
+ * <i>Start Level Service Specification</i>. Any exceptions that occur
+ * during bundle stopping must be wrapped in a {@link BundleException} and
+ * then published as a framework event of type {@link FrameworkEvent#ERROR}</li>
+ * <li>Unregister all services registered by this Framework.</li>
+ * <li>Event handling is disabled.</li>
+ * <li>This Framework's state is set to {@link #RESOLVED}.</li>
+ * <li>All resources held by this Framework are released. This includes
+ * threads, bundle class loaders, open files, etc.</li>
+ * <li>Notify all threads that are waiting at {@link #waitForStop(long)
+ * waitForStop} that the stop operation has completed.</li>
+ * </ol>
+ * <p>
+ * After being stopped, this Framework may be discarded, initialized or
+ * started.
+ *
+ * @throws BundleException If stopping this Framework could not be
+ * initiated.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @see "Start Level Service Specification"
+ */
+ void stop() throws BundleException;
+
+ /**
+ * Stop this Framework.
+ *
+ * <p>
+ * Calling this method is the same as calling {@link #stop()}. There are no
+ * stop options for the Framework.
+ *
+ * @param options Ignored. There are no stop options for the Framework.
+ * @throws BundleException If stopping this Framework could not be
+ * initiated.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+ * Environment supports permissions.
+ * @see #stop()
+ */
+ void stop(int options) throws BundleException;
+
+ /**
+ * The Framework cannot be uninstalled.
+ *
+ * <p>
+ * This method always throws a BundleException.
+ *
+ * @throws BundleException This Framework cannot be uninstalled.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+ * Runtime Environment supports permissions.
+ */
+ void uninstall() throws BundleException;
+
+ /**
+ * Stop and restart this Framework.
+ *
+ * <p>
+ * The method returns immediately to the caller after initiating the
+ * following steps to be taken on another thread.
+ * <ol>
+ * <li>Perform the steps in the {@link #stop()} method to stop this
+ * Framework.</li>
+ * <li>Perform the steps in the {@link #start()} method to start this
+ * Framework.</li>
+ * </ol>
+ *
+ * @throws BundleException If stopping and restarting this Framework could
+ * not be initiated.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+ * Runtime Environment supports permissions.
+ */
+ void update() throws BundleException;
+
+ /**
+ * Stop and restart this Framework.
+ *
+ * <p>
+ * Calling this method is the same as calling {@link #update()} except that
+ * any provided InputStream is immediately closed.
+ *
+ * @param in Any provided InputStream is immediately closed before returning
+ * from this method and otherwise ignored.
+ * @throws BundleException If stopping and restarting this Framework could
+ * not be initiated.
+ * @throws SecurityException If the caller does not have the appropriate
+ * <code>AdminPermission[this,LIFECYCLE]</code>, and the Java
+ * Runtime Environment supports permissions.
+ */
+ void update(InputStream in) throws BundleException;
+
+ /**
+ * Returns the Framework unique identifier. This Framework is assigned the
+ * unique identifier zero (0) since this Framework is also a System Bundle.
+ *
+ * @return 0.
+ * @see Bundle#getBundleId()
+ */
+ long getBundleId();
+
+ /**
+ * Returns the Framework location identifier. This Framework is assigned the
+ * unique location "<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/org.osgi.core/src/main/java/org/osgi/framework/launch/FrameworkFactory.java b/org.osgi.core/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
new file mode 100644
index 0000000..bcb6da3
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework.launch;
+
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * A factory for creating {@link Framework} instances.
+ *
+ * <p>
+ * A framework implementation jar must contain the following resource:
+ *
+ * <pre>
+ * /META-INF/services/org.osgi.framework.launch.FrameworkFactory
+ * </pre>
+ *
+ * This UTF-8 encoded resource must contain the name of the framework
+ * implementation's FrameworkFactory implementation class. Space and tab
+ * characters, including blank lines, in the resource must be ignored. The
+ * number sign ('#' \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/org.osgi.core/src/main/java/org/osgi/framework/launch/package.html b/org.osgi.core/src/main/java/org/osgi/framework/launch/package.html
new file mode 100644
index 0000000..6b0407b
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/launch/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Framework Launch Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework.launch;version="[1.0,2.0)"
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/launch/packageinfo b/org.osgi.core/src/main/java/org/osgi/framework/launch/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/launch/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/package.html b/org.osgi.core/src/main/java/org/osgi/framework/package.html
new file mode 100644
index 0000000..44d6c48
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Framework Package Version 1.5.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.framework;version="[1.5,2.0)"
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/framework/packageinfo b/org.osgi.core/src/main/java/org/osgi/framework/packageinfo
new file mode 100644
index 0000000..ccee95e
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/framework/packageinfo
@@ -0,0 +1 @@
+version 1.5
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java
index 752cdd0..25c4ad9 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/BundleLocationCondition.java,v 1.18 2006/06/16 16:31:37 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,13 +20,21 @@
import java.security.PrivilegedAction;
import java.util.Hashtable;
-import org.osgi.framework.*;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
/**
- * Condition to test if the location of a bundle matches a pattern. Pattern
- * matching is done according to the filter string matching rules.
+ * Condition to test if the location of a bundle matches or does not match a
+ * pattern. Since the bundle's location cannot be changed, this condition is
+ * immutable.
*
- * @version $Revision: 1.18 $
+ * <p>
+ * Pattern matching is done according to the filter string matching rules.
+ *
+ * @ThreadSafe
+ * @version $Revision: 5901 $
*/
public class BundleLocationCondition {
private static final String CONDITION_TYPE = "org.osgi.service.condpermadmin.BundleLocationCondition";
@@ -38,25 +44,31 @@
* to the location pattern.
*
* @param bundle The Bundle being evaluated.
- * @param info The ConditionInfo to construct the condition for. The args of
- * the ConditionInfo must be a single String which specifies the
- * location pattern to match against the Bundle location. Matching is
- * done according to the filter string matching rules. Any '*'
- * characters in the location argument are used as wildcards when
- * matching bundle locations unless they are escaped with a '\'
- * character.
+ * @param info The ConditionInfo from which to construct the condition. The
+ * ConditionInfo must specify one or two arguments. The first
+ * argument of the ConditionInfo specifies the location pattern
+ * against which to match the bundle location. Matching is done
+ * according to the filter string matching rules. Any '*' characters
+ * in the first argument are used as wildcards when matching bundle
+ * locations unless they are escaped with a '\' character. The
+ * Condition is satisfied if the bundle location matches the pattern.
+ * The second argument of the ConditionInfo is optional. If a second
+ * argument is present and equal to "!", then the satisfaction of the
+ * Condition is negated. That is, the Condition is satisfied if the
+ * bundle location does NOT match the pattern. If the second argument
+ * is present but does not equal "!", then the second argument is
+ * ignored.
* @return Condition object for the requested condition.
*/
- static public Condition getCondition(final Bundle bundle, ConditionInfo info) {
+ static public Condition getCondition(final Bundle bundle,
+ final ConditionInfo info) {
if (!CONDITION_TYPE.equals(info.getType()))
throw new IllegalArgumentException(
"ConditionInfo must be of type \"" + CONDITION_TYPE + "\"");
String[] args = info.getArgs();
- if (args.length != 1)
- throw new IllegalArgumentException("Illegal number of args: "
- + args.length);
- String bundleLocation = (String) AccessController
- .doPrivileged(new PrivilegedAction() {
+ if (args.length != 1 && args.length != 2)
+ throw new IllegalArgumentException("Illegal number of args: " + args.length);
+ String bundleLocation = (String) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return bundle.getLocation();
}
@@ -67,12 +79,14 @@
+ escapeLocation(args[0]) + ")");
}
catch (InvalidSyntaxException e) {
- // this should never happen, but just incase
- throw new RuntimeException("Invalid filter: " + e.getFilter());
+ // this should never happen, but just in case
+ throw new RuntimeException("Invalid filter: " + e.getFilter(), e);
}
Hashtable matchProps = new Hashtable(2);
matchProps.put("location", bundleLocation);
- return filter.match(matchProps) ? Condition.TRUE : Condition.FALSE;
+ boolean negate = (args.length == 2) ? "!".equals(args[1]) : false;
+ return (negate ^ filter.match(matchProps)) ? Condition.TRUE
+ : Condition.FALSE;
}
private BundleLocationCondition() {
@@ -86,7 +100,7 @@
* @param value unescaped value string.
* @return escaped value string.
*/
- private static String escapeLocation(String value) {
+ private static String escapeLocation(final String value) {
boolean escaped = false;
int inlen = value.length();
int outlen = inlen << 1; /* inlen * 2 */
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java
index 31cf5ff..31b6481 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/BundleSignerCondition.java,v 1.13 2006/10/24 17:54:27 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,15 +16,19 @@
package org.osgi.service.condpermadmin;
-import java.lang.reflect.*;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
/**
- * Condition to test if the signer of a bundle matches a pattern. Since the bundle's signer can
- * only change when the bundle is updated, this condition is immutable.
+ * Condition to test if the signer of a bundle matches or does not match a
+ * pattern. Since the bundle's signer can only change when the bundle is
+ * updated, this condition is immutable.
* <p>
* The condition expressed using a single String that specifies a Distinguished
* Name (DN) chain to match bundle signers against. DN's are encoded using IETF
@@ -47,68 +49,10 @@
* must be the first RDN and will match any number of RDNs (including zero
* RDNs).
*
- * @version $Revision: 1.13 $
+ * @ThreadSafe
+ * @version $Revision: 6860 $
*/
public class BundleSignerCondition {
- /*
- * NOTE: A framework implementor may also choose to replace this class in
- * their distribution with a class that directly interfaces with the
- * framework implementation. This replacement class MUST NOT alter the
- * public/protected signature of this class.
- */
-
- /*
- * This class will load the BundleSignerCondition class in the package named
- * by the org.osgi.vendor.condpermadmin package. This class will delegate
- * getCondition methods calls to the vendor BundleSignerCondition class.
- */
-
- private static class ImplHolder implements PrivilegedAction {
- private static final String packageProperty = "org.osgi.vendor.condpermadmin";
- static final Method getCondition;
- static {
- getCondition = (Method) AccessController.doPrivileged(new ImplHolder());
- }
-
- private ImplHolder() {
- }
-
- public Object run() {
- String packageName = System
- .getProperty(packageProperty);
- if (packageName == null) {
- throw new NoClassDefFoundError(packageProperty
- + " property not set");
- }
-
- Class delegateClass;
- try {
- delegateClass = Class.forName(packageName
- + ".BundleSignerCondition");
- }
- catch (ClassNotFoundException e) {
- throw new NoClassDefFoundError(e.toString());
- }
-
- Method result;
- try {
- result = delegateClass.getMethod("getCondition",
- new Class[] {Bundle.class,
- ConditionInfo.class });
- }
- catch (NoSuchMethodException e) {
- throw new NoSuchMethodError(e.toString());
- }
-
- if (!Modifier.isStatic(result.getModifiers())) {
- throw new NoSuchMethodError(
- "getCondition method must be static");
- }
-
- return result;
- }
- }
-
private static final String CONDITION_TYPE = "org.osgi.service.condpermadmin.BundleSignerCondition";
/**
@@ -116,39 +60,48 @@
* to the location pattern.
*
* @param bundle The Bundle being evaluated.
- * @param info The ConditionInfo to construct the condition for. The args of
- * the ConditionInfo specify a single String specifying the chain of
- * distinguished names pattern to match against the signer of the
- * Bundle.
- * @return A Condition which checks the signers of the specified bundle.
+ * @param info The ConditionInfo from which to construct the condition. The
+ * ConditionInfo must specify one or two arguments. The first
+ * argument of the ConditionInfo specifies the chain of distinguished
+ * names pattern to match against the signer of the bundle. The
+ * Condition is satisfied if the signer of the bundle matches the
+ * pattern. The second argument of the ConditionInfo is optional. If
+ * a second argument is present and equal to "!", then the
+ * satisfaction of the Condition is negated. That is, the Condition
+ * is satisfied if the signer of the bundle does NOT match the
+ * pattern. If the second argument is present but does not equal "!",
+ * then the second argument is ignored.
+ * @return A Condition which checks the signers of the specified bundle.
*/
- public static Condition getCondition(Bundle bundle, ConditionInfo info) {
+ public static Condition getCondition(final Bundle bundle,
+ final ConditionInfo info) {
if (!CONDITION_TYPE.equals(info.getType()))
throw new IllegalArgumentException(
"ConditionInfo must be of type \"" + CONDITION_TYPE + "\"");
String[] args = info.getArgs();
- if (args.length != 1)
+ if (args.length != 1 && args.length != 2)
throw new IllegalArgumentException("Illegal number of args: "
+ args.length);
- try {
- try {
- return (Condition) ImplHolder.getCondition.invoke(null, new Object[] {
- bundle, info});
+ Map/* <X509Certificate, List<X509Certificate>> */signers = bundle
+ .getSignerCertificates(Bundle.SIGNERS_TRUSTED);
+ boolean match = false;
+ for (Iterator iSigners = signers.values().iterator(); iSigners
+ .hasNext();) {
+ List/* <X509Certificate> */signerCerts = (List) iSigners.next();
+ List/* <String> */dnChain = new ArrayList(signerCerts.size());
+ for (Iterator iCerts = signerCerts.iterator(); iCerts.hasNext();) {
+ dnChain.add(((X509Certificate) iCerts.next()).getSubjectDN()
+ .getName());
}
- catch (InvocationTargetException e) {
- throw e.getTargetException();
+ if (FrameworkUtil.matchDistinguishedNameChain(args[0], dnChain)) {
+ match = true;
+ break;
}
}
- catch (Error e) {
- throw e;
- }
- catch (RuntimeException e) {
- throw e;
- }
- catch (Throwable e) {
- throw new RuntimeException(e.toString());
- }
+
+ boolean negate = (args.length == 2) ? "!".equals(args[1]) : false;
+ return negate ^ match ? Condition.TRUE : Condition.FALSE;
}
private BundleSignerCondition() {
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/Condition.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/Condition.java
index 4716c0a..63c33b4 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/Condition.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/Condition.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/Condition.java,v 1.13 2006/06/16 16:31:37 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +23,8 @@
* using Conditional Permission Info. The Permissions of a ConditionalPermission
* Info can only be used if the associated Conditions are satisfied.
*
- * @version $Revision: 1.13 $
+ * @ThreadSafe
+ * @version $Revision: 6464 $
*/
public interface Condition {
/**
@@ -42,63 +41,75 @@
/**
* Returns whether the evaluation must be postponed until the end of the
- * permission check. This method returns <code>true</code> if the
- * evaluation of the Condition must be postponed until the end of the
- * permission check. If this method returns <code>false</code>, this
- * Condition must be able to directly answer the {@link #isSatisfied()}
- * method. In other words, isSatisfied() will return very quickly since no
- * external sources, such as for example users, need to be consulted.
+ * permission check. If this method returns <code>false</code> (or this
+ * Condition is immutable), then this Condition must be able to directly
+ * answer the {@link #isSatisfied()} method. In other words, isSatisfied()
+ * will return very quickly since no external sources, such as for example
+ * users or networks, need to be consulted. <br/>
+ * This method must always return the same value whenever it is called so
+ * that the Conditional Permission Admin can cache its result.
*
* @return <code>true</code> to indicate the evaluation must be postponed.
- * Otherwise, <code>false</code> if the evaluation can be
- * immediately performed.
+ * Otherwise, <code>false</code> if the evaluation can be performed
+ * immediately.
*/
boolean isPostponed();
/**
- * Returns whether the Condition is satisfied.
+ * Returns whether the Condition is satisfied. This method is only called
+ * for immediate Condition objects or immutable postponed conditions, and
+ * must always be called inside a permission check. Mutable postponed
+ * Condition objects will be called with the grouped version
+ * {@link #isSatisfied(Condition[],Dictionary)} at the end of the permission
+ * check.
*
- * @return <code>true</code> to indicate the Conditions is satisfied.
+ * @return <code>true</code> to indicate the Conditions is satisfied.
* Otherwise, <code>false</code> if the Condition is not satisfied.
*/
boolean isSatisfied();
/**
- * Returns whether the Condition is mutable.
+ * Returns whether the Condition is mutable. A Condition can go from mutable
+ * (<code>true</code>) to immutable (<code>false</code>) over time but never
+ * from immutable (<code>false</code>) to mutable (<code>true</code>).
*
- * @return <code>true</code> to indicate the value returned by
- * {@link #isSatisfied()} can change. Otherwise, <code>false</code>
- * if the value returned by {@link #isSatisfied()} will not change.
+ * @return <code>true</code> {@link #isSatisfied()} can change. Otherwise,
+ * <code>false</code> if the value returned by
+ * {@link #isSatisfied()} will not change for this condition.
*/
boolean isMutable();
/**
- * Returns whether a the set of Conditions are satisfied. Although this
- * method is not static, it must be implemented as if it were static. All of
- * the passed Conditions will be of the same type and will correspond to the
- * class type of the object on which this method is invoked.
+ * Returns whether a the set of Condition objects are satisfied. Although
+ * this method is not static, it must be implemented as if it were static.
+ * All of the passed Condition objects will be of the same type and will
+ * correspond to the class type of the object on which this method is
+ * invoked.This method must be called inside a permission check only.
*
- * @param conditions The array of Conditions.
+ * @param conditions The array of Condition objects, which must all be of
+ * the same class and mutable. The receiver must be one of those
+ * Condition objects.
* @param context A Dictionary object that implementors can use to track
* state. If this method is invoked multiple times in the same
- * permission evaluation, the same Dictionary will be passed multiple
+ * permission check, the same Dictionary will be passed multiple
* times. The SecurityManager treats this Dictionary as an opaque
* object and simply creates an empty dictionary and passes it to
- * subsequent invocations if multiple invocatios are needed.
- * @return <code>true</code> if all the Conditions are satisfied.
- * Otherwise, <code>false</code> if one of the Conditions is not
- * satisfied.
+ * subsequent invocations if multiple invocations are needed.
+ * @return <code>true</code> if all the Condition objects are satisfied.
+ * Otherwise, <code>false</code> if one of the Condition objects is
+ * not satisfied.
*/
boolean isSatisfied(Condition conditions[], Dictionary context);
-
}
/**
- * Package internal class used to define the {@link Condition#FALSE} and
+ * Package private class used to define the {@link Condition#FALSE} and
* {@link Condition#TRUE} constants.
+ *
+ * @Immutable
*/
final class BooleanCondition implements Condition {
- final boolean satisfied;
+ private final boolean satisfied;
BooleanCondition(boolean satisfied) {
this.satisfied = satisfied;
@@ -117,11 +128,10 @@
}
public boolean isSatisfied(Condition[] conds, Dictionary context) {
- for (int i = 0; i < conds.length; i++) {
+ for (int i = 0, length = conds.length; i < length; i++) {
if (!conds[i].isSatisfied())
return false;
}
return true;
}
-
}
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java
index e32c4ab..6cb235c 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionInfo.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/ConditionInfo.java,v 1.13 2006/06/16 16:31:37 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,40 +43,39 @@
* <code>ConditionInfo</code> object as arguments.
* </ul>
*
- * @version $Revision: 1.13 $
+ * @Immutable
+ * @version $Revision: 6492 $
*/
public class ConditionInfo {
- private String type;
- private String[] args;
+ private final String type;
+ private final String[] args;
/**
- * Constructs a <code>ConditionInfo</code> from the specified type and
- * args.
+ * Constructs a <code>ConditionInfo</code> from the specified type and args.
*
* @param type The fully qualified class name of the Condition represented
* by this <code>ConditionInfo</code>.
* @param args The arguments for the Condition. These arguments are
* available to the newly created Condition by calling the
* {@link #getArgs()} method.
- * @throws java.lang.NullPointerException If <code>type</code> is
- * <code>null</code>.
+ * @throws NullPointerException If <code>type</code> is <code>null</code>.
*/
public ConditionInfo(String type, String[] args) {
this.type = type;
- this.args = args != null ? args : new String[0];
+ this.args = (args != null) ? (String[]) args.clone() : new String[0];
if (type == null) {
throw new NullPointerException("type is null");
}
}
/**
- * Constructs a <code>ConditionInfo</code> object from the specified
- * encoded <code>ConditionInfo</code> string. White space in the encoded
+ * Constructs a <code>ConditionInfo</code> object from the specified encoded
+ * <code>ConditionInfo</code> string. White space in the encoded
* <code>ConditionInfo</code> string is ignored.
*
* @param encodedCondition The encoded <code>ConditionInfo</code>.
* @see #getEncoded
- * @throws java.lang.IllegalArgumentException If the
+ * @throws IllegalArgumentException If the specified
* <code>encodedCondition</code> is not properly formatted.
*/
public ConditionInfo(String encodedCondition) {
@@ -165,26 +162,25 @@
}
/**
- * Returns the string encoding of this <code>ConditionInfo</code> in a
- * form suitable for restoring this <code>ConditionInfo</code>.
+ * Returns the string encoding of this <code>ConditionInfo</code> in a form
+ * suitable for restoring this <code>ConditionInfo</code>.
*
* <p>
- * The encoding format is:
+ * The encoded format is:
*
* <pre>
* [type "arg0" "arg1" ...]
* </pre>
*
- * where <i>argN</i> are strings that are encoded for proper parsing.
- * Specifically, the <code>"</code>, <code>\</code>, carriage return,
- * and linefeed characters are escaped using <code>\"</code>,
- * <code>\\</code>, <code>\r</code>, and <code>\n</code>,
- * respectively.
+ * where <i>argN</i> are strings that must be encoded for proper parsing.
+ * Specifically, the <code>"</code>, <code>\</code>, carriage return,
+ * and line feed characters must be escaped using <code>\"</code>,
+ * <code>\\</code>, <code>\r</code>, and <code>\n</code>, respectively.
*
* <p>
* The encoded string contains no leading or trailing whitespace characters.
- * A single space character is used between type and "<i>arg0</i>" and
- * between the arguments.
+ * A single space character is used between type and "<i>arg0</i>"
+ * and between the arguments.
*
* @return The string encoding of this <code>ConditionInfo</code>.
*/
@@ -234,7 +230,7 @@
* arguments.
*/
public final String[] getArgs() {
- return args;
+ return (String[]) args.clone();
}
/**
@@ -278,12 +274,11 @@
*/
public int hashCode() {
- int hash = type.hashCode();
-
+ int h = 31 * 17 + type.hashCode();
for (int i = 0; i < args.length; i++) {
- hash ^= args[i].hashCode();
+ h = 31 * h + args[i].hashCode();
}
- return hash;
+ return h;
}
/**
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java
index b35f87c..2ea7d87 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java,v 1.13 2006/06/16 16:31:37 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,79 +24,213 @@
/**
* Framework service to administer Conditional Permissions. Conditional
* Permissions can be added to, retrieved from, and removed from the framework.
+ * Conditional Permissions are conceptually managed in an ordered table called
+ * the Conditional Permission Table.
*
- * @version $Revision: 1.13 $
+ * @ThreadSafe
+ * @version $Revision: 6782 $
*/
public interface ConditionalPermissionAdmin {
/**
- * Create a new Conditional Permission Info.
- *
+ * Create a new Conditional Permission Info in the Conditional Permission
+ * Table.
+ * <p>
* The Conditional Permission Info will be given a unique, never reused
- * name.
+ * name. This entry will be added at the beginning of the Conditional
+ * Permission Table with an access decision of
+ * {@link ConditionalPermissionInfo#ALLOW ALLOW}.
+ * <p>
+ * Since this method changes the Conditional Permission Table any
+ * {@link ConditionalPermissionUpdate}s that were created prior to calling
+ * this method can no longer be committed.
*
- * @param conds The Conditions that need to be satisfied to enable the
- * corresponding Permissions.
- * @param perms The Permissions that are enable when the corresponding
- * Conditions are satisfied.
+ * @param conditions The conditions that need to be satisfied to enable the
+ * specified permissions. This argument can be <code>null</code> or
+ * an empty array indicating the specified permissions are not
+ * guarded by any conditions.
+ * @param permissions The permissions that are enabled when the specified
+ * conditions, if any, are satisfied. This argument must not be
+ * <code>null</code> and must specify at least one permission.
* @return The ConditionalPermissionInfo for the specified Conditions and
* Permissions.
+ * @throws IllegalArgumentException If no permissions are specified.
* @throws SecurityException If the caller does not have
* <code>AllPermission</code>.
+ * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+ * instead.
*/
- public ConditionalPermissionInfo addConditionalPermissionInfo(
- ConditionInfo conds[], PermissionInfo perms[]);
+ ConditionalPermissionInfo addConditionalPermissionInfo(
+ ConditionInfo conditions[], PermissionInfo permissions[]);
/**
- * Set or create a Conditional Permission Info with a specified name.
- *
- * If the specified name is <code>null</code>, a new Conditional
- * Permission Info must be created and will be given a unique, never reused
- * name. If there is currently no Conditional Permission Info with the
- * specified name, a new Conditional Permission Info must be created with
- * the specified name. Otherwise, the Conditional Permission Info with the
+ * Set or create a Conditional Permission Info with a specified name in the
+ * Conditional Permission Table.
+ * <p>
+ * If the specified name is <code>null</code>, a new Conditional Permission
+ * Info must be created and will be given a unique, never reused name. If
+ * there is currently no Conditional Permission Info with the specified
+ * name, a new Conditional Permission Info must be created with the
+ * specified name. Otherwise, the Conditional Permission Info with the
* specified name must be updated with the specified Conditions and
- * Permissions.
+ * Permissions. If a new entry was created in the Conditional Permission
+ * Table it will be added at the beginning of the table with an access
+ * decision of {@link ConditionalPermissionInfo#ALLOW ALLOW}.
+ * <p>
+ * Since this method changes the underlying permission table any
+ * {@link ConditionalPermissionUpdate}s that were created prior to calling
+ * this method can no longer be committed.
*
* @param name The name of the Conditional Permission Info, or
* <code>null</code>.
- * @param conds The Conditions that need to be satisfied to enable the
- * corresponding Permissions.
- * @param perms The Permissions that are enable when the corresponding
- * Conditions are satisfied.
- * @return The ConditionalPermissionInfo that for the specified name,
- * Conditions and Permissions.
+ * @param conditions The conditions that need to be satisfied to enable the
+ * specified permissions. This argument can be <code>null</code> or
+ * an empty array indicating the specified permissions are not
+ * guarded by any conditions.
+ * @param permissions The permissions that are enabled when the specified
+ * conditions, if any, are satisfied. This argument must not be
+ * <code>null</code> and must specify at least one permission.
+ * @return The ConditionalPermissionInfo for the specified name, Conditions
+ * and Permissions.
+ * @throws IllegalArgumentException If no permissions are specified.
* @throws SecurityException If the caller does not have
* <code>AllPermission</code>.
+ * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+ * instead.
*/
- public ConditionalPermissionInfo setConditionalPermissionInfo(String name,
- ConditionInfo conds[], PermissionInfo perms[]);
+ ConditionalPermissionInfo setConditionalPermissionInfo(String name,
+ ConditionInfo conditions[], PermissionInfo permissions[]);
/**
- * Returns the Conditional Permission Infos that are currently managed by
- * Conditional Permission Admin. Calling
- * {@link ConditionalPermissionInfo#delete()} will remove the Conditional
- * Permission Info from Conditional Permission Admin.
+ * Returns the Conditional Permission Infos from the Conditional Permission
+ * Table.
+ * <p>
+ * The returned Enumeration will return elements in the order they are kept
+ * in the Conditional Permission Table.
+ * <p>
+ * The Enumeration returned is based on a copy of the Conditional Permission
+ * Table and therefore will not throw exceptions if the Conditional
+ * Permission Table is changed during the course of reading elements from
+ * the Enumeration.
*
* @return An enumeration of the Conditional Permission Infos that are
- * currently managed by Conditional Permission Admin.
+ * currently in the Conditional Permission Table.
+ * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+ * instead.
*/
- public Enumeration getConditionalPermissionInfos();
+ Enumeration/* <ConditionalPermissionInfo> */getConditionalPermissionInfos();
/**
* Return the Conditional Permission Info with the specified name.
*
* @param name The name of the Conditional Permission Info to be returned.
- * @return The Conditional Permission Info with the specified name.
+ * @return The Conditional Permission Info with the specified name or
+ * <code>null</code> if no Conditional Permission Info with the
+ * specified name exists in the Conditional Permission Table.
+ * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()}
+ * instead.
*/
- public ConditionalPermissionInfo getConditionalPermissionInfo(String name);
+ ConditionalPermissionInfo getConditionalPermissionInfo(String name);
/**
* Returns the Access Control Context that corresponds to the specified
* signers.
*
+ * The returned Access Control Context must act as if its protection domain
+ * came from a bundle that has the following characteristics:
+ * <ul>
+ * <li>It is signed by all of the given signers</li>
+ * <li>It has a bundle id of -1</li>
+ * <li>Its location is the empty string</li>
+ * <li>Its state is UNINSTALLED</li>
+ * <li>It has no headers</li>
+ * <li>It has the empty version (0.0.0)</li>
+ * <li>Its last modified time=0</li>
+ * <li>Many methods will throw <code>IllegalStateException</code> because the state is UNINSTALLED</li>
+ * <li>All other methods return a <code>null</code></li>
+ * </ul>
* @param signers The signers for which to return an Access Control Context.
* @return An <code>AccessControlContext</code> that has the Permissions
* associated with the signer.
*/
- public AccessControlContext getAccessControlContext(String[] signers);
+ AccessControlContext getAccessControlContext(String[] signers);
+
+ /**
+ * Creates a new update for the Conditional Permission Table. The update is
+ * a working copy of the current Conditional Permission Table. If the
+ * running Conditional Permission Table is modified before commit is called
+ * on the returned update, then the call to commit on the returned update
+ * will fail. That is, the commit method will return false and no change
+ * will be made to the running Conditional Permission Table. There is no
+ * requirement that commit is eventually called on the returned update.
+ *
+ * @return A new update for the Conditional Permission Table.
+ * @since 1.1
+ */
+ ConditionalPermissionUpdate newConditionalPermissionUpdate();
+
+ /**
+ * Creates a new ConditionalPermissionInfo with the specified fields
+ * suitable for insertion into a {@link ConditionalPermissionUpdate}. The
+ * <code>delete</code> method on <code>ConditionalPermissionInfo</code>
+ * objects created with this method must throw
+ * UnsupportedOperationException.
+ *
+ * @param name The name of the created
+ * <code>ConditionalPermissionInfo</code> or <code>null</code> to
+ * have a unique name generated when the returned
+ * <code>ConditionalPermissionInfo</code> is committed in an update
+ * to the Conditional Permission Table.
+ * @param conditions The conditions that need to be satisfied to enable the
+ * specified permissions. This argument can be <code>null</code> or
+ * an empty array indicating the specified permissions are not
+ * guarded by any conditions.
+ * @param permissions The permissions that are enabled when the specified
+ * conditions, if any, are satisfied. This argument must not be
+ * <code>null</code> and must specify at least one permission.
+ * @param access Access decision. Must be one of the following values:
+ * <ul>
+ * <li>{@link ConditionalPermissionInfo#ALLOW allow}</li>
+ * <li>{@link ConditionalPermissionInfo#DENY deny}</li>
+ * </ul>
+ * The specified access decision value must be evaluated case
+ * insensitively.
+ * @return A <code>ConditionalPermissionInfo</code> object suitable for
+ * insertion into a {@link ConditionalPermissionUpdate}.
+ * @throws IllegalArgumentException If no permissions are specified or if
+ * the specified access decision is not a valid value.
+ * @since 1.1
+ */
+ ConditionalPermissionInfo newConditionalPermissionInfo(String name,
+ ConditionInfo conditions[], PermissionInfo permissions[],
+ String access);
+
+ /**
+ * Creates a new <code>ConditionalPermissionInfo</code> from the specified
+ * encoded <code>ConditionalPermissionInfo</code> string suitable for
+ * insertion into a {@link ConditionalPermissionUpdate}. The
+ * <code>delete</code> method on <code>ConditionalPermissionInfo</code>
+ * objects created with this method must throw
+ * UnsupportedOperationException.
+ *
+ * @param encodedConditionalPermissionInfo The encoded
+ * <code>ConditionalPermissionInfo</code>. White space in the encoded
+ * <code>ConditionalPermissionInfo</code> is ignored. The access
+ * decision value in the encoded
+ * <code>ConditionalPermissionInfo</code> must be evaluated case
+ * insensitively. If the encoded
+ * <code>ConditionalPermissionInfo</code> does not contain the
+ * optional name, <code>null</code> must be used for the name and a
+ * unique name will be generated when the returned
+ * <code>ConditionalPermissionInfo</code> is committed in an update
+ * to the Conditional Permission Table.
+ * @return A <code>ConditionalPermissionInfo</code> object suitable for
+ * insertion into a {@link ConditionalPermissionUpdate}.
+ * @throws IllegalArgumentException If the specified
+ * <code>encodedConditionalPermissionInfo</code> is not properly
+ * formatted.
+ * @see ConditionalPermissionInfo#getEncoded
+ * @since 1.1
+ */
+ ConditionalPermissionInfo newConditionalPermissionInfo(
+ String encodedConditionalPermissionInfo);
}
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java
index 31e4d2c..dbe09be 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/ConditionalPermissionInfo.java,v 1.11 2006/06/16 16:31:37 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,43 +19,172 @@
import org.osgi.service.permissionadmin.PermissionInfo;
/**
- * A binding of a set of Conditions to a set of Permissions. Instances of this
- * interface are obtained from the Conditional Permission Admin service.
+ * A list of Permissions guarded by a list of conditions with an access
+ * decision. Instances of this interface are obtained from the Conditional
+ * Permission Admin service.
*
- * @version $Revision: 1.11 $
+ * @Immutable
+ * @version $Revision: 6492 $
*/
public interface ConditionalPermissionInfo {
/**
+ * This string is used to indicate that a row in the Conditional Permission
+ * Table should return an access decision of "allow" if the
+ * conditions are all satisfied and at least one of the permissions is
+ * implied.
+ *
+ * @since 1.1
+ */
+ public final static String ALLOW = "allow";
+
+ /**
+ * This string is used to indicate that a row in the Conditional Permission
+ * Table should return an access decision of "deny" if the
+ * conditions are all satisfied and at least one of the permissions is
+ * implied.
+ *
+ * @since 1.1
+ */
+ public final static String DENY = "deny";
+
+ /**
* Returns the Condition Infos for the Conditions that must be satisfied to
* enable the Permissions.
*
* @return The Condition Infos for the Conditions in this Conditional
* Permission Info.
*/
- public ConditionInfo[] getConditionInfos();
+ ConditionInfo[] getConditionInfos();
/**
- * Returns the Permission Infos for the Permission in this Conditional
+ * Returns the Permission Infos for the Permissions in this Conditional
* Permission Info.
*
- * @return The Permission Infos for the Permission in this Conditional
+ * @return The Permission Infos for the Permissions in this Conditional
* Permission Info.
*/
- public PermissionInfo[] getPermissionInfos();
+ PermissionInfo[] getPermissionInfos();
/**
* Removes this Conditional Permission Info from the Conditional Permission
- * Admin.
+ * Table.
+ * <p>
+ * Since this method changes the underlying permission table, any
+ * {@link ConditionalPermissionUpdate}s that were created prior to calling
+ * this method can no longer be committed.
*
+ * @throws UnsupportedOperationException If this object was created by
+ * {@link ConditionalPermissionAdmin#newConditionalPermissionInfo}
+ * or obtained from a {@link ConditionalPermissionUpdate}. This
+ * method only functions if this object was obtained from one of the
+ * {@link ConditionalPermissionAdmin} methods deprecated in version
+ * 1.1.
* @throws SecurityException If the caller does not have
* <code>AllPermission</code>.
+ * @deprecated Since 1.1. Use
+ * {@link ConditionalPermissionAdmin#newConditionalPermissionUpdate()}
+ * instead to manage the Conditional Permissions.
*/
- public void delete();
+ void delete();
/**
* Returns the name of this Conditional Permission Info.
*
- * @return The name of this Conditional Permission Info.
+ * @return The name of this Conditional Permission Info. This can be
+ * <code>null</code> if this Conditional Permission Info was created
+ * without a name.
*/
- public String getName();
+ String getName();
+
+ /**
+ * Returns the access decision for this Conditional Permission Info.
+ *
+ * @return One of the following values:
+ * <ul>
+ * <li>{@link #ALLOW allow} - The access decision is
+ * "allow".</li>
+ * <li>{@link #DENY deny} - The access decision is "deny".
+ * </li>
+ * </ul>
+ * @since 1.1
+ */
+ String getAccessDecision();
+
+ /**
+ * Returns the string encoding of this
+ * <code>ConditionalPermissionInfo</code> in a form suitable for restoring
+ * this <code>ConditionalPermissionInfo</code>.
+ *
+ * <p>
+ * The encoded format is:
+ *
+ * <pre>
+ * access {conditions permissions} name
+ * </pre>
+ *
+ * where <i>access</i> is the access decision, <i>conditions</i> is zero or
+ * more {@link ConditionInfo#getEncoded() encoded conditions},
+ * <i>permissions</i> is one or more {@link PermissionInfo#getEncoded()
+ * encoded permissions} and <i>name</i> is the name of the
+ * <code>ConditionalPermissionInfo</code>.
+ *
+ * <p>
+ * <i>name</i> is optional. If <i>name</i> is present in the encoded string,
+ * it must quoted, beginning and ending with <code>"</code>. The
+ * <i>name</i> value must be encoded for proper parsing. Specifically, the
+ * <code>"</code>, <code>\</code>, carriage return, and line feed
+ * characters must be escaped using <code>\"</code>, <code>\\</code>,
+ * <code>\r</code>, and <code>\n</code>, respectively.
+ *
+ * <p>
+ * The encoded string contains no leading or trailing whitespace characters.
+ * A single space character is used between <i>access</i> and <code>{</code>
+ * and between <code>}</code> and <i>name</i>, if <i>name</i> is present.
+ * All encoded conditions and permissions are separated by a single space
+ * character.
+ *
+ * @return The string encoding of this
+ * <code>ConditionalPermissionInfo</code>.
+ * @since 1.1
+ */
+ String getEncoded();
+
+ /**
+ * Returns the string representation of this
+ * <code>ConditionalPermissionInfo</code>. The string is created by calling
+ * the <code>getEncoded</code> method on this
+ * <code>ConditionalPermissionInfo</code>.
+ *
+ * @return The string representation of this
+ * <code>ConditionalPermissionInfo</code>.
+ * @since 1.1
+ */
+ String toString();
+
+ /**
+ * Determines the equality of two <code>ConditionalPermissionInfo</code>
+ * objects.
+ *
+ * This method checks that specified object has the same access decision,
+ * conditions, permissions and name as this
+ * <code>ConditionalPermissionInfo</code> object.
+ *
+ * @param obj The object to test for equality with this
+ * <code>ConditionalPermissionInfo</code> object.
+ * @return <code>true</code> if <code>obj</code> is a
+ * <code>ConditionalPermissionInfo</code>, and has the same access
+ * decision, conditions, permissions and name as this
+ * <code>ConditionalPermissionInfo</code> object; <code>false</code>
+ * otherwise.
+ * @since 1.1
+ */
+ boolean equals(Object obj);
+
+ /**
+ * Returns the hash code value for this object.
+ *
+ * @return A hash code value for this object.
+ * @since 1.1
+ */
+ int hashCode();
}
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionUpdate.java b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionUpdate.java
new file mode 100644
index 0000000..b116cf9
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/ConditionalPermissionUpdate.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.condpermadmin;
+
+import java.util.List;
+
+/**
+ * Update the Conditional Permission Table. There may be many update objects in
+ * the system at one time. If commit is called and the Conditional Permission
+ * Table has been modified since this update was created, then the call to
+ * commit will fail and this object should be discarded.
+ *
+ * @ThreadSafe
+ * @version $Revision: 6492 $
+ * @since 1.1
+ */
+public interface ConditionalPermissionUpdate {
+ /**
+ * This method returns the list of {@link ConditionalPermissionInfo}s for
+ * this update. This list is originally based on the Conditional Permission
+ * Table at the time this update was created. The list returned by this
+ * method will be replace the Conditional Permission Table if commit is
+ * called and is successful.
+ * <p>
+ * The {@link ConditionalPermissionInfo#delete delete} method of the
+ * ConditionalPermissionInfos in the list must throw
+ * UnsupportedOperationException.
+ * <p>
+ * The list returned by this method is ordered and the most significant
+ * table entry is the first entry in the list.
+ *
+ * @return A <code>List</code> of the {@link ConditionalPermissionInfo}s
+ * which represent the Conditional Permissions maintained by this
+ * update. Modifications to this list will not affect the
+ * Conditional Permission Table until successfully committed. The
+ * list may be empty if the Conditional Permission Table was empty
+ * when this update was created.
+ */
+ List /* <ConditionalPermissionInfo> */getConditionalPermissionInfos();
+
+ /**
+ * Commit this update. If no changes have been made to the Conditional
+ * Permission Table since this update was created, then this method will
+ * replace the Conditional Permission Table with this update's Conditional
+ * Permissions. This method may only be successfully called once on this
+ * object.
+ * <p>
+ * If any of the {@link ConditionalPermissionInfo}s in the update list has
+ * <code>null</code> as a name it will be replaced with a new
+ * {@link ConditionalPermissionInfo} object that has a generated name which
+ * is unique within the list.
+ * <p>
+ * No two entries in this update's Conditional Permissions may have the same
+ * name. Other consistency checks may also be performed. If this update's
+ * Conditional Permissions are determined to be inconsistent in some way
+ * then an <code>IllegalStateException</code> will be thrown.
+ * <p>
+ * This method returns <code>false</code> if the commit did not occur
+ * because the Conditional Permission Table has been modified since the
+ * creation of this update.
+ *
+ * @return <code>true</code> if the commit was successful.
+ * <code>false</code> if the commit did not occur because the
+ * Conditional Permission Table has been modified since the creation
+ * of this update.
+ * @throws SecurityException If the caller does not have
+ * <code>AllPermission</code>.
+ * @throws IllegalStateException If this update's Conditional Permissions
+ * are not valid or inconsistent. For example, this update has two
+ * Conditional Permissions in it with the same name.
+ */
+ boolean commit();
+}
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/package.html b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/package.html
new file mode 100644
index 0000000..7930813
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/package.html
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Conditional Permission Admin Package Version 1.1.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.condpermadmin; version="[1.1,2.0)"
+</pre>
+</BODY>
diff --git a/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/packageinfo b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/condpermadmin/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java
index 2f3deb1..67ba3e9 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/ExportedPackage.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.packageadmin/src/org/osgi/service/packageadmin/ExportedPackage.java,v 1.14 2006/06/16 16:31:49 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2001, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2001, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,7 +41,8 @@
* <code>getExportingBundle()</code> and <code>getImportingBundles()</code>
* return <code>null</code>.
*
- * @version $Revision: 1.14 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
*/
public interface ExportedPackage {
/**
@@ -73,7 +72,8 @@
*
* @return The array of resolved bundles currently wired to this exported
* package, or <code>null</code> if this
- * <code>ExportedPackage</code> object has become stale.
+ * <code>ExportedPackage</code> object has become stale. The array
+ * will be empty if no bundles are wired to this exported package.
*/
public Bundle[] getImportingBundles();
diff --git a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java
index a382f39..c93cd28 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/PackageAdmin.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.packageadmin/src/org/osgi/service/packageadmin/PackageAdmin.java,v 1.19 2006/06/16 16:31:49 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2001, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2001, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +27,8 @@
* If present, there will only be a single instance of this service registered
* with the Framework.
*
- * @version $Revision: 1.19 $
+ * @ThreadSafe
+ * @version $Revision: 6779 $
* @see org.osgi.service.packageadmin.ExportedPackage
* @see org.osgi.service.packageadmin.RequiredBundle
*/
@@ -38,8 +37,8 @@
* Gets the exported packages for the specified bundle.
*
* @param bundle The bundle whose exported packages are to be returned, or
- * <code>null</code> if all exported packages are to be returned.
- * If the specified bundle is the system bundle (that is, the bundle
+ * <code>null</code> if all exported packages are to be returned. If
+ * the specified bundle is the system bundle (that is, the bundle
* with id zero), this method returns all the packages known to be
* exported by the system bundle. This will include the package
* specified by the <code>org.osgi.framework.system.packages</code>
@@ -48,6 +47,9 @@
*
* @return An array of exported packages, or <code>null</code> if the
* specified bundle has no exported packages.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+ * not created by the same framework instance that registered this
+ * <code>PackageAdmin</code> service.
*/
public ExportedPackage[] getExportedPackages(Bundle bundle);
@@ -93,8 +95,8 @@
* following steps on a separate thread:
*
* <ol>
- * <li>Compute a graph of bundles starting with the specified bundles. If
- * no bundles are specified, compute a graph of bundles starting with bundle
+ * <li>Compute a graph of bundles starting with the specified bundles. If no
+ * bundles are specified, compute a graph of bundles starting with bundle
* updated or uninstalled since the last call to this method. Add to the
* graph any bundle that is wired to a package that is currently exported by
* a bundle in the graph. The graph is fully constructed when there is no
@@ -105,9 +107,9 @@
* <li>Each bundle in the graph that is in the <code>ACTIVE</code> state
* will be stopped as described in the <code>Bundle.stop</code> method.
*
- * <li>Each bundle in the graph that is in the <code>RESOLVED</code>
- * state is unresolved and thus moved to the <code>INSTALLED</code> state.
- * The effect of this step is that bundles in the graph are no longer
+ * <li>Each bundle in the graph that is in the <code>RESOLVED</code> state
+ * is unresolved and thus moved to the <code>INSTALLED</code> state. The
+ * effect of this step is that bundles in the graph are no longer
* <code>RESOLVED</code>.
*
* <li>Each bundle in the graph that is in the <code>UNINSTALLED</code>
@@ -137,8 +139,11 @@
* removed, or <code>null</code> for all bundles updated or
* uninstalled since the last call to this method.
* @throws SecurityException If the caller does not have
- * <code>AdminPermission[System Bundle,RESOLVE]</code> and the
- * Java runtime environment supports permissions.
+ * <code>AdminPermission[System Bundle,RESOLVE]</code> and the Java
+ * runtime environment supports permissions.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code>s
+ * were not created by the same framework instance that registered
+ * this <code>PackageAdmin</code> service.
*/
public void refreshPackages(Bundle[] bundles);
@@ -155,12 +160,15 @@
* be refreshed, stopped, or started. This method will not return until the
* operation has completed.
*
- * @param bundles The bundles to resolve or <code>null</code> to resolve
- * all unresolved bundles installed in the Framework.
+ * @param bundles The bundles to resolve or <code>null</code> to resolve all
+ * unresolved bundles installed in the Framework.
* @return <code>true</code> if all specified bundles are resolved;
* @throws SecurityException If the caller does not have
- * <code>AdminPermission[System Bundle,RESOLVE]</code> and the
- * Java runtime environment supports permissions.
+ * <code>AdminPermission[System Bundle,RESOLVE]</code> and the Java
+ * runtime environment supports permissions.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code>s
+ * were not created by the same framework instance that registered
+ * this <code>PackageAdmin</code> service.
* @since 1.2
*/
public boolean resolveBundles(Bundle[] bundles);
@@ -203,8 +211,8 @@
/**
* Returns an array of attached fragment bundles for the specified bundle.
- * If the specified bundle is a fragment then <code>null</code> is
- * returned. If no fragments are attached to the specified bundle then
+ * If the specified bundle is a fragment then <code>null</code> is returned.
+ * If no fragments are attached to the specified bundle then
* <code>null</code> is returned.
* <p>
* This method does not attempt to resolve the specified bundle. If the
@@ -215,19 +223,24 @@
* @return An array of fragment bundles or <code>null</code> if the bundle
* does not have any attached fragment bundles or the bundle is not
* resolved.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+ * not created by the same framework instance that registered this
+ * <code>PackageAdmin</code> service.
* @since 1.2
*/
public Bundle[] getFragments(Bundle bundle);
/**
- * Returns an array containing the host bundle to which the specified
- * fragment bundle is attached or <code>null</code> if the specified
- * bundle is not attached to a host or is not a fragment bundle. A fragment
- * may only be attached to a single host bundle.
+ * Returns the host bundles to which the specified fragment bundle is
+ * attached.
*
- * @param bundle The bundle whose host bundle is to be returned.
- * @return An array containing the host bundle or <code>null</code> if the
- * bundle does not have a host bundle.
+ * @param bundle The fragment bundle whose host bundles are to be returned.
+ * @return An array containing the host bundles to which the specified
+ * fragment is attached or <code>null</code> if the specified bundle
+ * is not a fragment or is not attached to any host bundles.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+ * not created by the same framework instance that registered this
+ * <code>PackageAdmin</code> service.
* @since 1.2
*/
public Bundle[] getHosts(Bundle bundle);
@@ -241,7 +254,8 @@
* @param clazz The class object from which to locate the bundle.
* @return The bundle from which the specified class is loaded or
* <code>null</code> if the class was not loaded by a bundle class
- * loader.
+ * loader created by the same framework instance that registered
+ * this <code>PackageAdmin</code> service.
* @since 1.2
*/
public Bundle getBundle(Class clazz);
@@ -272,6 +286,9 @@
*
* @param bundle The bundle for which to return the special type.
* @return The special type of the bundle.
+ * @throws IllegalArgumentException If the specified <code>Bundle</code> was
+ * not created by the same framework instance that registered this
+ * <code>PackageAdmin</code> service.
* @since 1.2
*/
public int getBundleType(Bundle bundle);
diff --git a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java
index 9755e86..b15c5df 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/RequiredBundle.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.packageadmin/src/org/osgi/service/packageadmin/RequiredBundle.java,v 1.11 2006/06/16 16:31:49 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,7 +42,8 @@
* and <code>getRequiringBundles()</code> return <code>null</code>.
*
* @since 1.2
- * @version $Revision: 1.11 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
*/
public interface RequiredBundle {
/**
@@ -72,7 +71,8 @@
*
* @return An array of bundles currently requiring this required bundle, or
* <code>null</code> if this <code>RequiredBundle</code> object
- * has become stale.
+ * has become stale. The array will be empty if no bundles require
+ * this required package.
*/
public Bundle[] getRequiringBundles();
@@ -89,7 +89,7 @@
* Returns <code>true</code> if the bundle associated with this
* <code>RequiredBundle</code> object has been updated or uninstalled.
*
- * @return <code>true</code> if the reqiured bundle has been updated or
+ * @return <code>true</code> if the required bundle has been updated or
* uninstalled, or if the <code>RequiredBundle</code> object has
* become stale; <code>false</code> otherwise.
*/
diff --git a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/package.html b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/package.html
new file mode 100644
index 0000000..9fc9cab
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Package Admin Package Version 1.2.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.packageadmin; version="[1.2,2.0)"
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/service/packageadmin/packageinfo b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/packageinfo
new file mode 100644
index 0000000..ef7df68
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/packageadmin/packageinfo
@@ -0,0 +1 @@
+version 1.2
diff --git a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java
index 0588ae3..d51a9d4 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionAdmin.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.permissionadmin/src/org/osgi/service/permissionadmin/PermissionAdmin.java,v 1.12 2006/06/16 16:31:44 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2001, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2001, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,39 +22,41 @@
* in the OSGi environment.
* <p>
* Access to the Permission Admin service is protected by corresponding
- * <code>ServicePermission</code>. In addition <code>AdminPermission</code> is
- * required to actually set permissions.
+ * <code>ServicePermission</code>. In addition <code>AdminPermission</code>
+ * is required to actually set permissions.
*
* <p>
* Bundle permissions are managed using a permission table. A bundle's location
* serves as the key into this permission table. The value of a table entry is
- * the set of permissions (of type <code>PermissionInfo</code>) granted to the
- * bundle named by the given location. A bundle may have an entry in the
+ * the set of permissions (of type <code>PermissionInfo</code>) granted to
+ * the bundle named by the given location. A bundle may have an entry in the
* permission table prior to being installed in the Framework.
*
* <p>
- * The permissions specified in <code>setDefaultPermissions</code> are used as the
- * default permissions which are granted to all bundles that do not have an
+ * The permissions specified in <code>setDefaultPermissions</code> are used as
+ * the default permissions which are granted to all bundles that do not have an
* entry in the permission table.
*
* <p>
* Any changes to a bundle's permissions in the permission table will take
- * effect no later than when bundle's <code>java.security.ProtectionDomain</code>
- * is next involved in a permission check, and will be made persistent.
+ * effect no later than when bundle's
+ * <code>java.security.ProtectionDomain</code> is next involved in a
+ * permission check, and will be made persistent.
*
* <p>
* Only permission classes on the system classpath or from an exported package
* are considered during a permission check. Additionally, only permission
- * classes that are subclasses of <code>java.security.Permission</code> and define
- * a 2-argument constructor that takes a <i>name </i> string and an <i>actions
- * </i> string can be used.
+ * classes that are subclasses of <code>java.security.Permission</code> and
+ * define a 2-argument constructor that takes a <i>name </i> string and an
+ * <i>actions </i> string can be used.
* <p>
* Permissions implicitly granted by the Framework (for example, a bundle's
* permission to access its persistent storage area) cannot be changed, and are
- * not reflected in the permissions returned by <code>getPermissions</code> and
- * <code>getDefaultPermissions</code>.
+ * not reflected in the permissions returned by <code>getPermissions</code>
+ * and <code>getDefaultPermissions</code>.
*
- * @version $Revision: 1.12 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
*/
public interface PermissionAdmin {
/**
@@ -66,8 +66,8 @@
* returned.
*
* @return The permissions assigned to the bundle with the specified
- * location, or <code>null</code> if that bundle has not been assigned
- * any permissions.
+ * location, or <code>null</code> if that bundle has not been
+ * assigned any permissions.
*/
PermissionInfo[] getPermissions(String location);
@@ -77,10 +77,11 @@
*
* @param location The location of the bundle that will be assigned the
* permissions.
- * @param permissions The permissions to be assigned, or <code>null</code> if
- * the specified location is to be removed from the permission table.
+ * @param permissions The permissions to be assigned, or <code>null</code>
+ * if the specified location is to be removed from the permission
+ * table.
* @throws SecurityException If the caller does not have
- * <code>AllPermission</code>.
+ * <code>AllPermission</code>.
*/
void setPermissions(String location, PermissionInfo[] permissions);
@@ -115,7 +116,7 @@
* @param permissions The default permissions, or <code>null</code> if the
* default permissions are to be removed from the permission table.
* @throws SecurityException If the caller does not have
- * <code>AllPermission</code>.
+ * <code>AllPermission</code>.
*/
void setDefaultPermissions(PermissionInfo[] permissions);
}
diff --git a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java
index e0e72c7..e4bfae7 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/PermissionInfo.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.permissionadmin/src/org/osgi/service/permissionadmin/PermissionInfo.java,v 1.16 2006/06/16 16:31:44 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2001, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2001, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,8 +22,8 @@
* <p>
* This class encapsulates three pieces of information: a Permission <i>type
* </i> (class name), which must be a subclass of
- * <code>java.security.Permission</code>, and the <i>name </i> and <i>actions
- * </i> arguments passed to its constructor.
+ * <code>java.security.Permission</code>, and the <i>name</i> and <i>actions</i>
+ * arguments passed to its constructor.
*
* <p>
* In order for a permission represented by a <code>PermissionInfo</code> to be
@@ -35,22 +33,23 @@
* <code>PermissionInfo</code> may be delayed until the package containing its
* Permission class has been exported by a bundle.
*
- * @version $Revision: 1.16 $
+ * @Immutable
+ * @version $Revision: 6492 $
*/
public class PermissionInfo {
- private String type;
- private String name;
- private String actions;
+ private final String type;
+ private final String name;
+ private final String actions;
/**
- * Constructs a <code>PermissionInfo</code> from the specified type, name, and
- * actions.
+ * Constructs a <code>PermissionInfo</code> from the specified type, name,
+ * and actions.
*
* @param type The fully qualified class name of the permission represented
* by this <code>PermissionInfo</code>. The class must be a subclass
* of <code>java.security.Permission</code> and must define a
- * 2-argument constructor that takes a <i>name </i> string and an
- * <i>actions </i> string.
+ * 2-argument constructor that takes a <i>name</i> string and an
+ * <i>actions</i> string.
*
* @param name The permission name that will be passed as the first argument
* to the constructor of the <code>Permission</code> class identified
@@ -60,10 +59,9 @@
* argument to the constructor of the <code>Permission</code> class
* identified by <code>type</code>.
*
- * @throws java.lang.NullPointerException if <code>type</code> is
- * <code>null</code>.
- * @throws java.lang.IllegalArgumentException if <code>action</code> is not
- * <code>null</code> and <code>name</code> is <code>null</code>.
+ * @throws NullPointerException If <code>type</code> is <code>null</code>.
+ * @throws IllegalArgumentException If <code>action</code> is not
+ * <code>null</code> and <code>name</code> is <code>null</code>.
*/
public PermissionInfo(String type, String name, String actions) {
this.type = type;
@@ -78,15 +76,15 @@
}
/**
- * Constructs a <code>PermissionInfo</code> object from the specified encoded
- * <code>PermissionInfo</code> string. White space in the encoded
+ * Constructs a <code>PermissionInfo</code> object from the specified
+ * encoded <code>PermissionInfo</code> string. White space in the encoded
* <code>PermissionInfo</code> string is ignored.
*
*
* @param encodedPermission The encoded <code>PermissionInfo</code>.
* @see #getEncoded
- * @throws java.lang.IllegalArgumentException If the
- * <code>encodedPermission</code> is not properly formatted.
+ * @throws IllegalArgumentException If the specified
+ * <code>encodedPermission</code> is not properly formatted.
*/
public PermissionInfo(String encodedPermission) {
if (encodedPermission == null) {
@@ -95,20 +93,22 @@
if (encodedPermission.length() == 0) {
throw new IllegalArgumentException("empty encoded permission");
}
+ String parsedType = null;
+ String parsedName = null;
+ String parsedActions = null;
try {
char[] encoded = encodedPermission.toCharArray();
int length = encoded.length;
int pos = 0;
-
+
/* skip whitespace */
while (Character.isWhitespace(encoded[pos])) {
pos++;
}
-
+
/* the first character must be '(' */
if (encoded[pos] != '(') {
- throw new IllegalArgumentException(
- "expecting open parenthesis");
+ throw new IllegalArgumentException("expecting open parenthesis");
}
pos++;
@@ -116,22 +116,23 @@
while (Character.isWhitespace(encoded[pos])) {
pos++;
}
-
+
/* type is not quoted or encoded */
int begin = pos;
- while (!Character.isWhitespace(encoded[pos]) && (encoded[pos] != ')')) {
+ while (!Character.isWhitespace(encoded[pos])
+ && (encoded[pos] != ')')) {
pos++;
}
if (pos == begin || encoded[begin] == '"') {
throw new IllegalArgumentException("expecting type");
}
- this.type = new String(encoded, begin, pos - begin);
-
+ parsedType = new String(encoded, begin, pos - begin);
+
/* skip whitespace */
while (Character.isWhitespace(encoded[pos])) {
pos++;
}
-
+
/* type may be followed by name which is quoted and encoded */
if (encoded[pos] == '"') {
pos++;
@@ -142,7 +143,7 @@
}
pos++;
}
- this.name = unescapeString(encoded, begin, pos);
+ parsedName = unescapeString(encoded, begin, pos);
pos++;
if (Character.isWhitespace(encoded[pos])) {
@@ -150,8 +151,11 @@
while (Character.isWhitespace(encoded[pos])) {
pos++;
}
-
- /* name may be followed by actions which is quoted and encoded */
+
+ /*
+ * name may be followed by actions which is quoted and
+ * encoded
+ */
if (encoded[pos] == '"') {
pos++;
begin = pos;
@@ -161,7 +165,7 @@
}
pos++;
}
- this.actions = unescapeString(encoded, begin, pos);
+ parsedActions = unescapeString(encoded, begin, pos);
pos++;
/* skip whitespace */
@@ -171,7 +175,7 @@
}
}
}
-
+
/* the final character must be ')' */
char c = encoded[pos];
pos++;
@@ -179,12 +183,17 @@
pos++;
}
if ((c != ')') || (pos != length)) {
- throw new IllegalArgumentException("expecting close parenthesis");
+ throw new IllegalArgumentException(
+ "expecting close parenthesis");
}
}
catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException("parsing terminated abruptly");
}
+
+ type = parsedType;
+ name = parsedName;
+ actions = parsedActions;
}
/**
@@ -210,15 +219,17 @@
* (type "name" "actions")
* </pre>
*
- * where <i>name</i> and <i>actions</i> are strings that are encoded for
- * proper parsing. Specifically, the <code>"</code>,<code>\</code>, carriage
- * return, and linefeed characters are escaped using <code>\"</code>,
- * <code>\\</code>,<code>\r</code>, and <code>\n</code>, respectively.
+ * where <i>name</i> and <i>actions</i> are strings that must be encoded for
+ * proper parsing. Specifically, the <code>"</code>,<code>\</code>,
+ * carriage return, and line feed characters must be escaped using
+ * <code>\"</code>, <code>\\</code>,<code>\r</code>, and
+ * <code>\n</code>, respectively.
*
* <p>
- * The encoded string contains no leading or trailing whitespace
- * characters. A single space character is used between <i>type</i> and
- * "<i>name</i>" and between "<i>name</i>" and "<i>actions</i>".
+ * The encoded string contains no leading or trailing whitespace characters.
+ * A single space character is used between <i>type</i> and
+ * "<i>name</i>" and between "<i>name</i>" and
+ * "<i>actions</i>".
*
* @return The string encoding of this <code>PermissionInfo</code>.
*/
@@ -244,9 +255,9 @@
}
/**
- * Returns the string representation of this <code>PermissionInfo</code>. The
- * string is created by calling the <code>getEncoded</code> method on this
- * <code>PermissionInfo</code>.
+ * Returns the string representation of this <code>PermissionInfo</code>.
+ * The string is created by calling the <code>getEncoded</code> method on
+ * this <code>PermissionInfo</code>.
*
* @return The string representation of this <code>PermissionInfo</code>.
*/
@@ -270,8 +281,8 @@
* <code>PermissionInfo</code>.
*
* @return The name of the permission represented by this
- * <code>PermissionInfo</code>, or <code>null</code> if the permission
- * does not have a name.
+ * <code>PermissionInfo</code>, or <code>null</code> if the
+ * permission does not have a name.
*/
public final String getName() {
return name;
@@ -282,8 +293,8 @@
* <code>PermissionInfo</code>.
*
* @return The actions of the permission represented by this
- * <code>PermissionInfo</code>, or <code>null</code> if the permission
- * does not have any actions associated with it.
+ * <code>PermissionInfo</code>, or <code>null</code> if the
+ * permission does not have any actions associated with it.
*/
public final String getActions() {
return actions;
@@ -297,9 +308,10 @@
*
* @param obj The object to test for equality with this
* <code>PermissionInfo</code> object.
- * @return <code>true</code> if <code>obj</code> is a <code>PermissionInfo</code>,
- * and has the same type, name and actions as this
- * <code>PermissionInfo</code> object; <code>false</code> otherwise.
+ * @return <code>true</code> if <code>obj</code> is a
+ * <code>PermissionInfo</code>, and has the same type, name and
+ * actions as this <code>PermissionInfo</code> object;
+ * <code>false</code> otherwise.
*/
public boolean equals(Object obj) {
if (obj == this) {
@@ -315,8 +327,7 @@
}
if (name != null) {
if (actions != null) {
- return name.equals(other.name) && actions
- .equals(other.actions);
+ return name.equals(other.name) && actions.equals(other.actions);
}
else {
return name.equals(other.name);
@@ -333,14 +344,14 @@
* @return A hash code value for this object.
*/
public int hashCode() {
- int hash = type.hashCode();
+ int h = 31 * 17 + type.hashCode();
if (name != null) {
- hash ^= name.hashCode();
+ h = 31 * h + name.hashCode();
if (actions != null) {
- hash ^= actions.hashCode();
+ h = 31 * h + actions.hashCode();
}
}
- return hash;
+ return h;
}
/**
@@ -400,7 +411,7 @@
}
output.append(c);
}
-
+
return output.toString();
}
}
diff --git a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/package.html b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/package.html
new file mode 100644
index 0000000..396264c
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Permission Admin Package Version 1.2.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.permissionadmin; version="[1.2,2.0)"
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/packageinfo b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/packageinfo
new file mode 100644
index 0000000..ef7df68
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/permissionadmin/packageinfo
@@ -0,0 +1 @@
+version 1.2
diff --git a/org.osgi.core/src/main/java/org/osgi/service/startlevel/StartLevel.java b/org.osgi.core/src/main/java/org/osgi/service/startlevel/StartLevel.java
index 97e79e9..8a69b03 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/startlevel/StartLevel.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/startlevel/StartLevel.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.startlevel/src/org/osgi/service/startlevel/StartLevel.java,v 1.19 2007/02/09 03:20:24 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2002, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 2009). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -68,7 +66,8 @@
* The StartLevel service can be used by management bundles to alter the active
* start level of the framework.
*
- * @version $Revision: 1.19 $
+ * @ThreadSafe
+ * @version $Revision: 6747 $
*/
public interface StartLevel {
/**
@@ -152,7 +151,9 @@
* @param bundle The target bundle.
* @return The start level value of the specified Bundle.
* @throws java.lang.IllegalArgumentException If the specified bundle has
- * been uninstalled.
+ * been uninstalled or if the specified bundle was not created by
+ * the same framework instance that registered this
+ * <code>StartLevel</code> service.
*/
public int getBundleStartLevel(Bundle bundle);
@@ -183,11 +184,13 @@
* @param bundle The target bundle.
* @param startlevel The new start level for the specified Bundle.
* @throws IllegalArgumentException If the specified bundle has been
- * uninstalled or if the specified start level is less than or equal
- * to zero, or the specified bundle is the system bundle.
+ * uninstalled, or if the specified start level is less than or
+ * equal to zero, or if the specified bundle is the system bundle,
+ * or if the specified bundle was not created by the same framework
+ * instance that registered this <code>StartLevel</code> service.
* @throws SecurityException If the caller does not have
- * <code>AdminPermission[bundle,EXECUTE]</code> and the Java
- * runtime environment supports permissions.
+ * <code>AdminPermission[bundle,EXECUTE]</code> and the Java runtime
+ * environment supports permissions.
*/
public void setBundleStartLevel(Bundle bundle, int startlevel);
@@ -218,7 +221,7 @@
* been called to assign a different initial bundle start level value.
*
* <p>
- * Thie method does not change the start level values of installed bundles.
+ * This method does not change the start level values of installed bundles.
*
* @param startlevel The initial start level for newly installed bundles.
* @throws IllegalArgumentException If the specified start level is less
@@ -241,7 +244,9 @@
* indicates the bundle is to be started. <code>false</code>
* otherwise.
* @throws java.lang.IllegalArgumentException If the specified bundle has
- * been uninstalled.
+ * been uninstalled or if the specified bundle was not created by
+ * the same framework instance that registered this
+ * <code>StartLevel</code> service.
* @see Bundle#START_TRANSIENT
*/
public boolean isBundlePersistentlyStarted(Bundle bundle);
@@ -254,11 +259,13 @@
* activation policy is to be used when the bundle is started.
*
* @param bundle The bundle whose autostart setting is to be examined.
- * @return <code>true</code> if the bundle’s autostart setting indicates
- * the activation policy declared in the manifest must be used.
+ * @return <code>true</code> if the bundle's autostart setting indicates the
+ * activation policy declared in the manifest must be used.
* <code>false</code> if the bundle must be eagerly activated.
* @throws java.lang.IllegalArgumentException If the specified bundle has
- * been uninstalled.
+ * been uninstalled or if the specified bundle was not created by
+ * the same framework instance that registered this
+ * <code>StartLevel</code> service.
* @since 1.1
* @see Bundle#START_ACTIVATION_POLICY
*/
diff --git a/org.osgi.core/src/main/java/org/osgi/service/startlevel/package.html b/org.osgi.core/src/main/java/org/osgi/service/startlevel/package.html
new file mode 100644
index 0000000..4c27532
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/startlevel/package.html
@@ -0,0 +1,11 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Start Level Package Version 1.1.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.startlevel; version="[1.1,2.0)"
+</pre>
+</BODY>
+
diff --git a/org.osgi.core/src/main/java/org/osgi/service/startlevel/packageinfo b/org.osgi.core/src/main/java/org/osgi/service/startlevel/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/startlevel/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/AbstractURLStreamHandlerService.java b/org.osgi.core/src/main/java/org/osgi/service/url/AbstractURLStreamHandlerService.java
index b8e80dc..1ad37a2 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/url/AbstractURLStreamHandlerService.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/AbstractURLStreamHandlerService.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.url/src/org/osgi/service/url/AbstractURLStreamHandlerService.java,v 1.8 2006/06/16 16:31:31 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,15 +19,16 @@
import java.net.*;
/**
- * Abstract implementation of the <code>URLStreamHandlerService</code> interface.
- * All the methods simply invoke the corresponding methods on
- * <code>java.net.URLStreamHandler</code> except for <code>parseURL</code> and
- * <code>setURL</code>, which use the <code>URLStreamHandlerSetter</code>
+ * Abstract implementation of the <code>URLStreamHandlerService</code>
+ * interface. All the methods simply invoke the corresponding methods on
+ * <code>java.net.URLStreamHandler</code> except for <code>parseURL</code>
+ * and <code>setURL</code>, which use the <code>URLStreamHandlerSetter</code>
* parameter. Subclasses of this abstract class should not need to override the
* <code>setURL</code> and <code>parseURL(URLStreamHandlerSetter,...)</code>
* methods.
*
- * @version $Revision: 1.8 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
*/
public abstract class AbstractURLStreamHandlerService extends URLStreamHandler
implements URLStreamHandlerService {
@@ -43,7 +42,7 @@
* The <code>URLStreamHandlerSetter</code> object passed to the parseURL
* method.
*/
- protected URLStreamHandlerSetter realHandler;
+ protected volatile URLStreamHandlerSetter realHandler;
/**
* Parse a URL using the <code>URLStreamHandlerSetter</code> object. This
@@ -51,8 +50,8 @@
* <code>URLStreamHandlerSetter</code> object and then calls
* <code>parseURL(URL,String,int,int)</code>.
*
- * @param realHandler The object on which the <code>setURL</code> method must
- * be invoked for the specified URL.
+ * @param realHandler The object on which the <code>setURL</code> method
+ * must be invoked for the specified URL.
* @see "java.net.URLStreamHandler.parseURL"
*/
public void parseURL(URLStreamHandlerSetter realHandler, URL u,
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/URLConstants.java b/org.osgi.core/src/main/java/org/osgi/service/url/URLConstants.java
index 71b067e..ae95305 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/url/URLConstants.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/URLConstants.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.url/src/org/osgi/service/url/URLConstants.java,v 1.10 2006/12/01 06:38:45 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,23 +22,23 @@
* services.
*
* <p>
- * The values associated with these keys are of type <code>java.lang.String[]</code>
- * or <code>java.lang.String</code>,
- * unless otherwise indicated.
+ * The values associated with these keys are of type
+ * <code>java.lang.String[]</code> or <code>java.lang.String</code>, unless
+ * otherwise indicated.
*
- * @version $Revision: 1.10 $
+ * @version $Revision: 5673 $
*/
public interface URLConstants {
/**
* Service property naming the protocols serviced by a
- * URLStreamHandlerService. The property's value is
- * a protocol name or an array of protocol names.
+ * URLStreamHandlerService. The property's value is a protocol name or an
+ * array of protocol names.
*/
public static final String URL_HANDLER_PROTOCOL = "url.handler.protocol";
/**
* Service property naming the MIME types serviced by a
- * java.net.ContentHandler. The property's value is a
- * MIME type or an array of MIME types.
+ * java.net.ContentHandler. The property's value is a MIME type or an array
+ * of MIME types.
*/
public static final String URL_CONTENT_MIMETYPE = "url.content.mimetype";
}
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerService.java b/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerService.java
index c5cb303..b1ff7d8 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerService.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerService.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.url/src/org/osgi/service/url/URLStreamHandlerService.java,v 1.9 2006/07/11 00:53:59 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,17 +23,19 @@
* <code>java.net.URLStreamHandler</code> methods.
* <p>
* The important differences between this interface and the
- * <code>URLStreamHandler</code> class are that the <code>setURL</code> method is
- * absent and the <code>parseURL</code> method takes a
+ * <code>URLStreamHandler</code> class are that the <code>setURL</code>
+ * method is absent and the <code>parseURL</code> method takes a
* {@link URLStreamHandlerSetter} object as the first argument. Classes
* implementing this interface must call the <code>setURL</code> method on the
- * <code>URLStreamHandlerSetter</code> object received in the <code>parseURL</code>
- * method instead of <code>URLStreamHandler.setURL</code> to avoid a
+ * <code>URLStreamHandlerSetter</code> object received in the
+ * <code>parseURL</code> method instead of
+ * <code>URLStreamHandler.setURL</code> to avoid a
* <code>SecurityException</code>.
*
* @see AbstractURLStreamHandlerService
*
- * @version $Revision: 1.9 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
*/
public interface URLStreamHandlerService {
/**
@@ -45,11 +45,11 @@
/**
* Parse a URL. This method is called by the <code>URLStreamHandler</code>
- * proxy, instead of <code>java.net.URLStreamHandler.parseURL</code>, passing
- * a <code>URLStreamHandlerSetter</code> object.
+ * proxy, instead of <code>java.net.URLStreamHandler.parseURL</code>,
+ * passing a <code>URLStreamHandlerSetter</code> object.
*
- * @param realHandler The object on which <code>setURL</code> must be invoked
- * for this URL.
+ * @param realHandler The object on which <code>setURL</code> must be
+ * invoked for this URL.
* @see "java.net.URLStreamHandler.parseURL"
*/
public void parseURL(URLStreamHandlerSetter realHandler, URL u,
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerSetter.java b/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerSetter.java
index fedd59f..36bdce8 100644
--- a/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerSetter.java
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/URLStreamHandlerSetter.java
@@ -1,7 +1,5 @@
/*
- * $Header: /cvshome/build/org.osgi.service.url/src/org/osgi/service/url/URLStreamHandlerSetter.java,v 1.9 2006/07/11 00:53:59 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 2008). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,16 +20,19 @@
/**
* Interface used by <code>URLStreamHandlerService</code> objects to call the
- * <code>setURL</code> method on the proxy <code>URLStreamHandler</code> object.
+ * <code>setURL</code> method on the proxy <code>URLStreamHandler</code>
+ * object.
*
* <p>
* Objects of this type are passed to the
- * {@link URLStreamHandlerService#parseURL} method. Invoking the <code>setURL</code>
- * method on the <code>URLStreamHandlerSetter</code> object will invoke the
- * <code>setURL</code> method on the proxy <code>URLStreamHandler</code> object that
- * is actually registered with <code>java.net.URL</code> for the protocol.
+ * {@link URLStreamHandlerService#parseURL} method. Invoking the
+ * <code>setURL</code> method on the <code>URLStreamHandlerSetter</code>
+ * object will invoke the <code>setURL</code> method on the proxy
+ * <code>URLStreamHandler</code> object that is actually registered with
+ * <code>java.net.URL</code> for the protocol.
*
- * @version $Revision: 1.9 $
+ * @ThreadSafe
+ * @version $Revision: 5673 $
*/
public interface URLStreamHandlerSetter {
/**
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/package.html b/org.osgi.core/src/main/java/org/osgi/service/url/package.html
new file mode 100644
index 0000000..4ed4d6e
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/package.html
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>URL Stream and Content Handlers Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.url; version="[1.0,2.0)"
+</pre>
+</BODY>
diff --git a/org.osgi.core/src/main/java/org/osgi/service/url/packageinfo b/org.osgi.core/src/main/java/org/osgi/service/url/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/org.osgi.core/src/main/java/org/osgi/service/url/packageinfo
@@ -0,0 +1 @@
+version 1.0