M2 module for R4 Compendium ASL'd sources (FELIX-49)
o  OSGi R4 Compendium sources with ASL headers
o  Initial POM

git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@389891 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.osgi.compendium/pom.xml b/org.osgi.compendium/pom.xml
new file mode 100644
index 0000000..01d7a9d
--- /dev/null
+++ b/org.osgi.compendium/pom.xml
@@ -0,0 +1,55 @@
+<project>
+  <parent>
+    <groupId>org.apache.felix</groupId>
+    <artifactId>felix</artifactId>
+    <version>0.8.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <packaging>osgi-bundle</packaging>
+  <artifactId>org.osgi.compendium</artifactId>
+  <name>OSGi R4 Compendium Bundle</name>
+  <dependencies>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>org.osgi</artifactId>
+      <version>${pom.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet</artifactId>
+      <version>2.1</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>javax.microedition</groupId>
+      <artifactId>javax.microedition</artifactId>
+      <version>1.0.4</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix.plugins</groupId>
+        <artifactId>maven-osgi-plugin</artifactId>
+        <version>${pom.version}</version>
+        <extensions>true</extensions>
+        <configuration>
+          <osgiManifest>
+            <bundleName>osgi.compendium</bundleName>
+            <bundleVendor>OSGi Alliance</bundleVendor>
+            <!--<bundleVersion>4</bundleVersion>-->
+            <bundleSymbolicName>osgi.compendium</bundleSymbolicName>
+            <bundleDescription>OSGi Service Platform Release 4 Compendium Interfaces and Classes.</bundleDescription>
+            <!--<bundleCopyright>Copyright (c) OSGi Alliance (2000, 2005). All Rights Reserved.</bundleCopyright>-->
+            <bundleCategory>osgi</bundleCategory>
+            <!--<bundleDocUrl>http://www.osgi.org/</bundleDocUrl>-->
+            <exportPackage>org.osgi.service.cm ;specification-version="1.2",org.osgi.service.component ;specification-version="1.0",org.osgi.service.device ;specification-version="1.1",org.osgi.service.event ;specification-version="1.0.1",org.osgi.service.http ;specification-version="1.2",org.osgi.service.io ;specification-version="1.0",org.osgi.service.log ;specification-version="1.3",org.osgi.service.metatype ;specification-version="1.1",org.osgi.service.prefs ;specification-version="1.1",org.osgi.service.provisioning ;specification-version="1.1",org.osgi.service.upnp ;specification-version="1.1",org.osgi.service.useradmin ;specification-version="1.1",org.osgi.service.wireadmin ;specification-version="1.0",org.osgi.util.measurement ;specification-version="1.0",org.osgi.util.position ;specification-version="1.0",org.osgi.util.tracker ;specification-version="1.3.1",org.osgi.util.xml ;specification-version="1.0"</exportPackage>
+            <dynamicImportPackage>*</dynamicImportPackage>
+          </osgiManifest>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/cm/Configuration.java b/org.osgi.compendium/src/main/java/org/osgi/service/cm/Configuration.java
new file mode 100644
index 0000000..a4d54cd
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/cm/Configuration.java
@@ -0,0 +1,227 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/Configuration.java,v 1.16 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.cm;
+
+import java.io.IOException;
+import java.util.Dictionary;
+
+/**
+ * The configuration information for a <code>ManagedService</code> or
+ * <code>ManagedServiceFactory</code> object.
+ * 
+ * The Configuration Admin service uses this interface to represent the
+ * configuration information for a <code>ManagedService</code> or for a
+ * service instance of a <code>ManagedServiceFactory</code>.
+ * 
+ * <p>
+ * A <code>Configuration</code> object contains a configuration dictionary and
+ * allows the properties to be updated via this object. Bundles wishing to
+ * receive configuration dictionaries do not need to use this class - they
+ * register a <code>ManagedService</code> or
+ * <code>ManagedServiceFactory</code>. Only administrative bundles, and
+ * bundles wishing to update their own configurations need to use this class.
+ * 
+ * <p>
+ * The properties handled in this configuration have case insensitive
+ * <code>String</code> objects as keys. However, case is preserved from the
+ * last set key/value.
+ * <p>
+ * A configuration can be <i>bound </i> to a bundle location (
+ * <code>Bundle.getLocation()</code>). The purpose of binding a
+ * <code>Configuration</code> object to a location is to make it impossible
+ * for another bundle to forge a PID that would match this configuration. When a
+ * configuration is bound to a specific location, and a bundle with a different
+ * location registers a corresponding <code>ManagedService</code> object or
+ * <code>ManagedServiceFactory</code> object, then the configuration is not
+ * passed to the updated method of that object.
+ * 
+ * <p>
+ * If a configuration's location is <code>null</code>, it is not yet bound to
+ * a location. It will become bound to the location of the first bundle that
+ * registers a <code>ManagedService</code> or
+ * <code>ManagedServiceFactory</code> object with the corresponding PID.
+ * <p>
+ * The same <code>Configuration</code> object is used for configuring both a
+ * Managed Service Factory and a Managed Service. When it is important to
+ * differentiate between these two the term "factory configuration" is used.
+ * 
+ * @version $Revision: 1.16 $
+ */
+public interface Configuration {
+	/**
+	 * Get the PID for this <code>Configuration</code> object.
+	 * 
+	 * @return the PID for this <code>Configuration</code> object.
+	 * @throws IllegalStateException if this configuration has been deleted
+	 */
+	public String getPid();
+
+	/**
+	 * Return the properties of this <code>Configuration</code> object.
+	 * 
+	 * The <code>Dictionary</code> object returned is a private copy for the
+	 * caller and may be changed without influencing the stored configuration.
+	 * The keys in the returned dictionary are case insensitive and are always
+	 * of type <code>String</code>.
+	 * 
+	 * <p>
+	 * If called just after the configuration is created and before update has
+	 * been called, this method returns <code>null</code>.
+	 * 
+	 * @return A private copy of the properties for the caller or
+	 *         <code>null</code>. These properties must not contain the
+	 *         "service.bundleLocation" property. The value of this property may
+	 *         be obtained from the <code>getBundleLocation</code> method.
+	 * @throws IllegalStateException if this configuration has been deleted
+	 */
+	public Dictionary getProperties();
+
+	/**
+	 * Update the properties of this <code>Configuration</code> object.
+	 * 
+	 * Stores the properties in persistent storage after adding or overwriting
+	 * the following properties:
+	 * <ul>
+	 * <li>"service.pid" : is set to be the PID of this configuration.</li>
+	 * <li>"service.factoryPid" : if this is a factory configuration it is set
+	 * to the factory PID else it is not set.</li>
+	 * </ul>
+	 * These system properties are all of type <code>String</code>.
+	 * 
+	 * <p>
+	 * If the corresponding Managed Service/Managed Service Factory is
+	 * registered, its updated method must be called asynchronously. Else, this
+	 * callback is delayed until aforementioned registration occurs.
+	 * 
+	 * <p>
+	 * Also intiates an asynchronous call to all
+	 * <code>ConfigurationListener</code>s with a
+	 * <code>ConfigurationEvent.CM_UPDATED</code> event.
+	 * 
+	 * @param properties the new set of properties for this configuration
+	 * @throws IOException if update cannot be made persistent
+	 * @throws IllegalArgumentException if the <code>Dictionary</code> object
+	 *         contains invalid configuration types or contains case variants of
+	 *         the same key name.
+	 * @throws IllegalStateException if this configuration has been deleted
+	 */
+	public void update(Dictionary properties) throws IOException;
+
+	/**
+	 * Delete this <code>Configuration</code> object.
+	 * 
+	 * Removes this configuration object from the persistent store. Notify
+	 * asynchronously the corresponding Managed Service or Managed Service
+	 * Factory. A <code>ManagedService</code> object is notified by a call to
+	 * its <code>updated</code> method with a <code>null</code> properties
+	 * argument. A <code>ManagedServiceFactory</code> object is notified by a
+	 * call to its <code>deleted</code> method.
+	 * 
+	 * <p>
+	 * Also intiates an asynchronous call to all
+	 * <code>ConfigurationListener</code>s with a
+	 * <code>ConfigurationEvent.CM_DELETED</code> event.
+	 * 
+	 * @throws IOException If delete fails
+	 * @throws IllegalStateException if this configuration has been deleted
+	 */
+	public void delete() throws IOException;
+
+	/**
+	 * For a factory configuration return the PID of the corresponding Managed
+	 * Service Factory, else return <code>null</code>.
+	 * 
+	 * @return factory PID or <code>null</code>
+	 * @throws IllegalStateException if this configuration has been deleted
+	 */
+	public String getFactoryPid();
+
+	/**
+	 * Update the <code>Configuration</code> object with the current
+	 * properties.
+	 * 
+	 * Initiate the <code>updated</code> callback to the Managed Service or
+	 * Managed Service Factory with the current properties asynchronously.
+	 * 
+	 * <p>
+	 * This is the only way for a bundle that uses a Configuration Plugin
+	 * service to initate a callback. For example, when that bundle detects a
+	 * change that requires an update of the Managed Service or Managed Service
+	 * Factory via its <code>ConfigurationPlugin</code> object.
+	 * 
+	 * @see ConfigurationPlugin
+	 * @throws IOException if update cannot access the properties in persistent
+	 *         storage
+	 * @throws IllegalStateException if this configuration has been deleted
+	 */
+	public void update() throws IOException;
+
+	/**
+	 * Bind this <code>Configuration</code> object to the specified bundle
+	 * location.
+	 * 
+	 * If the bundleLocation parameter is <code>null</code> then the
+	 * <code>Configuration</code> object will not be bound to a location. It
+	 * will be set to the bundle's location before the first time a Managed
+	 * Service/Managed Service Factory receives this <code>Configuration</code>
+	 * object via the updated method and before any plugins are called. The
+	 * bundle location will be set persistently.
+	 * 
+	 * @param bundleLocation a bundle location or <code>null</code>
+	 * @throws IllegalStateException If this configuration has been deleted.
+	 * @throws SecurityException If the caller does not have
+	 *         <code>ConfigurationPermission[*,CONFIGURE]</code>.
+	 */
+	public void setBundleLocation(String bundleLocation);
+
+	/**
+	 * Get the bundle location.
+	 * 
+	 * Returns the bundle location to which this configuration is bound, or
+	 * <code>null</code> if it is not yet bound to a bundle location.
+	 * 
+	 * @return location to which this configuration is bound, or
+	 *         <code>null</code>.
+	 * @throws IllegalStateException If this <code>Configuration</code> object
+	 *         has been deleted.
+	 * @throws SecurityException If the caller does not have
+	 *         <code>ConfigurationPermission[*,CONFIGURE]</code>.
+	 */
+	public String getBundleLocation();
+
+	/**
+	 * Equality is defined to have equal PIDs
+	 * 
+	 * Two Configuration objects are equal when their PIDs are equal.
+	 * 
+	 * @param other <code>Configuration</code> object to compare against
+	 * @return <code>true</code> if equal, <code>false</code> if not a
+	 *         <code>Configuration</code> object or one with a different PID.
+	 */
+	public boolean equals(Object other);
+
+	/**
+	 * Hash code is based on PID.
+	 * 
+	 * The hashcode for two Configuration objects must be the same when the
+	 * Configuration PID's are the same.
+	 * 
+	 * @return hash code for this Configuration object
+	 */
+	public int hashCode();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java
new file mode 100644
index 0000000..f0f7836
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java
@@ -0,0 +1,256 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationAdmin.java,v 1.14 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.cm;
+
+import java.io.IOException;
+import java.util.Dictionary;
+
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * Service for administering configuration data.
+ * 
+ * <p>
+ * The main purpose of this interface is to store bundle configuration data
+ * persistently. This information is represented in <code>Configuration</code>
+ * objects. The actual configuration data is a <code>Dictionary</code> of
+ * properties inside a <code>Configuration</code> object.
+ * 
+ * <p>
+ * There are two principally different ways to manage configurations. First
+ * there is the concept of a Managed Service, where configuration data is
+ * uniquely associated with an object registered with the service registry.
+ * 
+ * <p>
+ * Next, there is the concept of a factory where the Configuration Admin service
+ * will maintain 0 or more <code>Configuration</code> objects for a Managed
+ * Service Factory that is registered with the Framework.
+ * 
+ * <p>
+ * The first concept is intended for configuration data about "things/services"
+ * whose existence is defined externally, e.g. a specific printer. Factories are
+ * intended for "things/services" that can be created any number of times, e.g.
+ * a configuration for a DHCP server for different networks.
+ * 
+ * <p>
+ * Bundles that require configuration should register a Managed Service or a
+ * Managed Service Factory in the service registry. A registration property
+ * named <code>service.pid</code> (persistent identifier or PID) must be used
+ * to identify this Managed Service or Managed Service Factory to the
+ * Configuration Admin service.
+ * 
+ * <p>
+ * When the ConfigurationAdmin detects the registration of a Managed Service, it
+ * checks its persistent storage for a configuration object whose PID matches
+ * the PID registration property (<code>service.pid</code>) of the Managed
+ * Service. If found, it calls {@link ManagedService#updated}method with the
+ * new properties. The implementation of a Configuration Admin service must run
+ * these call-backs asynchronously to allow proper synchronization.
+ * 
+ * <p>
+ * When the Configuration Admin service detects a Managed Service Factory
+ * registration, it checks its storage for configuration objects whose
+ * <code>factoryPid</code> matches the PID of the Managed Service Factory. For
+ * each such <code>Configuration</code> objects, it calls the
+ * <code>ManagedServiceFactory.updated</code> method asynchronously with the
+ * new properties. The calls to the <code>updated</code> method of a
+ * <code>ManagedServiceFactory</code> must be executed sequentially and not
+ * overlap in time.
+ * 
+ * <p>
+ * In general, bundles having permission to use the Configuration Admin service
+ * can only access and modify their own configuration information. Accessing or
+ * modifying the configuration of another bundle requires
+ * <code>ConfigurationPermission[*,CONFIGURE]</code>.
+ * 
+ * <p>
+ * <code>Configuration</code> objects can be <i>bound </i> to a specified
+ * bundle location. In this case, if a matching Managed Service or Managed
+ * Service Factory is registered by a bundle with a different location, then the
+ * Configuration Admin service must not do the normal callback, and it should
+ * log an error. In the case where a <code>Configuration</code> object is not
+ * bound, its location field is <code>null</code>, the Configuration Admin
+ * service will bind it to the location of the bundle that registers the first
+ * Managed Service or Managed Service Factory that has a corresponding PID
+ * property. When a <code>Configuration</code> object is bound to a bundle
+ * location in this manner, the Confguration Admin service must detect if the
+ * bundle corresponding to the location is uninstalled. If this occurs, the
+ * <code>Configuration</code> object is unbound, that is its location field is
+ * set back to <code>null</code>.
+ * 
+ * <p>
+ * The method descriptions of this class refer to a concept of "the calling
+ * bundle". This is a loose way of referring to the bundle which obtained the
+ * Configuration Admin service from the service registry. Implementations of
+ * <code>ConfigurationAdmin</code> must use a
+ * {@link org.osgi.framework.ServiceFactory}to support this concept.
+ * 
+ * @version $Revision: 1.14 $
+ */
+public interface ConfigurationAdmin {
+	/**
+	 * Service property naming the Factory PID in the configuration dictionary.
+	 * The property's value is of type <code>String</code>.
+	 * 
+	 * @since 1.1
+	 */
+	public final static String	SERVICE_FACTORYPID		= "service.factoryPid";
+	/**
+	 * Service property naming the location of the bundle that is associated
+	 * with a a <code>Configuration</code> object. This property can be
+	 * searched for but must not appear in the configuration dictionary for
+	 * security reason. The property's value is of type <code>String</code>.
+	 * 
+	 * @since 1.1
+	 */
+	public final static String	SERVICE_BUNDLELOCATION	= "service.bundleLocation";
+
+	/**
+	 * Create a new factory <code>Configuration</code> object with a new PID.
+	 * 
+	 * The properties of the new <code>Configuration</code> object are
+	 * <code>null</code> until the first time that its
+	 * {@link Configuration#update(Dictionary)}method is called.
+	 * 
+	 * <p>
+	 * It is not required that the <code>factoryPid</code> maps to a
+	 * registered Managed Service Factory.
+	 * <p>
+	 * The <code>Configuration</code> object is bound to the location of the
+	 * calling bundle.
+	 * 
+	 * @param factoryPid PID of factory (not <code>null</code>).
+	 * @return A new <code>Configuration</code> object.
+	 * @throws IOException if access to persistent storage fails.
+	 * @throws SecurityException if caller does not have <code>ConfigurationPermission[*,CONFIGURE]</code> and <code>factoryPid</code> is bound to another bundle.
+	 */
+	public Configuration createFactoryConfiguration(String factoryPid)
+			throws IOException;
+
+	/**
+	 * Create a new factory <code>Configuration</code> object with a new PID.
+	 * 
+	 * The properties of the new <code>Configuration</code> object are
+	 * <code>null</code> until the first time that its
+	 * {@link Configuration#update(Dictionary)}method is called.
+	 * 
+	 * <p>
+	 * It is not required that the <code>factoryPid</code> maps to a
+	 * registered Managed Service Factory.
+	 * 
+	 * <p>
+	 * The <code>Configuration</code> is bound to the location specified. If
+	 * this location is <code>null</code> it will be bound to the location of
+	 * the first bundle that registers a Managed Service Factory with a
+	 * corresponding PID.
+	 * 
+	 * @param factoryPid PID of factory (not <code>null</code>).
+	 * @param location A bundle location string, or <code>null</code>.
+	 * @return a new <code>Configuration</code> object.
+	 * @throws IOException if access to persistent storage fails.
+	 * @throws SecurityException if caller does not have <code>ConfigurationPermission[*,CONFIGURE]</code>.
+	 */
+	public Configuration createFactoryConfiguration(String factoryPid, String location)
+			throws IOException;
+
+	/**
+	 * Get an existing <code>Configuration</code> object from the persistent
+	 * store, or create a new <code>Configuration</code> object.
+	 * 
+	 * <p>
+	 * If a <code>Configuration</code> with this PID already exists in
+	 * Configuration Admin service return it. The location parameter is ignored
+	 * in this case.
+	 * 
+	 * <p>
+	 * Else, return a new <code>Configuration</code> object. This new object
+	 * is bound to the location and the properties are set to <code>null</code>.
+	 * If the location parameter is <code>null</code>, it will be set when a
+	 * Managed Service with the corresponding PID is registered for the first
+	 * time.
+	 * 
+	 * @param pid Persistent identifier.
+	 * @param location The bundle location string, or <code>null</code>.
+	 * @return An existing or new <code>Configuration</code> object.
+	 * @throws IOException if access to persistent storage fails.
+	 * @throws SecurityException if the caller does not have <code>ConfigurationPermission[*,CONFIGURE]</code>.
+	 */
+	public Configuration getConfiguration(String pid, String location)
+			throws IOException;
+
+	/**
+	 * Get an existing or new <code>Configuration</code> object from the
+	 * persistent store.
+	 * 
+	 * If the <code>Configuration</code> object for this PID does not exist,
+	 * create a new <code>Configuration</code> object for that PID, where
+	 * properties are <code>null</code>. Bind its location to the calling
+	 * bundle's location.
+	 * 
+	 * <p>
+	 * Otherwise, if the location of the existing <code>Configuration</code> object
+	 * is <code>null</code>, set it to the calling bundle's location.
+	 * 
+	 * @param pid persistent identifier.
+	 * @return an existing or new <code>Configuration</code> matching the PID.
+	 * @throws IOException if access to persistent storage fails.
+	 * @throws SecurityException if the <code>Configuration</code> object is bound to a location different from that of the calling bundle and it has no <code>ConfigurationPermission[*,CONFIGURE]</code>.
+	 */
+	public Configuration getConfiguration(String pid) throws IOException;
+
+	/**
+	 * List the current <code>Configuration</code> objects which match the
+	 * filter.
+	 * 
+	 * <p>
+	 * Only <code>Configuration</code> objects with non- <code>null</code>
+	 * properties are considered current. That is,
+	 * <code>Configuration.getProperties()</code> is guaranteed not to return
+	 * <code>null</code> for each of the returned <code>Configuration</code>
+	 * objects.
+	 * 
+	 * <p>
+	 * Normally only <code>Configuration</code> objects that are bound to the
+	 * location of the calling bundle are returned, or all if the caller has 
+	 * <code>ConfigurationPermission[*,CONFIGURE]</code>.
+	 * 
+	 * <p>
+	 * The syntax of the filter string is as defined in the <code>Filter</code>
+	 * class. The filter can test any configuration parameters including the
+	 * following system properties:
+	 * <ul>
+	 * <li><code>service.pid</code>-<code>String</code>- the PID under
+	 * which this is registered</li>
+	 * <li><code>service.factoryPid</code>-<code>String</code>- the
+	 * factory if applicable</li>
+	 * <li><code>service.bundleLocation</code>-<code>String</code>- the
+	 * bundle location</li>
+	 * </ul>
+	 * The filter can also be <code>null</code>, meaning that all
+	 * <code>Configuration</code> objects should be returned.
+	 * 
+	 * @param filter a <code>Filter</code> object, or <code>null</code> to
+	 *        retrieve all <code>Configuration</code> objects.
+	 * @return all matching <code>Configuration</code> objects, or
+	 *         <code>null</code> if there aren't any
+	 * @throws IOException if access to persistent storage fails
+	 * @throws InvalidSyntaxException if the filter string is invalid
+	 */
+	public Configuration[] listConfigurations(String filter) throws IOException,
+			InvalidSyntaxException;
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationEvent.java b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationEvent.java
new file mode 100644
index 0000000..28ef9e4
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationEvent.java
@@ -0,0 +1,167 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationEvent.java,v 1.8 2006/03/14 01:21:09 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2004, 2005). 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.cm;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A Configuration Event.
+ * 
+ * <p>
+ * <code>ConfigurationEvent</code> objects are delivered to all registered
+ * <code>ConfigurationListener</code> service objects. ConfigurationEvents
+ * must be asynchronously delivered in chronological order with respect to each
+ * listener.
+ * 
+ * <p>
+ * A type code is used to identify the type of event. The following event types
+ * are defined:
+ * <ul>
+ * <li>{@link #CM_UPDATED}
+ * <li>{@link #CM_DELETED}
+ * </ul>
+ * Additional event types may be defined in the future.
+ * 
+ * <p>
+ * Security Considerations. <code>ConfigurationEvent</code> objects do not
+ * provide <code>Configuration</code> objects, so no sensitive configuration
+ * information is available from the event. If the listener wants to locate the
+ * <code>Configuration</code> object for the specified pid, it must use
+ * <code>ConfigurationAdmin</code>.
+ * 
+ * @see ConfigurationListener
+ * 
+ * @version $Revision: 1.8 $
+ * @since 1.2
+ */
+public class ConfigurationEvent {
+	/**
+	 * A <code>Configuration</code> has been updated.
+	 * 
+	 * <p>
+	 * This <code>ConfigurationEvent</code> type that indicates that a
+	 * <code>Configuration</code> object has been updated with new properties.
+	 * 
+	 * An event is fired when a call to <code>Configuration.update</code>
+	 * successfully changes a configuration.
+	 * 
+	 * <p>
+	 * The value of <code>CM_UPDATED</code> is 1.
+	 */
+	public static final int			CM_UPDATED	= 1;
+	/**
+	 * A <code>Configuration</code> has been deleted.
+	 * 
+	 * <p>
+	 * This <code>ConfigurationEvent</code> type that indicates that a
+	 * <code>Configuration</code> object has been deleted.
+	 * 
+	 * An event is fired when a call to <code>Configuration.delete</code>
+	 * successfully deletes a configuration.
+	 * 
+	 * <p>
+	 * The value of <code>CM_DELETED</code> is 2.
+	 */
+	public static final int			CM_DELETED	= 2;
+	/**
+	 * Type of this event.
+	 * 
+	 * @see #getType
+	 */
+	private final int				type;
+	/**
+	 * The factory pid associated with this event.
+	 */
+	private final String			factoryPid;
+	/**
+	 * The pid associated with this event.
+	 */
+	private final String			pid;
+	/**
+	 * The ConfigurationAdmin service which created this event.
+	 */
+	private final ServiceReference	reference;
+
+	/**
+	 * Constructs a <code>ConfigurationEvent</code> object from the given
+	 * <code>ServiceReference</code> object, event type, and pids.
+	 * 
+	 * @param reference The <code>ServiceReference</code> object of the
+	 *        Configuration Admin service that created this event.
+	 * @param type The event type. See {@link #getType}.
+	 * @param factoryPid The factory pid of the associated configuration if the
+	 *        target of the configuration is a ManagedServiceFactory. Otherwise
+	 *        <code>null</code> if the target of the configuration is a
+	 *        ManagedService.
+	 * @param pid The pid of the associated configuration.
+	 */
+	public ConfigurationEvent(ServiceReference reference, int type,
+			String factoryPid, String pid) {
+		this.reference = reference;
+		this.type = type;
+		this.factoryPid = factoryPid;
+		this.pid = pid;
+	}
+
+	/**
+	 * Returns the factory pid of the associated configuration.
+	 * 
+	 * @return Returns the factory pid of the associated configuration if the
+	 *         target of the configuration is a ManagedServiceFactory. Otherwise
+	 *         <code>null</code> if the target of the configuration is a
+	 *         ManagedService.
+	 */
+	public String getFactoryPid() {
+		return factoryPid;
+	}
+
+	/**
+	 * Returns the pid of the associated configuration.
+	 * 
+	 * @return Returns the pid of the associated configuration.
+	 */
+	public String getPid() {
+		return pid;
+	}
+
+	/**
+	 * Return the type of this event.
+	 * <p>
+	 * The type values are:
+	 * <ul>
+	 * <li>{@link #CM_UPDATED}
+	 * <li>{@link #CM_DELETED}
+	 * </ul>
+	 * 
+	 * @return The type of this event.
+	 */
+	public int getType() {
+		return type;
+	}
+
+	/**
+	 * Return the <code>ServiceReference</code> object of the Configuration
+	 * Admin service that created this event.
+	 * 
+	 * @return The <code>ServiceReference</code> object for the Configuration
+	 *         Admin service that created this event.
+	 */
+	public ServiceReference getReference() {
+		return reference;
+	}
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationException.java b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationException.java
new file mode 100644
index 0000000..6d41dce
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationException.java
@@ -0,0 +1,112 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationException.java,v 1.11 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.cm;
+
+/**
+ * An <code>Exception</code> class to inform the Configuration Admin service
+ * of problems with configuration data.
+ * 
+ * @version $Revision: 1.11 $
+ */
+public class ConfigurationException extends Exception {
+	static final long	serialVersionUID	= -1690090413441769377L;
+
+	private String		property;
+	private String		reason;
+
+	/**
+	 * Nested exception.
+	 */
+	private Throwable	cause;
+
+	/**
+	 * Create a <code>ConfigurationException</code> object.
+	 * 
+	 * @param property name of the property that caused the problem,
+	 *        <code>null</code> if no specific property was the cause
+	 * @param reason reason for failure
+	 */
+	public ConfigurationException(String property, String reason) {
+		super(property + " : " + reason);
+		this.property = property;
+		this.reason = reason;
+		this.cause = null;
+	}
+
+	/**
+	 * Create a <code>ConfigurationException</code> object.
+	 * 
+	 * @param property name of the property that caused the problem,
+	 *        <code>null</code> if no specific property was the cause
+	 * @param reason reason for failure
+	 * @param cause The cause of this exception.
+	 * @since 1.2
+	 */
+	public ConfigurationException(String property, String reason,
+			Throwable cause) {
+		super(property + " : " + reason);
+		this.property = property;
+		this.reason = reason;
+		this.cause = cause;
+	}
+
+	/**
+	 * Return the property name that caused the failure or null.
+	 * 
+	 * @return name of property or null if no specific property caused the
+	 *         problem
+	 */
+	public String getProperty() {
+		return property;
+	}
+
+	/**
+	 * Return the reason for this exception.
+	 * 
+	 * @return reason of the failure
+	 */
+	public String getReason() {
+		return reason;
+	}
+
+	/**
+	 * Returns the cause of this exception or <code>null</code> if no cause
+	 * was specified when this exception was created.
+	 * 
+	 * @return The cause of this exception or <code>null</code> if no cause
+	 *         was specified.
+	 * @since 1.2
+	 */
+	public Throwable getCause() {
+		return cause;
+	}
+
+	/**
+	 * The cause of this exception can only be set when constructed.
+	 * 
+	 * @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.
+	 * @since 1.2
+	 */
+	public Throwable initCause(Throwable cause) {
+		throw new IllegalStateException();
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationListener.java b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationListener.java
new file mode 100644
index 0000000..f7fb6a6
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationListener.java
@@ -0,0 +1,50 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationListener.java,v 1.9 2006/03/14 01:21:09 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2004, 2005). 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.cm;
+
+/**
+ * Listener for Configuration Events. When a <code>ConfigurationEvent</code>
+ * is fired, it is asynchronously delivered to a
+ * <code>ConfigurationListener</code>.
+ * 
+ * <p>
+ * <code>ConfigurationListener</code> objects are registered with the
+ * Framework service registry and are notified with a
+ * <code>ConfigurationEvent</code> object when an event is fired.
+ * <p>
+ * <code>ConfigurationListener</code> objects can inspect the received
+ * <code>ConfigurationEvent</code> object to determine its type, the pid of
+ * the <code>Configuration</code> object with which it is associated, and the
+ * Configuration Admin service that fired the event.
+ * 
+ * <p>
+ * Security Considerations. Bundles wishing to monitor configuration events will
+ * require <code>ServicePermission[ConfigurationListener,REGISTER]</code> to
+ * register a <code>ConfigurationListener</code> service.
+ * 
+ * @version $Revision: 1.9 $
+ * @since 1.2
+ */
+public interface ConfigurationListener {
+	/**
+	 * Receives notification of a Configuration that has changed.
+	 * 
+	 * @param event The <code>ConfigurationEvent</code>.
+	 */
+	public void configurationEvent(ConfigurationEvent event);
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationPermission.java b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationPermission.java
new file mode 100644
index 0000000..dc0c6ec
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationPermission.java
@@ -0,0 +1,217 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationPermission.java,v 1.20 2006/03/14 01:21:09 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2004, 2005). 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.cm;
+
+import java.security.*;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * Indicates a bundle's authority to configure bundles.
+ * 
+ * This permission has only a single action: CONFIGURE.
+ * 
+ * @version $Revision: 1.20 $
+ * @since 1.2
+ */
+
+public final class ConfigurationPermission extends BasicPermission {
+	static final long			serialVersionUID	= 5716868734811965383L;
+	/**
+	 * The action string <code>configure</code>.
+	 */
+	public final static String	CONFIGURE			= "configure";
+
+	/**
+	 * Create a new ConfigurationPermission.
+	 * 
+	 * @param name Name must be &quot;*&quot;.
+	 * @param actions <code>configure</code> (canonical order).
+	 */
+
+	public ConfigurationPermission(String name, String actions) {
+		super(name);
+		if (!name.equals("*")) {
+			throw new IllegalArgumentException("name must be *");
+		}
+		actions = actions.trim();
+		if (actions.equalsIgnoreCase(CONFIGURE)||actions.equals("*"))
+			return;
+		
+		throw new IllegalArgumentException("actions must be " + CONFIGURE);
+	}
+
+	/**
+	 * Determines if a <code>ConfigurationPermission</code> object "implies"
+	 * the specified permission.
+	 * 
+	 * @param p The target permission to check.
+	 * @return <code>true</code> if the specified permission is implied by
+	 *         this object; <code>false</code> otherwise.
+	 */
+
+	public boolean implies(Permission p) {
+		return p instanceof ConfigurationPermission;
+	}
+
+	/**
+	 * Determines the equality of two <code>ConfigurationPermission</code>
+	 * objects.
+	 * <p>
+	 * Two <code>ConfigurationPermission</code> objects are equal.
+	 * 
+	 * @param obj The object being compared for equality with this object.
+	 * @return <code>true</code> if <code>obj</code> is equivalent to this
+	 *         <code>ConfigurationPermission</code>; <code>false</code>
+	 *         otherwise.
+	 */
+	public boolean equals(Object obj) {
+		return obj instanceof ConfigurationPermission;
+	}
+
+	/**
+	 * Returns the hash code value for this object.
+	 * 
+	 * @return Hash code value for this object.
+	 */
+
+	public int hashCode() {
+		return getName().hashCode() ^ getActions().hashCode();
+	}
+
+	/**
+	 * Returns the canonical string representation of the
+	 * <code>ConfigurationPermission</code> actions.
+	 * 
+	 * <p>
+	 * Always returns present <code>ConfigurationPermission</code> actions in
+	 * the following order: <code>CONFIGURE</code>
+	 * 
+	 * @return Canonical string representation of the
+	 *         <code>ConfigurationPermission</code> actions.
+	 */
+	public String getActions() {
+		return CONFIGURE;
+	}
+
+	/**
+	 * Returns a new <code>PermissionCollection</code> object suitable for
+	 * storing <code>ConfigurationPermission</code>s.
+	 * 
+	 * @return A new <code>PermissionCollection</code> object.
+	 */
+	public PermissionCollection newPermissionCollection() {
+		return new ConfigurationPermissionCollection();
+	}
+}
+
+/**
+ * Stores a set of <code>ConfigurationPermission</code> permissions.
+ * 
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ */
+final class ConfigurationPermissionCollection extends PermissionCollection {
+	static final long	serialVersionUID	= -6917638867081695839L;
+	/**
+	 * True if collection is non-empty.
+	 * 
+	 * @serial
+	 */
+	private boolean		hasElement;
+
+	/**
+	 * Creates an empty <tt>ConfigurationPermissionCollection</tt> object.
+	 * 
+	 */
+	public ConfigurationPermissionCollection() {
+		hasElement = false;
+	}
+
+	/**
+	 * Adds the specified permission to the
+	 * <tt>ConfigurationPermissionCollection</tt>. The key for the hash is
+	 * the interface name of the service.
+	 * 
+	 * @param permission The <tt>Permission</tt> object to add.
+	 * 
+	 * @exception IllegalArgumentException If the permission is not an
+	 *            <tt>ConfigurationPermission</tt>.
+	 * 
+	 * @exception SecurityException If this ConfigurationPermissionCollection
+	 *            object has been marked read-only.
+	 */
+
+	public void add(Permission permission) {
+		if (!(permission instanceof ConfigurationPermission)) {
+			throw new IllegalArgumentException("invalid permission: "
+					+ permission);
+		}
+
+		if (isReadOnly())
+			throw new SecurityException("attempt to add a Permission to a "
+					+ "readonly PermissionCollection");
+
+		hasElement = true;
+	}
+
+	/**
+	 * Determines if the specified set of permissions implies the permissions
+	 * expressed in the parameter <tt>permission</tt>.
+	 * 
+	 * @param p The Permission object to compare.
+	 * 
+	 * @return true if permission is a proper subset of a permission in the set;
+	 *         false otherwise.
+	 */
+
+	public boolean implies(Permission p) {
+		return hasElement && (p instanceof ConfigurationPermission);
+	}
+
+	/**
+	 * Returns an enumeration of an <tt>ConfigurationPermission</tt> object.
+	 * 
+	 * @return Enumeration of an <tt>ConfigurationPermission</tt> object.
+	 */
+
+	public Enumeration elements() {
+		return new Enumeration() {
+			private boolean	more	= hasElement;
+
+			public boolean hasMoreElements() {
+				return more;
+			}
+
+			public Object nextElement() {
+				if (more) {
+					more = false;
+
+					return new ConfigurationPermission("*",
+							ConfigurationPermission.CONFIGURE);
+				}
+				else {
+					throw new NoSuchElementException();
+				}
+			}
+		};
+	}
+
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationPlugin.java b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationPlugin.java
new file mode 100644
index 0000000..089e626
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ConfigurationPlugin.java
@@ -0,0 +1,131 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationPlugin.java,v 1.10 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.cm;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A service interface for processing configuration dictionary before the
+ * update.
+ * 
+ * <p>
+ * A bundle registers a <code>ConfigurationPlugin</code> object in order to
+ * process configuration updates before they reach the Managed Service or
+ * Managed Service Factory. The Configuration Admin service will detect
+ * registrations of Configuration Plugin services and must call these services
+ * every time before it calls the <code>ManagedService</code> or
+ * <code>ManagedServiceFactory</code>
+ * <code>updated</code> method. The
+ * Configuration Plugin service thus has the opportunity to view and modify the
+ * properties before they are passed to the ManagedS ervice or Managed Service
+ * Factory.
+ * 
+ * <p>
+ * Configuration Plugin (plugin) services have full read/write access to all
+ * configuration information. Therefore, bundles using this facility should be
+ * trusted. Access to this facility should be limited with
+ * <code>ServicePermission[ConfigurationPlugin,REGISTER]</code>.
+ * Implementations of a Configuration Plugin service should assure that they
+ * only act on appropriate configurations.
+ * 
+ * <p>
+ * The <code>Integer</code> <code>service.cmRanking</code> registration
+ * property may be specified. Not specifying this registration property, or
+ * setting it to something other than an <code>Integer</code>, is the same as
+ * setting it to the <code>Integer</code> zero. The
+ * <code>service.cmRanking</code> property determines the order in which
+ * plugins are invoked. Lower ranked plugins are called before higher ranked
+ * ones. In the event of more than one plugin having the same value of
+ * <code>service.cmRanking</code>, then the Configuration Admin service
+ * arbitrarily chooses the order in which they are called.
+ * 
+ * <p>
+ * By convention, plugins with <code>service.cmRanking&lt; 0</code> or
+ * <code>service.cmRanking &gt; 1000</code> should not make modifications to
+ * the properties.
+ * 
+ * <p>
+ * The Configuration Admin service has the right to hide properties from
+ * plugins, or to ignore some or all the changes that they make. This might be
+ * done for security reasons. Any such behavior is entirely implementation
+ * defined.
+ * 
+ * <p>
+ * A plugin may optionally specify a <code>cm.target</code> registration
+ * property whose value is the PID of the Managed Service or Managed Service
+ * Factory whose configuration updates the plugin is intended to intercept. The
+ * plugin will then only be called with configuration updates that are targetted
+ * at the Managed Service or Managed Service Factory with the specified PID.
+ * Omitting the <code>cm.target</code> registration property means that the
+ * plugin is called for all configuration updates.
+ * 
+ * @version $Revision: 1.10 $
+ */
+public interface ConfigurationPlugin {
+	/**
+	 * A service property to limit the Managed Service or Managed Service
+	 * Factory configuration dictionaries a Configuration Plugin service
+	 * receives.
+	 * 
+	 * This property contains a <code>String[]</code> of PIDs. A Configuration
+	 * Admin service must call a Configuration Plugin service only when this
+	 * property is not set, or the target service's PID is listed in this
+	 * property.
+	 */
+	public static final String	CM_TARGET	= "cm.target";
+	/**
+	 * A service property to specify the order in which plugins are invoked.
+	 * 
+	 * This property contains an <code>Integer</code> ranking of the plugin.
+	 * Not specifying this registration property, or setting it to something
+	 * other than an <code>Integer</code>, is the same as setting it to the
+	 * <code>Integer</code> zero. This property determines the order in which
+	 * plugins are invoked. Lower ranked plugins are called before higher ranked
+	 * ones.
+	 * 
+	 * @since 1.2
+	 */
+	public static final String	CM_RANKING	= "service.cmRanking";
+
+	/**
+	 * View and possibly modify the a set of configuration properties before
+	 * they are sent to the Managed Service or the Managed Service Factory. The
+	 * Configuration Plugin services are called in increasing order of their
+	 * <code>service.cmRanking</code> property. If this property is undefined
+	 * or is a non- <code>Integer</code> type, 0 is used.
+	 * 
+	 * <p>
+	 * This method should not modify the properties unless the
+	 * <code>service.cmRanking</code> of this plugin is in the range
+	 * <code>0 &lt;= service.cmRanking &lt;= 1000</code>.
+	 * <p>
+	 * If this method throws any <code>Exception</code>, the Configuration
+	 * Admin service must catch it and should log it.
+	 * 
+	 * @param reference reference to the Managed Service or Managed Service
+	 *        Factory
+	 * @param properties The configuration properties. This argument must not
+	 *        contain the "service.bundleLocation" property. The value of this
+	 *        property may be obtained from the
+	 *        <code>Configuration.getBundleLocation</code> method.
+	 */
+	public void modifyConfiguration(ServiceReference reference,
+			Dictionary properties);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/cm/ManagedService.java b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ManagedService.java
new file mode 100644
index 0000000..b5ccce4
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ManagedService.java
@@ -0,0 +1,140 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ManagedService.java,v 1.11 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.cm;
+
+import java.util.Dictionary;
+
+/**
+ * A service that can receive configuration data from a Configuration Admin
+ * service.
+ * 
+ * <p>
+ * A Managed Service is a service that needs configuration data. Such an object
+ * should be registered with the Framework registry with the
+ * <code>service.pid</code> property set to some unique identitifier called a
+ * PID.
+ * 
+ * <p>
+ * If the Configuration Admin service has a <code>Configuration</code> object
+ * corresponding to this PID, it will callback the <code>updated()</code>
+ * method of the <code>ManagedService</code> object, passing the properties of
+ * that <code>Configuration</code> object.
+ * 
+ * <p>
+ * If it has no such <code>Configuration</code> object, then it calls back
+ * with a <code>null</code> properties argument. Registering a Managed Service
+ * will always result in a callback to the <code>updated()</code> method
+ * provided the Configuration Admin service is, or becomes active. This callback
+ * must always be done asynchronously.
+ * 
+ * <p>
+ * Else, every time that either of the <code>updated()</code> methods is
+ * called on that <code>Configuration</code> object, the
+ * <code>ManagedService.updated()</code> method with the new properties is
+ * called. If the <code>delete()</code> method is called on that
+ * <code>Configuration</code> object, <code>ManagedService.updated()</code>
+ * is called with a <code>null</code> for the properties parameter. All these
+ * callbacks must be done asynchronously.
+ * 
+ * <p>
+ * The following example shows the code of a serial port that will create a port
+ * depending on configuration information.
+ * 
+ * <pre>
+ *  
+ *   class SerialPort implements ManagedService {
+ *  
+ *     ServiceRegistration registration;
+ *     Hashtable configuration;
+ *     CommPortIdentifier id;
+ *  
+ *     synchronized void open(CommPortIdentifier id,
+ *     BundleContext context) {
+ *       this.id = id;
+ *       registration = context.registerService(
+ *         ManagedService.class.getName(),
+ *         this,
+ *         getDefaults()
+ *       );
+ *     }
+ *  
+ *     Hashtable getDefaults() {
+ *       Hashtable defaults = new Hashtable();
+ *       defaults.put( &quot;port&quot;, id.getName() );
+ *       defaults.put( &quot;product&quot;, &quot;unknown&quot; );
+ *       defaults.put( &quot;baud&quot;, &quot;9600&quot; );
+ *       defaults.put( Constants.SERVICE_PID,
+ *         &quot;com.acme.serialport.&quot; + id.getName() );
+ *       return defaults;
+ *     }
+ *  
+ *     public synchronized void updated(
+ *       Dictionary configuration  ) {
+ *       if ( configuration == 
+ * <code>
+ * null
+ * </code>
+ *   )
+ *         registration.setProperties( getDefaults() );
+ *       else {
+ *         setSpeed( configuration.get(&quot;baud&quot;) );
+ *         registration.setProperties( configuration );
+ *       }
+ *     }
+ *     ...
+ *   }
+ *   
+ * </pre>
+ * 
+ * <p>
+ * As a convention, it is recommended that when a Managed Service is updated, it
+ * should copy all the properties it does not recognize into the service
+ * registration properties. This will allow the Configuration Admin service to
+ * set properties on services which can then be used by other applications.
+ * 
+ * @version $Revision: 1.11 $
+ */
+public interface ManagedService {
+	/**
+	 * Update the configuration for a Managed Service.
+	 * 
+	 * <p>
+	 * When the implementation of <code>updated(Dictionary)</code> detects any
+	 * kind of error in the configuration properties, it should create a new
+	 * <code>ConfigurationException</code> which describes the problem. This
+	 * can allow a management system to provide useful information to a human
+	 * administrator.
+	 * 
+	 * <p>
+	 * If this method throws any other <code>Exception</code>, the
+	 * Configuration Admin service must catch it and should log it.
+	 * <p>
+	 * The Configuration Admin service must call this method asynchronously
+	 * which initiated the callback. This implies that implementors of Managed
+	 * Service can be assured that the callback will not take place during
+	 * registration when they execute the registration in a synchronized method.
+	 * 
+	 * @param properties A copy of the Configuration properties, or
+	 *        <code>null</code>. This argument must not contain the
+	 *        "service.bundleLocation" property. The value of this property may
+	 *        be obtained from the <code>Configuration.getBundleLocation</code>
+	 *        method.
+	 * @throws ConfigurationException when the update fails
+	 */
+	public void updated(Dictionary properties) throws ConfigurationException;
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/cm/ManagedServiceFactory.java b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ManagedServiceFactory.java
new file mode 100644
index 0000000..001ddd8
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/cm/ManagedServiceFactory.java
@@ -0,0 +1,162 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ManagedServiceFactory.java,v 1.10 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.cm;
+
+import java.util.Dictionary;
+
+/**
+ * Manage multiple service instances.
+ * 
+ * Bundles registering this interface are giving the Configuration Admin service
+ * the ability to create and configure a number of instances of a service that
+ * the implementing bundle can provide. For example, a bundle implementing a
+ * DHCP server could be instantiated multiple times for different interfaces
+ * using a factory.
+ * 
+ * <p>
+ * Each of these <i>service instances </i> is represented, in the persistent
+ * storage of the Configuration Admin service, by a factory
+ * <code>Configuration</code> object that has a PID. When such a
+ * <code>Configuration</code> is updated, the Configuration Admin service
+ * calls the <code>ManagedServiceFactory</code> updated method with the new
+ * properties. When <code>updated</code> is called with a new PID, the Managed
+ * Service Factory should create a new factory instance based on these
+ * configuration properties. When called with a PID that it has seen before, it
+ * should update that existing service instance with the new configuration
+ * information.
+ * 
+ * <p>
+ * In general it is expected that the implementation of this interface will
+ * maintain a data structure that maps PIDs to the factory instances that it has
+ * created. The semantics of a factory instance are defined by the Managed
+ * Service Factory. However, if the factory instance is registered as a service
+ * object with the service registry, its PID should match the PID of the
+ * corresponding <code>Configuration</code> object (but it should <b>not </b>
+ * be registered as a Managed Service!).
+ * 
+ * <p>
+ * An example that demonstrates the use of a factory. It will create serial
+ * ports under command of the Configuration Admin service.
+ * 
+ * <pre>
+ *  
+ *   class SerialPortFactory
+ *     implements ManagedServiceFactory {
+ *     ServiceRegistration registration;
+ *     Hashtable ports;
+ *     void start(BundleContext context) {
+ *       Hashtable properties = new Hashtable();
+ *       properties.put( Constants.SERVICE_PID,
+ *         &quot;com.acme.serialportfactory&quot; );
+ *       registration = context.registerService(
+ *         ManagedServiceFactory.class.getName(),
+ *         this,
+ *         properties
+ *       );
+ *     }
+ *     public void updated( String pid,
+ *       Dictionary properties  ) {
+ *       String portName = (String) properties.get(&quot;port&quot;);
+ *       SerialPortService port =
+ *         (SerialPort) ports.get( pid );
+ *       if ( port == null ) {
+ *         port = new SerialPortService();
+ *         ports.put( pid, port );
+ *         port.open();
+ *       }
+ *       if ( port.getPortName().equals(portName) )
+ *         return;
+ *       port.setPortName( portName );
+ *     }
+ *     public void deleted( String pid ) {
+ *       SerialPortService port =
+ *         (SerialPort) ports.get( pid );
+ *       port.close();
+ *       ports.remove( pid );
+ *     }
+ *     ...
+ *   }
+ *   
+ * </pre>
+ * 
+ * @version $Revision: 1.10 $
+ */
+public interface ManagedServiceFactory {
+	/**
+	 * Return a descriptive name of this factory.
+	 * 
+	 * @return the name for the factory, which might be localized
+	 */
+	public String getName();
+
+	/**
+	 * Create a new instance, or update the configuration of an existing
+	 * instance.
+	 * 
+	 * If the PID of the <code>Configuration</code> object is new for the
+	 * Managed Service Factory, then create a new factory instance, using the
+	 * configuration <code>properties</code> provided. Else, update the
+	 * service instance with the provided <code>properties</code>.
+	 * 
+	 * <p>
+	 * If the factory instance is registered with the Framework, then the
+	 * configuration <code>properties</code> should be copied to its registry
+	 * properties. This is not mandatory and security sensitive properties
+	 * should obviously not be copied.
+	 * 
+	 * <p>
+	 * If this method throws any <code>Exception</code>, the Configuration
+	 * Admin service must catch it and should log it.
+	 * 
+	 * <p>
+	 * When the implementation of updated detects any kind of error in the
+	 * configuration properties, it should create a new
+	 * {@link ConfigurationException}which describes the problem.
+	 * 
+	 * <p>
+	 * The Configuration Admin service must call this method asynchronously.
+	 * This implies that implementors of the <code>ManagedServiceFactory</code>
+	 * class can be assured that the callback will not take place during
+	 * registration when they execute the registration in a synchronized method.
+	 * 
+	 * @param pid The PID for this configuration.
+	 * @param properties A copy of the configuration properties. This argument
+	 *        must not contain the service.bundleLocation" property. The value
+	 *        of this property may be obtained from the
+	 *        <code>Configuration.getBundleLocation</code> method.
+	 * @throws ConfigurationException when the configuration properties are
+	 *         invalid.
+	 */
+	public void updated(String pid, Dictionary properties)
+			throws ConfigurationException;
+
+	/**
+	 * Remove a factory instance.
+	 * 
+	 * Remove the factory instance associated with the PID. If the instance was
+	 * registered with the service registry, it should be unregistered.
+	 * <p>
+	 * If this method throws any <code>Exception</code>, the Configuration
+	 * Admin service must catch it and should log it.
+	 * <p>
+	 * The Configuration Admin service must call this method asynchronously.
+	 * 
+	 * @param pid the PID of the service to be removed
+	 */
+	public void deleted(String pid);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/cm/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/cm/package.html
new file mode 100644
index 0000000..3f65348
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/cm/package.html
@@ -0,0 +1,11 @@
+<!-- $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/package.html,v 1.2 2004/12/01 19:01:11 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Configuration Admin service Package. Specification 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.cm; version=1.2
+</pre>
+</BODY>
+
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/cm/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/cm/packageinfo
new file mode 100644
index 0000000..ef7df68
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/cm/packageinfo
@@ -0,0 +1 @@
+version 1.2
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentConstants.java b/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentConstants.java
new file mode 100644
index 0000000..be30ac0
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentConstants.java
@@ -0,0 +1,71 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.component/src/org/osgi/service/component/ComponentConstants.java,v 1.13 2006/03/14 01:20:50 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2004, 2005). 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.component;
+
+/**
+ * Defines standard names for Service Component constants.
+ * 
+ * @version $Revision: 1.13 $
+ */
+public interface ComponentConstants {
+	/**
+	 * Manifest header (named &quot;Service-Component&quot;) specifying the XML
+	 * documents within a bundle that contain the bundle's Service Component
+	 * descriptions.
+	 * <p>
+	 * The attribute value may be retrieved from the <code>Dictionary</code>
+	 * object returned by the <code>Bundle.getHeaders</code> method.
+	 */
+	public static final String	SERVICE_COMPONENT		= "Service-Component";
+
+	/**
+	 * A component property for a component configuration that contains the name
+	 * of the component as specified in the <code>name</code> attribute of the
+	 * <code>component</code> element. The type of this property must be
+	 * <code>String</code>.
+	 */
+	public final static String	COMPONENT_NAME			= "component.name";
+
+	/**
+	 * A component property that contains the generated id for a component
+	 * configuration. The type of this property must be <code>Long</code>.
+	 * 
+	 * <p>
+	 * The value of this property is assigned by the Service Component Runtime
+	 * when a component configuration is created. The Service Component Runtime
+	 * assigns a unique value that is larger than all previously assigned values
+	 * since the Service Component Runtime was started. These values are NOT
+	 * persistent across restarts of the Service Component Runtime.
+	 */
+	public final static String	COMPONENT_ID			= "component.id";
+
+	/**
+	 * A service registration property for a Component Factory that contains the
+	 * value of the <code>factory</code> attribute. The type of this property
+	 * must be <code>String</code>.
+	 */
+	public final static String	COMPONENT_FACTORY		= "component.factory";
+
+	/**
+	 * The suffix for reference target properties. These properties contain the
+	 * filter to select the target services for a reference. The type of this
+	 * property must be <code>String</code>.
+	 */
+	public final static String	REFERENCE_TARGET_SUFFIX	= ".target";
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentContext.java b/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentContext.java
new file mode 100644
index 0000000..af4aab9
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentContext.java
@@ -0,0 +1,198 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.component/src/org/osgi/service/component/ComponentContext.java,v 1.19 2006/03/14 01:20:50 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2005). 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.component;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.*;
+
+/**
+ * A Component Context object is used by a component instance to interact with
+ * its execution context including locating services by reference name. Each
+ * component instance has a unique Component Context.
+ * 
+ * <p>
+ * A component's implementation class may optionaly implement an activate
+ * method:
+ * 
+ * <pre>
+ * protected void activate(ComponentContext context);
+ * </pre>
+ * 
+ * If a component implements this method, this method will be called when a
+ * component configuration is activated to provide the component instance's
+ * Component Context object.
+ * 
+ * <p>
+ * A component's implementation class may optionaly implement a deactivate
+ * method:
+ * 
+ * <pre>
+ * protected void deactivate(ComponentContext context);
+ * </pre>
+ * 
+ * If a component implements this method, this method will be called when the
+ * component configuration is deactivated.
+ * 
+ * <p>
+ * The activate and deactivate methods will be called using reflection and must
+ * be protected or public accessible. These methods should not be public methods
+ * so that they do not appear as public methods on the component instance when
+ * used as a service object. These methods will be located by looking through
+ * the component's implementation class hierarchy for the first declaration of
+ * the method. If the method is found, if it is declared protected or public,
+ * the method will be called. Otherwise, the method will not be called.
+ * 
+ * @version $Revision: 1.19 $
+ */
+public interface ComponentContext {
+	/**
+	 * Returns the component properties for this Component Context.
+	 * 
+	 * @return The properties for this Component Context. The Dictionary is read
+	 *         only and cannot be modified.
+	 */
+	public Dictionary getProperties();
+
+	/**
+	 * Returns the service object for the specified reference name.
+	 * 
+	 * <p>
+	 * If the cardinality of the reference is <code>0..n</code> or
+	 * <code>1..n</code> and multiple services are bound to the reference, the
+	 * service with the highest ranking (as specified in its
+	 * <code>Constants.SERVICE_RANKING</code> property) is returned. If there
+	 * is a tie in ranking, the service with the lowest service ID (as specified
+	 * in its <code>Constants.SERVICE_ID</code> property); that is, the
+	 * service that was registered first is returned.
+	 * 
+	 * @param name The name of a reference as specified in a
+	 *        <code>reference</code> element in this component's description.
+	 * @return A service object for the referenced service or <code>null</code>
+	 *         if the reference cardinality is <code>0..1</code> or
+	 *         <code>0..n</code> and no bound service is available.
+	 * @throws ComponentException If the Service Component Runtime catches an
+	 *         exception while activating the bound service.
+	 */
+	public Object locateService(String name);
+
+	/**
+	 * Returns the service object for the specified reference name and
+	 * <code>ServiceReference</code>.
+	 * 
+	 * @param name The name of a reference as specified in a
+	 *        <code>reference</code> element in this component's description.
+	 * @param reference The <code>ServiceReference</code> to a bound service.
+	 *        This must be a <code>ServiceReference</code> provided to the
+	 *        component via the bind or unbind method for the specified
+	 *        reference name.
+	 * @return A service object for the referenced service or <code>null</code>
+	 *         if the specified <code>ServiceReference</code> is not a bound
+	 *         service for the specified reference name.
+	 * @throws ComponentException If the Service Component Runtime catches an
+	 *         exception while activating the bound service.
+	 */
+	public Object locateService(String name, ServiceReference reference);
+
+	/**
+	 * Returns the service objects for the specified reference name.
+	 * 
+	 * @param name The name of a reference as specified in a
+	 *        <code>reference</code> element in this component's description.
+	 * @return An array of service objects for the referenced service or
+	 *         <code>null</code> if the reference cardinality is
+	 *         <code>0..1</code> or <code>0..n</code> and no bound service
+	 *         is available.
+	 * @throws ComponentException If the Service Component Runtime catches an
+	 *         exception while activating a bound service.
+	 */
+	public Object[] locateServices(String name);
+
+	/**
+	 * Returns the <code>BundleContext</code> of the bundle which contains
+	 * this component.
+	 * 
+	 * @return The <code>BundleContext</code> of the bundle containing this
+	 *         component.
+	 */
+	public BundleContext getBundleContext();
+
+	/**
+	 * If the component instance is registered as a service using the
+	 * <code>servicefactory=&quot;true&quot;</code> attribute, then this
+	 * method returns the bundle using the service provided by the component
+	 * instance.
+	 * <p>
+	 * This method will return <code>null</code> if:
+	 * <ul>
+	 * <li>The component instance is not a service, then no bundle can be using
+	 * it as a service.
+	 * <li>The component instance is a service but did not specify the
+	 * <code>servicefactory=&quot;true&quot;</code> attribute, then all
+	 * bundles using the service provided by the component instance will share
+	 * the same component instance.
+	 * <li>The service provided by the component instance is not currently
+	 * being used by any bundle.
+	 * </ul>
+	 * 
+	 * @return The bundle using the component instance as a service or
+	 *         <code>null</code>.
+	 */
+	public Bundle getUsingBundle();
+
+	/**
+	 * Returns the Component Instance object for the component instance
+	 * associated with this Component Context.
+	 * 
+	 * @return The Component Instance object for the component instance.
+	 */
+	public ComponentInstance getComponentInstance();
+
+	/**
+	 * Enables the specified component name. The specified component name must
+	 * be in the same bundle as this component.
+	 * 
+	 * @param name The name of a component or <code>null</code> to indicate
+	 *        all components in the bundle.
+	 */
+	public void enableComponent(String name);
+
+	/**
+	 * Disables the specified component name. The specified component name must
+	 * be in the same bundle as this component.
+	 * 
+	 * @param name The name of a component.
+	 */
+	public void disableComponent(String name);
+
+	/**
+	 * If the component instance is registered as a service using the
+	 * <code>service</code> element, then this method returns the service
+	 * reference of the service provided by this component instance.
+	 * <p>
+	 * This method will return <code>null</code> if the component instance is
+	 * not registered as a service.
+	 * 
+	 * @return The <code>ServiceReference</code> object for the component
+	 *         instance or <code>null</code> if the component instance is not
+	 *         registered as a service.
+	 */
+	public ServiceReference getServiceReference();
+
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentException.java b/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentException.java
new file mode 100644
index 0000000..4679d31
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentException.java
@@ -0,0 +1,87 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.component/src/org/osgi/service/component/ComponentException.java,v 1.11 2006/03/14 01:20:50 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2004, 2005). 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.component;
+
+/**
+ * Unchecked exception which may be thrown by the Service Component Runtime.
+ * 
+ * @version $Revision: 1.11 $
+ */
+public class ComponentException extends RuntimeException {
+	static final long	serialVersionUID	= -7438212656298726924L;
+	/**
+	 * Nested exception.
+	 */
+	private Throwable	cause;
+
+	/**
+	 * Construct a new ComponentException with the specified message and cause.
+	 * 
+	 * @param message The message for the exception.
+	 * @param cause The cause of the exception. May be <code>null</code>.
+	 */
+	public ComponentException(String message, Throwable cause) {
+		super(message);
+		this.cause = cause;
+	}
+
+	/**
+	 * Construct a new ComponentException with the specified message.
+	 * 
+	 * @param message The message for the exception.
+	 */
+	public ComponentException(String message) {
+		super(message);
+		this.cause = null;
+	}
+
+	/**
+	 * Construct a new ComponentException with the specified cause.
+	 * 
+	 * @param cause The cause of the exception. May be <code>null</code>.
+	 */
+	public ComponentException(Throwable cause) {
+		super();
+		this.cause = cause;
+	}
+
+	/**
+	 * Returns the cause of this exception or <code>null</code> if no cause
+	 * was specified when this exception was created.
+	 * 
+	 * @return The cause of this exception or <code>null</code> if no cause
+	 *         was specified.
+	 */
+	public Throwable getCause() {
+		return cause;
+	}
+
+	/**
+	 * The cause of this exception can only be set when constructed.
+	 * 
+	 * @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.
+	 */
+	public Throwable initCause(Throwable cause) {
+		throw new IllegalStateException();
+	}
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentFactory.java b/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentFactory.java
new file mode 100644
index 0000000..26dd697
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentFactory.java
@@ -0,0 +1,47 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.component/src/org/osgi/service/component/ComponentFactory.java,v 1.17 2006/03/14 01:20:50 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2005). 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.component;
+
+import java.util.Dictionary;
+
+/**
+ * When a component is declared with the <code>factory</code> attribute on its
+ * <code>component</code> element, the Service Component Runtime will register
+ * a Component Factory service to allow new component configurations to be
+ * created and activated rather than automatically creating and activating
+ * component configuration as necessary.
+ * 
+ * @version $Revision: 1.17 $
+ */
+public interface ComponentFactory {
+	/**
+	 * Create and activate a new component configuration. Additional properties
+	 * may be provided for the component configuration.
+	 * 
+	 * @param properties Additional properties for the component configuration.
+	 * @return A <code>ComponentInstance</code> object encapsulating the
+	 *         component instance of the component configuration. The component
+	 *         configuration has been activated and, if the component specifies
+	 *         a <code>service</code> element, the component instance has been
+	 *         registered as a service.
+	 * @throws ComponentException If the Service Component Runtime is unable to
+	 *         activate the component configuration.
+	 */
+	public ComponentInstance newInstance(Dictionary properties);
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentInstance.java b/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentInstance.java
new file mode 100644
index 0000000..d55cb60
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/component/ComponentInstance.java
@@ -0,0 +1,47 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.component/src/org/osgi/service/component/ComponentInstance.java,v 1.12 2006/03/14 01:20:50 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2005). 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.component;
+
+/**
+ * A ComponentInstance encapsulates a component instance of an activated
+ * component configuration. ComponentInstances are created whenever a component
+ * configuration is activated.
+ * 
+ * <p>
+ * ComponentInstances are never reused. A new ComponentInstance object will be
+ * created when the component configuration is activated again.
+ * 
+ * @version $Revision: 1.12 $
+ */
+public interface ComponentInstance {
+	/**
+	 * Dispose of the component configuration for this component instance. The
+	 * component configuration will be deactivated. If the component
+	 * configuration has already been deactivated, this method does nothing.
+	 */
+	public void dispose();
+
+	/**
+	 * Returns the component instance of the activated component configuration.
+	 * 
+	 * @return The component instance or <code>null</code> if the component
+	 *         configuration has been deactivated.
+	 */
+	public Object getInstance();
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/component/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/component/package.html
new file mode 100644
index 0000000..9f0de40
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/component/package.html
@@ -0,0 +1,11 @@
+<!-- $Header: /cvshome/build/org.osgi.service.component/src/org/osgi/service/component/package.html,v 1.2 2004/12/01 19:01:25 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Service Component Package. Specification 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.component; version=1.0
+</pre>
+</BODY>
+
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/component/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/component/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/component/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/device/Constants.java b/org.osgi.compendium/src/main/java/org/osgi/service/device/Constants.java
new file mode 100644
index 0000000..309a602
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/device/Constants.java
@@ -0,0 +1,75 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.device/src/org/osgi/service/device/Constants.java,v 1.7 2006/03/14 01:20:43 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2000, 2005). 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.device;
+
+/**
+ * This interface defines standard names for property keys associated with
+ * {@link Device}and {@link Driver}services.
+ * 
+ * <p>
+ * The values associated with these keys are of type <code>java.lang.String</code>,
+ * unless otherwise stated.
+ * 
+ * @version $Revision: 1.7 $
+ * @since 1.1
+ * @see Device
+ * @see Driver
+ */
+public interface Constants {
+	/**
+	 * Property (named &quot;DRIVER_ID&quot;) identifying a driver.
+	 * 
+	 * <p>
+	 * A <code>DRIVER_ID</code> should start with the reversed domain name of the
+	 * company that implemented the driver (e.g., <code>com.acme</code>), and
+	 * must meet the following requirements:
+	 * 
+	 * <ul>
+	 * <li>It must be independent of the location from where it is obtained.
+	 * <li>It must be independent of the {@link DriverLocator}service that
+	 * downloaded it.
+	 * <li>It must be unique.
+	 * <li>It must be different for different revisions of the same driver.
+	 * </ul>
+	 * 
+	 * <p>
+	 * This property is mandatory, i.e., every <code>Driver</code> service must be
+	 * registered with it.
+	 */
+	public static final String	DRIVER_ID			= "DRIVER_ID";
+	/**
+	 * Property (named &quot;DEVICE_CATEGORY&quot;) containing a human readable
+	 * description of the device categories implemented by a device. This
+	 * property is of type <code>String[]</code>
+	 * 
+	 * <p>
+	 * Services registered with this property will be treated as devices and
+	 * discovered by the device manager
+	 */
+	public static final String	DEVICE_CATEGORY		= "DEVICE_CATEGORY";
+	/**
+	 * Property (named &quot;DEVICE_SERIAL&quot;) specifying a device's serial
+	 * number.
+	 */
+	public static final String	DEVICE_SERIAL		= "DEVICE_SERIAL";
+	/**
+	 * Property (named &quot;DEVICE_DESCRIPTION&quot;) containing a human
+	 * readable string describing the actual hardware device.
+	 */
+	public static final String	DEVICE_DESCRIPTION	= "DEVICE_DESCRIPTION";
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/device/Device.java b/org.osgi.compendium/src/main/java/org/osgi/service/device/Device.java
new file mode 100644
index 0000000..3b70045
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/device/Device.java
@@ -0,0 +1,62 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.device/src/org/osgi/service/device/Device.java,v 1.8 2006/03/14 01:20:43 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2000, 2005). 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.device;
+
+/**
+ * <p>
+ * Interface for identifying device services.
+ * 
+ * <p>
+ * A service must implement this interface or use the
+ * {@link Constants#DEVICE_CATEGORY}registration property to indicate that it
+ * is a device. Any services implementing this interface or registered with the
+ * <code>DEVICE_CATEGORY</code> property will be discovered by the device manager.
+ * 
+ * <p>
+ * Device services implementing this interface give the device manager the
+ * opportunity to indicate to the device that no drivers were found that could
+ * (further) refine it. In this case, the device manager calls the
+ * {@link #noDriverFound}method on the <code>Device</code> object.
+ * 
+ * <p>
+ * Specialized device implementations will extend this interface by adding
+ * methods appropriate to their device category to it.
+ * 
+ * @version $Revision: 1.8 $
+ * @see Driver
+ */
+public interface Device {
+	/**
+	 * Return value from {@link Driver#match}indicating that the driver cannot
+	 * refine the device presented to it by the device manager.
+	 * 
+	 * The value is zero.
+	 */
+	public static final int	MATCH_NONE	= 0;
+
+	/**
+	 * Indicates to this <code>Device</code> object that the device manager has
+	 * failed to attach any drivers to it.
+	 * 
+	 * <p>
+	 * If this <code>Device</code> object can be configured differently, the
+	 * driver that registered this <code>Device</code> object may unregister it
+	 * and register a different Device service instead.
+	 */
+	public void noDriverFound();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/device/Driver.java b/org.osgi.compendium/src/main/java/org/osgi/service/device/Driver.java
new file mode 100644
index 0000000..e6a5dcd
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/device/Driver.java
@@ -0,0 +1,108 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.device/src/org/osgi/service/device/Driver.java,v 1.9 2006/03/14 01:20:43 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2000, 2005). 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.device;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A <code>Driver</code> service object must be registered by each Driver bundle
+ * wishing to attach to Device services provided by other drivers. For each
+ * newly discovered {@link Device}object, the device manager enters a bidding
+ * phase. The <code>Driver</code> object whose {@link #match}method bids the
+ * highest for a particular <code>Device</code> object will be instructed by the
+ * device manager to attach to the <code>Device</code> object.
+ * 
+ * @version $Revision: 1.9 $
+ * @see Device
+ * @see DriverLocator
+ */
+public interface Driver {
+	/**
+	 * Checks whether this Driver service can be attached to the Device service.
+	 * 
+	 * The Device service is represented by the given {@link ServiceReference}
+	 * and returns a value indicating how well this driver can support the given
+	 * Device service, or {@link Device#MATCH_NONE}if it cannot support the
+	 * given Device service at all.
+	 * 
+	 * <p>
+	 * The return value must be one of the possible match values defined in the
+	 * device category definition for the given Device service, or
+	 * <code>Device.MATCH_NONE</code> if the category of the Device service is not
+	 * recognized.
+	 * 
+	 * <p>
+	 * In order to make its decision, this Driver service may examine the
+	 * properties associated with the given Device service, or may get the
+	 * referenced service object (representing the actual physical device) to
+	 * talk to it, as long as it ungets the service and returns the physical
+	 * device to a normal state before this method returns.
+	 * 
+	 * <p>
+	 * A Driver service must always return the same match code whenever it is
+	 * presented with the same Device service.
+	 * 
+	 * <p>
+	 * The match function is called by the device manager during the matching
+	 * process.
+	 * 
+	 * @param reference the <code>ServiceReference</code> object of the device to
+	 *        match
+	 * 
+	 * @return value indicating how well this driver can support the given
+	 *         Device service, or <code>Device.MATCH_NONE</code> if it cannot
+	 *         support the Device service at all
+	 * 
+	 * @throws java.lang.Exception if this Driver service cannot examine the
+	 *            Device service
+	 */
+	public int match(ServiceReference reference) throws Exception;
+
+	/**
+	 * Attaches this Driver service to the Device service represented by the
+	 * given <code>ServiceReference</code> object.
+	 * 
+	 * <p>
+	 * A return value of <code>null</code> indicates that this Driver service has
+	 * successfully attached to the given Device service. If this Driver service
+	 * is unable to attach to the given Device service, but knows of a more
+	 * suitable Driver service, it must return the <code>DRIVER_ID</code> of that
+	 * Driver service. This allows for the implementation of referring drivers
+	 * whose only purpose is to refer to other drivers capable of handling a
+	 * given Device service.
+	 * 
+	 * <p>
+	 * After having attached to the Device service, this driver may register the
+	 * underlying device as a new service exposing driver-specific
+	 * functionality.
+	 * 
+	 * <p>
+	 * This method is called by the device manager.
+	 * 
+	 * @param reference the <code>ServiceReference</code> object of the device to
+	 *        attach to
+	 * 
+	 * @return <code>null</code> if this Driver service has successfully attached
+	 *         to the given Device service, or the <code>DRIVER_ID</code> of a
+	 *         more suitable driver
+	 * 
+	 * @throws java.lang.Exception if the driver cannot attach to the given
+	 *            device and does not know of a more suitable driver
+	 */
+	public String attach(ServiceReference reference) throws Exception;
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/device/DriverLocator.java b/org.osgi.compendium/src/main/java/org/osgi/service/device/DriverLocator.java
new file mode 100644
index 0000000..7815ec7
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/device/DriverLocator.java
@@ -0,0 +1,66 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.device/src/org/osgi/service/device/DriverLocator.java,v 1.8 2006/03/14 01:20:43 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2000, 2005). 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.device;
+
+import java.util.Dictionary;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * A Driver Locator service can find and load device driver bundles given a
+ * property set. Each driver is represented by a unique <code>DRIVER_ID</code>.
+ * <p>
+ * Driver Locator services provide the mechanism for dynamically downloading new
+ * device driver bundles into an OSGi environment. They are supplied by
+ * providers and encapsulate all provider-specific details related to the
+ * location and acquisition of driver bundles.
+ * 
+ * @version $Revision: 1.8 $
+ * @see Driver
+ */
+public interface DriverLocator {
+	/**
+	 * Returns an array of <code>DRIVER_ID</code> strings of drivers capable of
+	 * attaching to a device with the given properties.
+	 * 
+	 * <p>
+	 * The property keys in the specified <code>Dictionary</code> objects are
+	 * case-insensitive.
+	 * 
+	 * @param props the properties of the device for which a driver is sought
+	 * @return array of driver <code>DRIVER_ID</code> strings of drivers capable
+	 *         of attaching to a Device service with the given properties, or
+	 *         <code>null</code> if this Driver Locator service does not know of
+	 *         any such drivers
+	 */
+	public String[] findDrivers(Dictionary props);
+
+	/**
+	 * Get an <code>InputStream</code> from which the driver bundle providing a
+	 * driver with the giving <code>DRIVER_ID</code> can be installed.
+	 * 
+	 * @param id the <code>DRIVER_ID</code> of the driver that needs to be
+	 *        installed.
+	 * @return An <code>InputStream</code> object from which the driver bundle can
+	 *         be installed or <code>null</code> if the driver with the given ID
+	 *         cannot be located
+	 * @throws java.io.IOException the input stream for the bundle cannot be
+	 *         created
+	 */
+	public InputStream loadDriver(String id) throws IOException;
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/device/DriverSelector.java b/org.osgi.compendium/src/main/java/org/osgi/service/device/DriverSelector.java
new file mode 100644
index 0000000..e6429af
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/device/DriverSelector.java
@@ -0,0 +1,54 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.device/src/org/osgi/service/device/DriverSelector.java,v 1.8 2006/03/14 01:20:43 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.device;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * When the device manager detects a new Device service, it calls all registered
+ * Driver services to determine if anyone matches the Device service. If at
+ * least one Driver service matches, the device manager must choose one. If
+ * there is a Driver Selector service registered with the Framework, the device
+ * manager will ask it to make the selection. If there is no Driver Selector
+ * service, or if it returns an invalid result, or throws an <code>Exception</code>,
+ * the device manager uses the default selection strategy.
+ * 
+ * @version $Revision: 1.8 $
+ * @since 1.1
+ */
+public interface DriverSelector {
+	/**
+	 * Return value from <code>DriverSelector.select</code>, if no Driver service
+	 * should be attached to the Device service. The value is -1.
+	 */
+	public static final int	SELECT_NONE	= -1;
+
+	/**
+	 * Select one of the matching Driver services. The device manager calls this
+	 * method if there is at least one driver bidding for a device. Only Driver
+	 * services that have responded with nonzero (not {@link Device#MATCH_NONE})
+	 * <code></code> match values will be included in the list.
+	 * 
+	 * @param reference the <code>ServiceReference</code> object of the Device
+	 *        service.
+	 * @param matches the array of all non-zero matches.
+	 * @return index into the array of <code>Match</code> objects, or
+	 *         <code>SELECT_NONE</code> if no Driver service should be attached
+	 */
+	public int select(ServiceReference reference, Match[] matches);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/device/Match.java b/org.osgi.compendium/src/main/java/org/osgi/service/device/Match.java
new file mode 100644
index 0000000..4c0cfcd
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/device/Match.java
@@ -0,0 +1,44 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.device/src/org/osgi/service/device/Match.java,v 1.8 2006/03/14 01:20:43 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.device;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Instances of <code>Match</code> are used in the {@link DriverSelector#select}
+ * method to identify Driver services matching a Device service.
+ * 
+ * @version $Revision: 1.8 $
+ * @since 1.1
+ * @see DriverSelector
+ */
+public interface Match {
+	/**
+	 * Return the reference to a Driver service.
+	 * 
+	 * @return <code>ServiceReference</code> object to a Driver service.
+	 */
+	public ServiceReference getDriver();
+
+	/**
+	 * Return the match value of this object.
+	 * 
+	 * @return the match value returned by this Driver service.
+	 */
+	public int getMatchValue();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/device/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/device/package.html
new file mode 100644
index 0000000..74e11d4
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/device/package.html
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.service.device/src/org/osgi/service/device/package.html,v 1.2 2004/12/01 19:01:15 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Device Access Package. Specification 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.device; version=1.1
+</pre>
+</BODY>
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/device/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/device/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/device/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/event/Event.java b/org.osgi.compendium/src/main/java/org/osgi/service/event/Event.java
new file mode 100644
index 0000000..202e16a
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/event/Event.java
@@ -0,0 +1,199 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.event/src/org/osgi/service/event/Event.java,v 1.6 2006/03/14 01:21:30 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005). 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.event;
+
+import java.util.*;
+
+import org.osgi.framework.Filter;
+
+/**
+ * An event.
+ * 
+ * <code>Event</code> objects are delivered to <code>EventHandler</code>
+ * services which subsrcibe to the topic of the event.
+ * 
+ * @version $Revision: 1.6 $
+ */
+public class Event {
+	/**
+	 * The topic of this event.
+	 */
+	String	topic;
+	/**
+	 * The properties carried by this event. Keys are strings and values are
+	 * objects
+	 */
+	Hashtable	properties;
+
+	/**
+	 * Constructs an event.
+	 * 
+	 * @param topic The topic of the event.
+	 * @param properties The event's properties (may be <code>null</code>).
+	 * 
+	 * @throws IllegalArgumentException If topic is not a valid topic name.
+	 */
+	public Event(String topic, Dictionary properties) {
+		this.topic = topic;
+		validateTopicName();
+		this.properties = new Hashtable();
+		if (properties != null) {
+			for (Enumeration e = properties.keys(); e.hasMoreElements();) {
+				String key = (String) e.nextElement();
+				Object value = properties.get(key);
+				this.properties.put(key, value);
+			}
+		}
+		this.properties.put(EventConstants.EVENT_TOPIC, topic);
+	}
+
+	/**
+	 * Retrieves a property.
+	 * 
+	 * @param name the name of the property to retrieve
+	 * 
+	 * @return The value of the property, or <code>null</code> if not found.
+	 */
+	public final Object getProperty(String name) {
+		return properties.get(name);
+	}
+
+	/**
+	 * Returns a list of this event's property names.
+	 * 
+	 * @return A non-empty array with one element per property.
+	 */
+	public final String[] getPropertyNames() {
+		String[] names = new String[properties.size()];
+		Enumeration keys = properties.keys();
+		for (int i = 0; keys.hasMoreElements(); i++) {
+			names[i] = (String) keys.nextElement();
+		}
+		return names;
+	}
+
+	/**
+	 * Returns the topic of this event.
+	 * 
+	 * @return The topic of this event.
+	 */
+	public final String getTopic() {
+		return topic;
+	}
+
+	/**
+	 * Tests this event's properties against the given filter.
+	 * 
+	 * @param filter The filter to test.
+	 * 
+	 * @return true If this event's properties match the filter, false
+	 *         otherwise.
+	 */
+	public final boolean matches(Filter filter) {
+		return filter.matchCase(properties);
+	}
+
+	/**
+	 * Compares this <code>Event</code> object to another object.
+	 * 
+	 * <p>
+	 * An event is considered to be <b>equal to </b> another
+	 * event if the topic is equal and the properties are equal.
+	 * 
+	 * @param object The <code>Event</code> object to be compared.
+	 * @return <code>true</code> if <code>object</code> is a
+	 *         <code>Event</code> and is equal to this object;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean equals(Object object) {
+		if (object == this) { // quicktest
+			return true;
+		}
+
+		if (!(object instanceof Event)) {
+			return false;
+		}
+
+		Event event = (Event) object;
+		return topic.equals(event.topic) && properties.equals(event.properties);
+	}
+
+	/**
+	 * Returns a hash code value for the object.
+	 * 
+	 * @return An integer which is a hash code value for this object.
+	 */
+	public int hashCode() {
+		return topic.hashCode() ^ properties.hashCode();
+	}
+
+	/**
+	 * Returns the string representation of this event.
+	 * 
+	 * @return The string representation of this event.
+	 */
+	public String toString() {
+		return getClass().getName() + " [topic=" + topic + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	private static final String	SEPARATOR	= "/"; //$NON-NLS-1$
+
+	/**
+	 * Called by the constructor to validate the topic name.
+	 * 
+	 * @throws IllegalArgumentException If the topic name is invalid.
+	 */
+	private void validateTopicName() {
+		try {
+			StringTokenizer st = new StringTokenizer(topic, SEPARATOR, true);
+			validateToken(st.nextToken());
+
+			while (st.hasMoreTokens()) {
+				st.nextToken(); // consume delimiter
+				validateToken(st.nextToken());
+			}
+		}
+		catch (NoSuchElementException e) {
+			throw new IllegalArgumentException("invalid topic"); //$NON-NLS-1$
+		}
+	}
+
+	private static final String	alphaGrammar	= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; //$NON-NLS-1$
+	private static final String	tokenGrammar	= alphaGrammar + "0123456789_"; //$NON-NLS-1$
+
+	/**
+	 * Validate a token.
+	 * 
+	 * @throws IllegalArgumentException If the token is invalid.
+	 */
+	private void validateToken(String token) {
+		int length = token.length();
+		if (length < 1) {
+			throw new IllegalArgumentException("invalid topic"); //$NON-NLS-1$
+		}
+		if (alphaGrammar.indexOf(token.charAt(0)) == -1) { //$NON-NLS-1$
+			throw new IllegalArgumentException("invalid topic"); //$NON-NLS-1$
+		}
+		for (int i = 1; i < length; i++) {
+			if (tokenGrammar.indexOf(token.charAt(i)) == -1) { //$NON-NLS-1$
+				throw new IllegalArgumentException("invalid topic"); //$NON-NLS-1$
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/event/EventAdmin.java b/org.osgi.compendium/src/main/java/org/osgi/service/event/EventAdmin.java
new file mode 100644
index 0000000..01d00e4
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/event/EventAdmin.java
@@ -0,0 +1,53 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.event/src/org/osgi/service/event/EventAdmin.java,v 1.5 2006/03/14 01:21:30 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005). 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.event;
+
+/**
+ * The Event Admin service. Bundles wishing to publish events must obtain the
+ * Event Admin service and call one of the event delivery methods.
+ * 
+ * @version $Revision: 1.5 $
+ */
+public interface EventAdmin {
+	/**
+	 * Initiate asynchronous delivery of an event. This method returns to
+	 * the caller before delivery of the event is completed.
+	 * 
+	 * @param event The event to send to all listeners which subscribe
+	 *        to the topic of the event.
+	 * 
+	 * @throws SecurityException If the caller does not have
+	 *            <code>TopicPermission[topic,PUBLISH]</code> for the topic
+	 *            specified in the event.
+	 */
+	void postEvent(Event event);
+
+	/**
+	 * Initiate synchronous delivery of an event. This method does not
+	 * return to the caller until delivery of the event is completed.
+	 * 
+	 * @param event The event to send to all listeners which subscribe
+	 *        to the topic of the event.
+	 * 
+	 * @throws SecurityException If the caller does not have
+	 *            <code>TopicPermission[topic,PUBLISH]</code> for the topic
+	 *            specified in the event.
+	 */
+	void sendEvent(Event event);
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/event/EventConstants.java b/org.osgi.compendium/src/main/java/org/osgi/service/event/EventConstants.java
new file mode 100644
index 0000000..2481e0a
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/event/EventConstants.java
@@ -0,0 +1,147 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.event/src/org/osgi/service/event/EventConstants.java,v 1.12 2006/03/14 01:21:30 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005). 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.event;
+
+import org.osgi.framework.Constants;
+
+/**
+ * 
+ * Defines standard names for <code>EventHandler</code> properties.
+ * 
+ * @version $Revision: 1.12 $
+ */
+public interface EventConstants {
+
+	/**
+	 * Service registration property (named <code>event.topic</code>)
+	 * specifying the <code>Event</code> topics of interest to a Event Handler
+	 * service.
+	 * <p>
+	 * Event handlers SHOULD be registered with this property. The value of the
+	 * property is an array of strings that describe the topics in which the
+	 * handler is interested. An asterisk ('*') may be used as a
+	 * trailing wildcard. Event Handlers which do not have a value for this property
+	 * must not receive events. More precisely, the value of each entry in the
+	 * array must conform to the following grammar:
+	 * 
+	 * <pre>
+	 *          topic-description := '*' | topic ( '/*' )?
+	 *          topic := token ( '/' token )*
+	 * </pre>
+	 * 
+	 * @see Event
+	 */
+	public static final String	EVENT_TOPIC			= "event.topics";
+
+	/**
+	 * Service Registration property (named <code>event.filter</code>)
+	 * specifying a filter to further select <code>Event</code> s of interest
+	 * to a Event Handler service.
+	 * <p>
+	 * Event handlers MAY be registered with this property. The value of this
+	 * property is a string containing an LDAP-style filter specification. Any
+	 * of the event's properties may be used in the filter expression. Each
+	 * event handler is notified for any event which belongs to the topics in
+	 * which the handler has expressed an interest. If the event handler is also
+	 * registered with this service property, then the properties of the event
+	 * must also match the filter for the event to be delivered to the event
+	 * handler.
+	 * <p>
+	 * If the filter syntax is invalid, then the Event Handler must be ignored and a 
+	 * warning should be logged.
+	 * 
+	 * @see Event
+	 * @see org.osgi.framework.Filter
+	 */
+	public static final String	EVENT_FILTER		= "event.filter";
+
+	/**
+	 * The Distinguished Name of the bundle relevant to the event.
+	 */
+	public static final String	BUNDLE_SIGNER		= "bundle.signer";
+
+	/**
+	 * The Bundle Symbolic Name of the bundle relevant to the event.
+	 */
+	public static final String	BUNDLE_SYMBOLICNAME	= "bundle.symbolicName";
+
+	/**
+	 * The actual event object. Used when rebroadcasting an event that was sent
+	 * via some other event mechanism.
+	 */
+	public static final String	EVENT				= "event";
+
+	/**
+	 * An exception or error.
+	 */
+	public static final String	EXCEPTION			= "exception";
+
+	/**
+	 * Must be equal to the name of the Exception class.
+	 */
+	public static final String	EXCEPTION_CLASS		= "exception.class";
+	
+	/**
+	 * This constant was released with an incorrect spelling. It has been
+	 * replaced by {@link #EXCEPTION_CLASS}
+	 * @deprecated As of 1.0.1, replaced by EXCEPTION_CLASS
+	 */
+	public static final String	EXECPTION_CLASS		= "exception.class";
+
+	/**
+	 * Must be equal to exception.getMessage()
+	 */
+	public static final String	EXCEPTION_MESSAGE	= "exception.message";
+
+	/**
+	 * A human-readable message that is usually not localized.
+	 */
+	public static final String	MESSAGE				= "message";
+
+	/**
+	 * A service
+	 */
+
+	public static final String	SERVICE				= "service";
+
+	/**
+	 * A service’s id.
+	 */
+	public static final String	SERVICE_ID			= Constants.SERVICE_ID;
+
+	/**
+	 * 
+	 * A service's objectClass
+	 */
+	public static final String	SERVICE_OBJECTCLASS	= "service.objectClass";
+
+	/**
+	 * 
+	 * A service’s persistent identity.
+	 */
+	public static final String	SERVICE_PID			= Constants.SERVICE_PID;
+
+	/**
+	 * 
+	 * The time when the event occurred, as reported by
+	 * System.currentTimeMillis()
+	 */
+	public static final String	TIMESTAMP			= "timestamp";
+
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/event/EventHandler.java b/org.osgi.compendium/src/main/java/org/osgi/service/event/EventHandler.java
new file mode 100644
index 0000000..a964f1b
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/event/EventHandler.java
@@ -0,0 +1,67 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.event/src/org/osgi/service/event/EventHandler.java,v 1.8 2006/03/14 01:21:30 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005). 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.event;
+
+/**
+ * Listener for Events.
+ * 
+ * <p>
+ * <code>EventHandler</code> objects are registered with the Framework service
+ * registry and are notified with an <code>Event</code> object when an
+ * event is sent or posted.
+ * <p>
+ * <code>EventHandler</code> objects can inspect the received
+ * <code>Event</code> object to determine its topic and properties.
+ * 
+ * <p>
+ * <code>EventHandler</code> objects must be registered with a service
+ * property {@link EventConstants#EVENT_TOPIC} whose value is the list of
+ * topics in which the event handler is interesed.
+ * <p>
+ * For example:
+ * 
+ * <pre>
+ * String[] topics = new String[] {EventConstants.EVENT_TOPIC, &quot;com/isv/*&quot;};
+ * Hashtable ht = new Hashtable();
+ * ht.put(EVENT_TOPIC, topics);
+ * context.registerService(EventHandler.class.getName(), this, ht);
+ * </pre>
+ * Event Handler services can also be registered with an @link EventConstants#EVENT_FILTER}
+ * service propery to further filter the events. If the syntax of this filter is invalid,
+ * then the Event Handler must be ignored by the Event Admin service. The Event Admin
+ * service should log a warning.
+ * <p>
+ * Security Considerations. Bundles wishing to monitor <code>Event</code>
+ * objects will require <code>ServicePermission[EventHandler,REGISTER]</code>
+ * to register an <code>EventHandler</code> service. The bundle must also have
+ * <code>TopicPermission[topic,SUBSCRIBE]</code> for the topic specified in the
+ * event in order to receive the event.
+ * 
+ * @see Event
+ * 
+ * @version $Revision: 1.8 $
+ */
+public interface EventHandler {
+	/**
+	 * Called by the {@link EventAdmin} service to notify the listener of an event.
+	 * 
+	 * @param event The event that occurred.
+	 */
+	void handleEvent(Event event);
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/event/TopicPermission.java b/org.osgi.compendium/src/main/java/org/osgi/service/event/TopicPermission.java
new file mode 100644
index 0000000..334d80d
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/event/TopicPermission.java
@@ -0,0 +1,506 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.event/src/org/osgi/service/event/TopicPermission.java,v 1.10 2006/03/14 01:21:30 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005). 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.event;
+
+import java.io.IOException;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * A bundle's authority to publish or subscribe to event on a topic.
+ * 
+ * <p>
+ * A topic is a slash-separated string that defines a topic.
+ * <p>
+ * For example:
+ * 
+ * <pre>
+ * org/osgi/service/foo/FooEvent/ACTION
+ * </pre>
+ * 
+ * <p>
+ * <code>TopicPermission</code> has two actions: <code>publish</code> and
+ * <code>subscribe</code>.
+ * 
+ * @version $Revision: 1.10 $
+ */
+public final class TopicPermission extends Permission {
+	static final long			serialVersionUID	= -5855563886961618300L;
+	/**
+	 * The action string <code>publish</code>.
+	 */
+	public final static String	PUBLISH				= "publish";				//$NON-NLS-1$
+	/**
+	 * The action string <code>subscribe</code>.
+	 */
+	public final static String	SUBSCRIBE			= "subscribe";				//$NON-NLS-1$
+	private final static int	ACTION_PUBLISH		= 0x00000001;
+	private final static int	ACTION_SUBSCRIBE	= 0x00000002;
+	private final static int	ACTION_ALL			= ACTION_PUBLISH
+															| ACTION_SUBSCRIBE;
+	private final static int	ACTION_NONE			= 0;
+	/**
+	 * The actions mask.
+	 */
+	private transient int		action_mask			= ACTION_NONE;
+
+	/**
+	 * prefix if the name is wildcarded.
+	 */
+	private transient String	prefix;
+
+	/**
+	 * The actions in canonical form.
+	 * 
+	 * @serial
+	 */
+	private String				actions				= null;
+
+	/**
+	 * Defines the authority to publich and/or subscribe to a topic within the
+	 * EventAdmin service.
+	 * <p>
+	 * The name is specified as a slash-separated string. Wildcards may be used.
+	 * For example:
+	 * 
+	 * <pre>
+	 *    org/osgi/service/fooFooEvent/ACTION
+	 *    com/isv/*
+	 *    *
+	 * </pre>
+	 * 
+	 * <p>
+	 * A bundle that needs to publish events on a topic must have the
+	 * appropriate <code>TopicPermission</code> for that topic; similarly, a
+	 * bundle that needs to subscribe to events on a topic must have the
+	 * appropriate <code>TopicPermssion</code> for that topic.
+	 * <p>
+	 * 
+	 * @param name Topic name.
+	 * @param actions <code>publish</code>,<code>subscribe</code>
+	 *        (canonical order).
+	 */
+	public TopicPermission(String name, String actions) {
+		this(name, getMask(actions));
+	}
+
+	/**
+	 * Package private constructor used by TopicPermissionCollection.
+	 * 
+	 * @param name class name
+	 * @param mask action mask
+	 */
+	TopicPermission(String name, int mask) {
+		super(name);
+		init(name, mask);
+	}
+
+	/**
+	 * Called by constructors and when deserialized.
+	 * 
+	 * @param name topic name
+	 * @param mask action mask
+	 */
+	private void init(String name, int mask) {
+		if ((name == null) || name.length() == 0) {
+			throw new IllegalArgumentException("invalid name"); //$NON-NLS-1$
+		}
+
+		if (name.equals("*")) {
+			prefix = "";
+		}
+		else
+			if (name.endsWith("/*")) {
+				prefix = name.substring(0, name.length() - 1);
+			}
+			else {
+				prefix = null;
+			}
+
+		if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
+			throw new IllegalArgumentException("invalid action string"); //$NON-NLS-1$
+		}
+		action_mask = mask;
+	}
+
+	/**
+	 * Parse action string into action mask.
+	 * 
+	 * @param actions Action string.
+	 * @return action mask.
+	 */
+	private static int getMask(String actions) {
+		boolean seencomma = false;
+		int mask = ACTION_NONE;
+		if (actions == null) {
+			return mask;
+		}
+		char[] a = actions.toCharArray();
+		int i = a.length - 1;
+		if (i < 0)
+			return mask;
+		while (i != -1) {
+			char c;
+			// skip whitespace
+			while ((i != -1)
+					&& ((c = a[i]) == ' ' || c == '\r' || c == '\n'
+							|| c == '\f' || c == '\t'))
+				i--;
+			// check for the known strings
+			int matchlen;
+			if (i >= 8 && (a[i - 8] == 's' || a[i - 8] == 'S')
+					&& (a[i - 7] == 'u' || a[i - 7] == 'U')
+					&& (a[i - 6] == 'b' || a[i - 6] == 'B')
+					&& (a[i - 5] == 's' || a[i - 5] == 'S')
+					&& (a[i - 4] == 'c' || a[i - 4] == 'C')
+					&& (a[i - 3] == 'r' || a[i - 3] == 'R')
+					&& (a[i - 2] == 'i' || a[i - 2] == 'I')
+					&& (a[i - 1] == 'b' || a[i - 1] == 'B')
+					&& (a[i] == 'e' || a[i] == 'E')) {
+				matchlen = 9;
+				mask |= ACTION_SUBSCRIBE;
+			}
+			else
+				if (i >= 6 && (a[i - 6] == 'p' || a[i - 6] == 'P')
+						&& (a[i - 5] == 'u' || a[i - 5] == 'U')
+						&& (a[i - 4] == 'b' || a[i - 4] == 'B')
+						&& (a[i - 3] == 'l' || a[i - 3] == 'L')
+						&& (a[i - 2] == 'i' || a[i - 2] == 'I')
+						&& (a[i - 1] == 's' || a[i - 1] == 'S')
+						&& (a[i] == 'h' || a[i] == 'H')) {
+					matchlen = 7;
+					mask |= ACTION_PUBLISH;
+				}
+				else {
+					// parse error
+					throw new IllegalArgumentException("invalid permission: " //$NON-NLS-1$
+							+ actions);
+				}
+			// make sure we didn't just match the tail of a word
+			// like "ackbarfpublish". 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); //$NON-NLS-1$
+				}
+				i--;
+			}
+			// point i at the location of the comma minus one (or -1).
+			i -= matchlen;
+		}
+		if (seencomma) {
+			throw new IllegalArgumentException("invalid permission: " + actions); //$NON-NLS-1$
+		}
+		return mask;
+	}
+
+	/**
+	 * Determines if the specified permission is implied by this object.
+	 * 
+	 * <p>
+	 * This method checks that the topic name of the target is implied by the
+	 * topic name of this object. The list of <code>TopicPermission</code>
+	 * actions must either match or allow for the list of the target object to
+	 * imply the target <code>TopicPermission</code> action.
+	 * 
+	 * <pre>
+	 *    x/y/*,&quot;publish&quot; -&gt; x/y/z,&quot;publish&quot; is true
+	 *    *,&quot;subscribe&quot; -&gt; x/y,&quot;subscribe&quot;   is true
+	 *    *,&quot;publish&quot; -&gt; x/y,&quot;subscribe&quot;     is false
+	 *    x/y,&quot;publish&quot; -&gt; x/y/z,&quot;publish&quot;   is false
+	 * </pre>
+	 * 
+	 * @param p The target permission to interrogate.
+	 * @return <code>true</code> if the specified <code>TopicPermission</code>
+	 *         action is implied by this object; <code>false</code> otherwise.
+	 */
+	public boolean implies(Permission p) {
+		if (p instanceof TopicPermission) {
+			TopicPermission target = (TopicPermission) p;
+			if ((action_mask & target.action_mask) == target.action_mask) {
+				if (prefix != null) {
+					return target.getName().startsWith(prefix);
+				}
+
+				return target.getName().equals(getName());
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Returns the canonical string representation of the
+	 * <code>TopicPermission</code> actions.
+	 * 
+	 * <p>
+	 * Always returns present <code>TopicPermission</code> actions in the
+	 * following order: <code>publish</code>,<code>subscribe</code>.
+	 * 
+	 * @return Canonical string representation of the
+	 *         <code>TopicPermission</code> actions.
+	 */
+	public String getActions() {
+		if (actions == null) {
+			StringBuffer sb = new StringBuffer();
+			boolean comma = false;
+			if ((action_mask & ACTION_PUBLISH) == ACTION_PUBLISH) {
+				sb.append(PUBLISH);
+				comma = true;
+			}
+			if ((action_mask & ACTION_SUBSCRIBE) == ACTION_SUBSCRIBE) {
+				if (comma)
+					sb.append(',');
+				sb.append(SUBSCRIBE);
+			}
+			actions = sb.toString();
+		}
+		return actions;
+	}
+
+	/**
+	 * Returns a new <code>PermissionCollection</code> object suitable for
+	 * storing <code>TopicPermission</code> objects.
+	 * 
+	 * @return A new <code>PermissionCollection</code> object.
+	 */
+	public PermissionCollection newPermissionCollection() {
+		return new TopicPermissionCollection();
+	}
+
+	/**
+	 * Determines the equality of two <code>TopicPermission</code> objects.
+	 * 
+	 * This method checks that specified <code>TopicPermission</code> has the same topic name and
+	 * actions as this
+	 * <code>TopicPermission</code> object.
+	 * 
+	 * @param obj The object to test for equality with this
+	 *        <code>TopicPermission</code> object.
+	 * @return <code>true</code> if <code>obj</code> is a
+	 *         <code>TopicPermission</code>, and has the same topic name and
+	 *         actions as this <code>TopicPermission</code> object;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+		if (!(obj instanceof TopicPermission)) {
+			return false;
+		}
+		TopicPermission p = (TopicPermission) obj;
+		return (action_mask == p.action_mask) && getName().equals(p.getName());
+	}
+
+	/**
+	 * Returns the hash code value for this object.
+	 * 
+	 * @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 TopicPermissionCollection class.
+	 * 
+	 * @return Current action mask.
+	 */
+	int getMask() {
+		return action_mask;
+	}
+
+	/**
+	 * 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 {
+		// Write out the actions. The superclass takes care of the name
+		// call getActions to make sure actions field is initialized
+		if (actions == null)
+			getActions();
+		s.defaultWriteObject();
+	}
+
+	/**
+	 * readObject is called to restore the state of this permission from a
+	 * stream.
+	 */
+	private synchronized void readObject(java.io.ObjectInputStream s)
+			throws IOException, ClassNotFoundException {
+		// Read in the action, then initialize the rest
+		s.defaultReadObject();
+		init(getName(), getMask(actions));
+	}
+}
+
+/**
+ * Stores a set of <code>TopicPermission</code> permissions.
+ * 
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ */
+final class TopicPermissionCollection extends PermissionCollection {
+	static final long	serialVersionUID	= -614647783533924048L;
+	/**
+	 * Table of permissions.
+	 * 
+	 * @serial
+	 */
+	private Hashtable	permissions;
+	/**
+	 * Boolean saying if "*" is in the collection.
+	 * 
+	 * @serial
+	 */
+	private boolean		all_allowed;
+
+	/**
+	 * Create an empty TopicPermissions object.
+	 * 
+	 */
+	public TopicPermissionCollection() {
+		permissions = new Hashtable();
+		all_allowed = false;
+	}
+
+	/**
+	 * Adds a permission to the <code>TopicPermission</code> objects. The key
+	 * for the hash is the name.
+	 * 
+	 * @param permission The <code>TopicPermission</code> object to add.
+	 * 
+	 * @throws IllegalArgumentException If the permission is not a
+	 *            <code>TopicPermission</code> instance.
+	 * 
+	 * @throws SecurityException If this
+	 *            <code>TopicPermissionCollection</code> object has been
+	 *            marked read-only.
+	 */
+	public void add(Permission permission) {
+		if (!(permission instanceof TopicPermission))
+			throw new IllegalArgumentException("invalid permission: " //$NON-NLS-1$
+					+ permission);
+		if (isReadOnly())
+			throw new SecurityException("attempt to add a Permission to a " //$NON-NLS-1$
+					+ "readonly PermissionCollection"); //$NON-NLS-1$
+		TopicPermission pp = (TopicPermission) permission;
+		String name = pp.getName();
+		TopicPermission existing = (TopicPermission) permissions.get(name);
+		if (existing != null) {
+			int oldMask = existing.getMask();
+			int newMask = pp.getMask();
+			if (oldMask != newMask) {
+				permissions.put(name, new TopicPermission(name, oldMask
+						| newMask));
+			}
+		}
+		else {
+			permissions.put(name, permission);
+		}
+		if (!all_allowed) {
+			if (name.equals("*")) //$NON-NLS-1$
+				all_allowed = true;
+		}
+	}
+
+	/**
+	 * Determines if the specified permissions implies the permissions expressed
+	 * in <code>permission</code>.
+	 * 
+	 * @param permission The Permission object to compare with this
+	 *        <code>TopicPermission</code> object.
+	 * 
+	 * @return <code>true</code> if <code>permission</code> is a proper
+	 *         subset of a permission in the set; <code>false</code>
+	 *         otherwise.
+	 */
+	public boolean implies(Permission permission) {
+		if (!(permission instanceof TopicPermission))
+			return false;
+		TopicPermission pp = (TopicPermission) permission;
+		TopicPermission x;
+		int desired = pp.getMask();
+		int effective = 0;
+		// short circuit if the "*" Permission was added
+		if (all_allowed) {
+			x = (TopicPermission) permissions.get("*"); //$NON-NLS-1$
+			if (x != null) {
+				effective |= x.getMask();
+				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 = pp.getName();
+		x = (TopicPermission) 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) { //$NON-NLS-1$
+			name = name.substring(0, last + 1) + "*"; //$NON-NLS-1$
+			x = (TopicPermission) 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;
+	}
+
+	/**
+	 * Returns an enumeration of all <code>TopicPermission</code> objects in
+	 * the container.
+	 * 
+	 * @return Enumeration of all <code>TopicPermission</code> objects.
+	 */
+	public Enumeration elements() {
+		return permissions.elements();
+	}
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/event/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/event/package.html
new file mode 100644
index 0000000..f22b7e5
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/event/package.html
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.service.event/src/org/osgi/service/event/package.html,v 1.6 2005/11/01 18:55:09 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Event Admin Specification Version 1.0.1.
+<p>Bundles wishing to use this package must list the package
+in the <TT>Import-Package</TT> header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.event; version=1.0.1
+</pre>
+</BODY>
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/event/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/event/packageinfo
new file mode 100644
index 0000000..b3d1f97
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/event/packageinfo
@@ -0,0 +1 @@
+version 1.0.1
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/http/HttpContext.java b/org.osgi.compendium/src/main/java/org/osgi/service/http/HttpContext.java
new file mode 100644
index 0000000..d5a0eb5
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/http/HttpContext.java
@@ -0,0 +1,167 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.http/src/org/osgi/service/http/HttpContext.java,v 1.9 2006/03/14 01:20:39 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2000, 2005). 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.http;
+
+import java.io.IOException;
+import java.net.URL;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * This interface defines methods that the Http Service may call to get
+ * information about a registration.
+ * 
+ * <p>
+ * Servlets and resources may be registered with an <code>HttpContext</code>
+ * object; if no <code>HttpContext</code> object is specified, a default
+ * <code>HttpContext</code> object is used. Servlets that are registered using the
+ * same <code>HttpContext</code> object will share the same
+ * <code>ServletContext</code> object.
+ * 
+ * <p>
+ * This interface is implemented by users of the <code>HttpService</code>.
+ * 
+ * @version $Revision: 1.9 $
+ */
+public interface HttpContext {
+	/**
+	 * <code>HttpServletRequest</code> attribute specifying the name of the
+	 * authenticated user. The value of the attribute can be retrieved by
+	 * <code>HttpServletRequest.getRemoteUser</code>. This attribute name is
+	 * <code>org.osgi.service.http.authentication.remote.user</code>.
+	 * 
+	 * @since 1.1
+	 */
+	public static final String	REMOTE_USER			= "org.osgi.service.http.authentication.remote.user";
+	/**
+	 * <code>HttpServletRequest</code> attribute specifying the scheme used in
+	 * authentication. The value of the attribute can be retrieved by
+	 * <code>HttpServletRequest.getAuthType</code>. This attribute name is
+	 * <code>org.osgi.service.http.authentication.type</code>.
+	 * 
+	 * @since 1.1
+	 */
+	public static final String	AUTHENTICATION_TYPE	= "org.osgi.service.http.authentication.type";
+	/**
+	 * <code>HttpServletRequest</code> attribute specifying the
+	 * <code>Authorization</code> object obtained from the
+	 * <code>org.osgi.service.useradmin.UserAdmin</code> service. The value of the
+	 * attribute can be retrieved by
+	 * <code>HttpServletRequest.getAttribute(HttpContext.AUTHORIZATION)</code>.
+	 * This attribute name is <code>org.osgi.service.useradmin.authorization</code>.
+	 * 
+	 * @since 1.1
+	 */
+	public static final String	AUTHORIZATION		= "org.osgi.service.useradmin.authorization";
+
+	/**
+	 * Handles security for the specified request.
+	 * 
+	 * <p>
+	 * The Http Service calls this method prior to servicing the specified
+	 * request. This method controls whether the request is processed in the
+	 * normal manner or an error is returned.
+	 * 
+	 * <p>
+	 * If the request requires authentication and the Authorization header in
+	 * the request is missing or not acceptable, then this method should set the
+	 * WWW-Authenticate header in the response object, set the status in the
+	 * response object to Unauthorized(401) and return <code>false</code>. See
+	 * also RFC 2617: <i>HTTP Authentication: Basic and Digest Access
+	 * Authentication </i> (available at http://www.ietf.org/rfc/rfc2617.txt).
+	 * 
+	 * <p>
+	 * If the request requires a secure connection and the <code>getScheme</code>
+	 * method in the request does not return 'https' or some other acceptable
+	 * secure protocol, then this method should set the status in the response
+	 * object to Forbidden(403) and return <code>false</code>.
+	 * 
+	 * <p>
+	 * When this method returns <code>false</code>, the Http Service will send
+	 * the response back to the client, thereby completing the request. When
+	 * this method returns <code>true</code>, the Http Service will proceed with
+	 * servicing the request.
+	 * 
+	 * <p>
+	 * If the specified request has been authenticated, this method must set the
+	 * {@link #AUTHENTICATION_TYPE}request attribute to the type of
+	 * authentication used, and the {@link #REMOTE_USER}request attribute to
+	 * the remote user (request attributes are set using the
+	 * <code>setAttribute</code> method on the request). If this method does not
+	 * perform any authentication, it must not set these attributes.
+	 * 
+	 * <p>
+	 * If the authenticated user is also authorized to access certain resources,
+	 * this method must set the {@link #AUTHORIZATION}request attribute to the
+	 * <code>Authorization</code> object obtained from the
+	 * <code>org.osgi.service.useradmin.UserAdmin</code> service.
+	 * 
+	 * <p>
+	 * The servlet responsible for servicing the specified request determines
+	 * the authentication type and remote user by calling the
+	 * <code>getAuthType</code> and <code>getRemoteUser</code> methods,
+	 * respectively, on the request.
+	 * 
+	 * @param request the HTTP request
+	 * @param response the HTTP response
+	 * @return <code>true</code> if the request should be serviced, <code>false</code>
+	 *         if the request should not be serviced and Http Service will send
+	 *         the response back to the client.
+	 * @throws java.io.IOException may be thrown by this method. If this
+	 *            occurs, the Http Service will terminate the request and close
+	 *            the socket.
+	 */
+	public boolean handleSecurity(HttpServletRequest request,
+			HttpServletResponse response) throws IOException;
+
+	/**
+	 * Maps a resource name to a URL.
+	 * 
+	 * <p>
+	 * Called by the Http Service to map a resource name to a URL. For servlet
+	 * registrations, Http Service will call this method to support the
+	 * <code>ServletContext</code> methods <code>getResource</code> and
+	 * <code>getResourceAsStream</code>. For resource registrations, Http Service
+	 * will call this method to locate the named resource. The context can
+	 * control from where resources come. For example, the resource can be
+	 * mapped to a file in the bundle's persistent storage area via
+	 * <code>bundleContext.getDataFile(name).toURL()</code> or to a resource in
+	 * the context's bundle via <code>getClass().getResource(name)</code>
+	 * 
+	 * @param name the name of the requested resource
+	 * @return URL that Http Service can use to read the resource or
+	 *         <code>null</code> if the resource does not exist.
+	 */
+	public URL getResource(String name);
+
+	/**
+	 * Maps a name to a MIME type.
+	 * 
+	 * Called by the Http Service to determine the MIME type for the name. For
+	 * servlet registrations, the Http Service will call this method to support
+	 * the <code>ServletContext</code> method <code>getMimeType</code>. For
+	 * resource registrations, the Http Service will call this method to
+	 * determine the MIME type for the Content-Type header in the response.
+	 * 
+	 * @param name determine the MIME type for this name.
+	 * @return MIME type (e.g. text/html) of the name or <code>null</code> to
+	 *         indicate that the Http Service should determine the MIME type
+	 *         itself.
+	 */
+	public String getMimeType(String name);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/http/HttpService.java b/org.osgi.compendium/src/main/java/org/osgi/service/http/HttpService.java
new file mode 100644
index 0000000..95acce9
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/http/HttpService.java
@@ -0,0 +1,177 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.http/src/org/osgi/service/http/HttpService.java,v 1.10 2006/03/14 01:20:39 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2000, 2005). 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.http;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import java.util.Dictionary;
+
+/**
+ * The Http Service allows other bundles in the OSGi environment to dynamically
+ * register resources and servlets into the URI namespace of Http Service. A
+ * bundle may later unregister its resources or servlets.
+ * 
+ * @version $Revision: 1.10 $
+ * @see HttpContext
+ */
+public interface HttpService {
+	/**
+	 * Registers a servlet into the URI namespace.
+	 * 
+	 * <p>
+	 * The alias is the name in the URI namespace of the Http Service at which
+	 * the registration will be mapped.
+	 * 
+	 * <p>
+	 * An alias must begin with slash ('/') and must not end with slash ('/'),
+	 * with the exception that an alias of the form &quot;/&quot; is used to
+	 * denote the root alias. See the specification text for details on how HTTP
+	 * requests are mapped to servlet and resource registrations.
+	 * 
+	 * <p>
+	 * The Http Service will call the servlet's <code>init</code> method before
+	 * returning.
+	 * 
+	 * <pre>
+	 * httpService.registerServlet(&quot;/myservlet&quot;, servlet, initparams, context);
+	 * </pre>
+	 * 
+	 * <p>
+	 * Servlets registered with the same <code>HttpContext</code> object will
+	 * share the same <code>ServletContext</code>. The Http Service will call the
+	 * <code>context</code> argument to support the <code>ServletContext</code>
+	 * methods <code>getResource</code>,<code>getResourceAsStream</code> and
+	 * <code>getMimeType</code>, and to handle security for requests. If the
+	 * <code>context</code> argument is <code>null</code>, a default
+	 * <code>HttpContext</code> object is used (see
+	 * {@link #createDefaultHttpContext}).
+	 * 
+	 * @param alias name in the URI namespace at which the servlet is registered
+	 * @param servlet the servlet object to register
+	 * @param initparams initialization arguments for the servlet or
+	 *        <code>null</code> if there are none. This argument is used by the
+	 *        servlet's <code>ServletConfig</code> object.
+	 * @param context the <code>HttpContext</code> object for the registered
+	 *        servlet, or <code>null</code> if a default <code>HttpContext</code> is
+	 *        to be created and used.
+	 * @throws NamespaceException if the registration fails because the alias
+	 *            is already in use.
+	 * @throws javax.servlet.ServletException if the servlet's <code>init</code>
+	 *            method throws an exception, or the given servlet object has
+	 *            already been registered at a different alias.
+	 * @throws java.lang.IllegalArgumentException if any of the arguments are
+	 *            invalid
+	 */
+	public void registerServlet(String alias, Servlet servlet,
+			Dictionary initparams, HttpContext context)
+			throws ServletException, NamespaceException;
+
+	/**
+	 * Registers resources into the URI namespace.
+	 * 
+	 * <p>
+	 * The alias is the name in the URI namespace of the Http Service at which
+	 * the registration will be mapped. An alias must begin with slash ('/') and
+	 * must not end with slash ('/'), with the exception that an alias of the
+	 * form &quot;/&quot; is used to denote the root alias. The name parameter
+	 * must also not end with slash ('/'). See the specification text for
+	 * details on how HTTP requests are mapped to servlet and resource
+	 * registrations.
+	 * <p>
+	 * For example, suppose the resource name /tmp is registered to the alias
+	 * /files. A request for /files/foo.txt will map to the resource name
+	 * /tmp/foo.txt.
+	 * 
+	 * <pre>
+	 * httpservice.registerResources(&quot;/files&quot;, &quot;/tmp&quot;, context);
+	 * </pre>
+	 * 
+	 * The Http Service will call the <code>HttpContext</code> argument to map
+	 * resource names to URLs and MIME types and to handle security for
+	 * requests. If the <code>HttpContext</code> argument is <code>null</code>, a
+	 * default <code>HttpContext</code> is used (see
+	 * {@link #createDefaultHttpContext}).
+	 * 
+	 * @param alias name in the URI namespace at which the resources are
+	 *        registered
+	 * @param name the base name of the resources that will be registered
+	 * @param context the <code>HttpContext</code> object for the registered
+	 *        resources, or <code>null</code> if a default <code>HttpContext</code>
+	 *        is to be created and used.
+	 * @throws NamespaceException if the registration fails because the alias
+	 *            is already in use.
+	 * @throws java.lang.IllegalArgumentException if any of the parameters
+	 *            are invalid
+	 */
+	public void registerResources(String alias, String name,
+			HttpContext context) throws NamespaceException;
+
+	/**
+	 * Unregisters a previous registration done by <code>registerServlet</code> or
+	 * <code>registerResources</code> methods.
+	 * 
+	 * <p>
+	 * After this call, the registered alias in the URI name-space will no
+	 * longer be available. If the registration was for a servlet, the Http
+	 * Service must call the <code>destroy</code> method of the servlet before
+	 * returning.
+	 * <p>
+	 * If the bundle which performed the registration is stopped or otherwise
+	 * "unget"s the Http Service without calling {@link #unregister}then Http
+	 * Service must automatically unregister the registration. However, if the
+	 * registration was for a servlet, the <code>destroy</code> method of the
+	 * servlet will not be called in this case since the bundle may be stopped.
+	 * {@link #unregister}must be explicitly called to cause the
+	 * <code>destroy</code> method of the servlet to be called. This can be done
+	 * in the <code>BundleActivator.stop</code> method of the
+	 * bundle registering the servlet.
+	 * 
+	 * @param alias name in the URI name-space of the registration to unregister
+	 * @throws java.lang.IllegalArgumentException if there is no registration
+	 *            for the alias or the calling bundle was not the bundle which
+	 *            registered the alias.
+	 */
+	public void unregister(String alias);
+
+	/**
+	 * Creates a default <code>HttpContext</code> for registering servlets or
+	 * resources with the HttpService, a new <code>HttpContext</code> object is
+	 * created each time this method is called.
+	 * 
+	 * <p>
+	 * The behavior of the methods on the default <code>HttpContext</code> is
+	 * defined as follows:
+	 * <ul>
+	 * <li><code>getMimeType</code>- Does not define any customized MIME types
+	 * for the Content-Type header in the response, and always returns
+	 * <code>null</code>.
+	 * <li><code>handleSecurity</code>- Performs implementation-defined
+	 * authentication on the request.
+	 * <li><code>getResource</code>- Assumes the named resource is in the
+	 * context bundle; this method calls the context bundle's
+	 * <code>Bundle.getResource</code> method, and returns the appropriate URL to
+	 * access the resource. On a Java runtime environment that supports
+	 * permissions, the Http Service needs to be granted 
+	 * <code>org.osgi.framework.AdminPermission[*,RESOURCE]</code>.
+	 * </ul>
+	 * 
+	 * @return a default <code>HttpContext</code> object.
+	 * @since 1.1
+	 */
+	public HttpContext createDefaultHttpContext();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/http/NamespaceException.java b/org.osgi.compendium/src/main/java/org/osgi/service/http/NamespaceException.java
new file mode 100644
index 0000000..c8e7889
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/http/NamespaceException.java
@@ -0,0 +1,95 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.http/src/org/osgi/service/http/NamespaceException.java,v 1.9 2006/03/14 01:20:39 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2000, 2005). 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.http;
+
+/**
+ * A NamespaceException is thrown to indicate an error with the caller's request
+ * to register a servlet or resources into the URI namespace of the Http
+ * Service. This exception indicates that the requested alias already is in use.
+ * 
+ * @version $Revision: 1.9 $
+ */
+public class NamespaceException extends Exception {
+    static final long serialVersionUID = 7235606031147877747L;
+	/**
+	 * Nested exception.
+	 */
+	private Throwable	cause;
+
+	/**
+	 * Construct a <code>NamespaceException</code> object with a detail message.
+	 * 
+	 * @param message the detail message
+	 */
+	public NamespaceException(String message) {
+		super(message);
+		cause = null;
+	}
+
+	/**
+	 * Construct a <code>NamespaceException</code> object with a detail message
+	 * and a nested exception.
+	 * 
+	 * @param message The detail message.
+	 * @param cause The nested exception.
+	 */
+	public NamespaceException(String message, Throwable cause) {
+		super(message);
+		this.cause = cause;
+	}
+
+	/**
+	 * Returns the nested exception.
+	 *
+     * <p>This method predates the general purpose exception chaining mechanism.
+     * The {@link #getCause()} method is now the preferred means of
+     * obtaining this information.
+	 * 
+	 * @return the nested exception or <code>null</code> if there is no nested
+	 *         exception.
+	 */
+	public Throwable getException() {
+		return cause;
+	}
+
+	/**
+	 * Returns the cause of this exception or <code>null</code> if no
+	 * cause was specified when this exception was created.
+	 *
+	 * @return  The cause of this exception or <code>null</code> if no
+	 * cause was specified.
+	 * @since 1.2 
+	 */
+	public Throwable getCause() {
+	    return cause;
+	}
+
+	/**
+	 * The cause of this exception can only be set when constructed.
+	 *
+	 * @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.
+	 * @since 1.2 
+	 */
+	public Throwable initCause(Throwable cause) {
+		throw new IllegalStateException();
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/http/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/http/package.html
new file mode 100644
index 0000000..79dfae9
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/http/package.html
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.service.http/src/org/osgi/service/http/package.html,v 1.3 2004/12/09 19:44:20 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Http Service Package. Specification Version 1.2.
+<p>Bundles wishing to use this package must list the package
+in the <TT>Import-Package</TT> header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.http; version=1.2
+</pre>
+</BODY>
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/http/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/http/packageinfo
new file mode 100644
index 0000000..ef7df68
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/http/packageinfo
@@ -0,0 +1 @@
+version 1.2
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/io/ConnectionFactory.java b/org.osgi.compendium/src/main/java/org/osgi/service/io/ConnectionFactory.java
new file mode 100644
index 0000000..cb7c396
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/io/ConnectionFactory.java
@@ -0,0 +1,61 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.io/src/org/osgi/service/io/ConnectionFactory.java,v 1.6 2006/03/14 01:20:44 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.io;
+
+import javax.microedition.io.*;
+import java.io.*;
+
+/**
+ * A Connection Factory service is called by the implementation of the Connector
+ * Service to create <code>javax.microedition.io.Connection</code> objects which
+ * implement the scheme named by <code>IO_SCHEME</code>.
+ * 
+ * When a <code>ConnectorService.open</code> method is called, the implementation
+ * of the Connector Service will examine the specified name for a scheme. The
+ * Connector Service will then look for a Connection Factory service which is
+ * registered with the service property <code>IO_SCHEME</code> which matches the
+ * scheme. The {@link #createConnection}method of the selected Connection
+ * Factory will then be called to create the actual <code>Connection</code>
+ * object.
+ * 
+ * @version $Revision: 1.6 $
+ */
+public interface ConnectionFactory {
+	/**
+	 * Service property containing the scheme(s) for which this Connection
+	 * Factory can create <code>Connection</code> objects. This property is of
+	 * type <code>String[]</code>.
+	 */
+	public static final String	IO_SCHEME	= "io.scheme";
+
+	/**
+	 * Create a new <code>Connection</code> object for the specified URI.
+	 * 
+	 * @param name The full URI passed to the <code>ConnectorService.open</code>
+	 *        method
+	 * @param mode The mode parameter passed to the
+	 *        <code>ConnectorService.open</code> method
+	 * @param timeouts The timeouts parameter passed to the
+	 *        <code>ConnectorService.open</code> method
+	 * @return A new <code>javax.microedition.io.Connection</code> object.
+	 * @throws IOException If a <code>javax.microedition.io.Connection</code>
+	 *         object can not not be created.
+	 */
+	public Connection createConnection(String name, int mode, boolean timeouts)
+			throws IOException;
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/io/ConnectorService.java b/org.osgi.compendium/src/main/java/org/osgi/service/io/ConnectorService.java
new file mode 100644
index 0000000..7172b18
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/io/ConnectorService.java
@@ -0,0 +1,165 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.io/src/org/osgi/service/io/ConnectorService.java,v 1.7 2006/03/14 01:20:44 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.io;
+
+import java.io.*;
+import javax.microedition.io.*;
+
+/**
+ * The Connector Service should be called to create and open
+ * <code>javax.microedition.io.Connection</code> objects.
+ * 
+ * When an <code>open*</code> method is called, the implementation of the
+ * Connector Service will examine the specified name for a scheme. The Connector
+ * Service will then look for a Connection Factory service which is registered
+ * with the service property <code>IO_SCHEME</code> which matches the scheme. The
+ * <code>createConnection</code> method of the selected Connection Factory will
+ * then be called to create the actual <code>Connection</code> object.
+ * 
+ * <p>
+ * If more than one Connection Factory service is registered for a particular
+ * scheme, the service with the highest ranking (as specified in its
+ * <code>service.ranking</code> property) is called. If there is a tie in ranking,
+ * the service with the lowest service ID (as specified in its
+ * <code>service.id</code> property), that is the service that was registered
+ * first, is called. This is the same algorithm used by
+ * <code>BundleContext.getServiceReference</code>.
+ * 
+ * @version $Revision: 1.7 $
+ */
+public interface ConnectorService {
+	/**
+	 * Read access mode.
+	 * 
+	 * @see "javax.microedition.io.Connector.READ"
+	 */
+	public static final int	READ		= Connector.READ;
+	/**
+	 * Write access mode.
+	 * 
+	 * @see "javax.microedition.io.Connector.WRITE"
+	 */
+	public static final int	WRITE		= Connector.WRITE;
+	/**
+	 * Read/Write access mode.
+	 * 
+	 * @see "javax.microedition.io.Connector.READ_WRITE"
+	 */
+	public static final int	READ_WRITE	= Connector.READ_WRITE;
+
+	/**
+	 * Create and open a <code>Connection</code> object for the specified name.
+	 * 
+	 * @param name The URI for the connection.
+	 * @return A new <code>javax.microedition.io.Connection</code> object.
+	 * @throws IllegalArgumentException If a parameter is invalid.
+	 * @throws javax.microedition.io.ConnectionNotFoundException If the
+	 *         connection cannot be found.
+	 * @throws IOException If some other kind of I/O error occurs.
+	 * @see "javax.microedition.io.Connector.open(String name)"
+	 */
+	public Connection open(String name) throws IOException;
+
+	/**
+	 * Create and open a <code>Connection</code> object for the specified name and
+	 * access mode.
+	 * 
+	 * @param name The URI for the connection.
+	 * @param mode The access mode.
+	 * @return A new <code>javax.microedition.io.Connection</code> object.
+	 * @throws IllegalArgumentException If a parameter is invalid.
+	 * @throws javax.microedition.io.ConnectionNotFoundException If the
+	 *         connection cannot be found.
+	 * @throws IOException If some other kind of I/O error occurs.
+	 * @see "javax.microedition.io.Connector.open(String name, int mode)"
+	 */
+	public Connection open(String name, int mode) throws IOException;
+
+	/**
+	 * Create and open a <code>Connection</code> object for the specified name,
+	 * access mode and timeouts.
+	 * 
+	 * @param name The URI for the connection.
+	 * @param mode The access mode.
+	 * @param timeouts A flag to indicate that the caller wants timeout
+	 *        exceptions.
+	 * @return A new <code>javax.microedition.io.Connection</code> object.
+	 * @throws IllegalArgumentException If a parameter is invalid.
+	 * @throws javax.microedition.io.ConnectionNotFoundException If the
+	 *         connection cannot be found.
+	 * @throws IOException If some other kind of I/O error occurs.
+	 * @see "<code>javax.microedition.io.Connector.open</code>"
+	 */
+	public Connection open(String name, int mode, boolean timeouts)
+			throws IOException;
+
+	/**
+	 * Create and open an <code>InputStream</code> object for the specified name.
+	 * 
+	 * @param name The URI for the connection.
+	 * @return An <code>InputStream</code> object.
+	 * @throws IllegalArgumentException If a parameter is invalid.
+	 * @throws javax.microedition.io.ConnectionNotFoundException If the
+	 *         connection cannot be found.
+	 * @throws IOException If some other kind of I/O error occurs.
+	 * @see "javax.microedition.io.Connector.openInputStream(String name)"
+	 */
+	public InputStream openInputStream(String name) throws IOException;
+
+	/**
+	 * Create and open a <code>DataInputStream</code> object for the specified
+	 * name.
+	 * 
+	 * @param name The URI for the connection.
+	 * @return A <code>DataInputStream</code> object.
+	 * @throws IllegalArgumentException If a parameter is invalid.
+	 * @throws javax.microedition.io.ConnectionNotFoundException If the
+	 *         connection cannot be found.
+	 * @throws IOException If some other kind of I/O error occurs.
+	 * @see "javax.microedition.io.Connector.openDataInputStream(String name)"
+	 */
+	public DataInputStream openDataInputStream(String name) throws IOException;
+
+	/**
+	 * Create and open an <code>OutputStream</code> object for the specified name.
+	 * 
+	 * @param name The URI for the connection.
+	 * @return An <code>OutputStream</code> object.
+	 * @throws IllegalArgumentException If a parameter is invalid.
+	 * @throws javax.microedition.io.ConnectionNotFoundException If the
+	 *         connection cannot be found.
+	 * @throws IOException If some other kind of I/O error occurs.
+	 * @see "javax.microedition.io.Connector.openOutputStream(String name)"
+	 */
+	public OutputStream openOutputStream(String name) throws IOException;
+
+	/**
+	 * Create and open a <code>DataOutputStream</code> object for the specified
+	 * name.
+	 * 
+	 * @param name The URI for the connection.
+	 * @return A <code>DataOutputStream</code> object.
+	 * @throws IllegalArgumentException If a parameter is invalid.
+	 * @throws javax.microedition.io.ConnectionNotFoundException If the
+	 *         connection cannot be found.
+	 * @throws IOException If some other kind of I/O error occurs.
+	 * @see "javax.microedition.io.Connector.openDataOutputStream(String name)"
+	 */
+	public DataOutputStream openDataOutputStream(String name)
+			throws IOException;
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/io/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/io/package.html
new file mode 100644
index 0000000..19c6ce5
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/io/package.html
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.service.io/src/org/osgi/service/io/package.html,v 1.2 2004/12/01 19:01:26 hargrave Exp $ -->
+<BODY>
+<P>The OSGi IO Connector Specification Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the <TT>Import-Package</TT> header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.io; version=1.0, javax.microedition.io
+</pre>
+</BODY>
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/io/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/io/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/io/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/log/LogEntry.java b/org.osgi.compendium/src/main/java/org/osgi/service/log/LogEntry.java
new file mode 100644
index 0000000..db200eb
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/log/LogEntry.java
@@ -0,0 +1,109 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.log/src/org/osgi/service/log/LogEntry.java,v 1.8 2006/03/14 01:21:24 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2000, 2005). 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.log;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Provides methods to access the information contained in an individual Log
+ * Service log entry.
+ * 
+ * <p>
+ * A <code>LogEntry</code> object may be acquired from the
+ * <code>LogReaderService.getLog</code> method or by registering a
+ * <code>LogListener</code> object.
+ * 
+ * @version $Revision: 1.8 $
+ * @see LogReaderService#getLog
+ * @see LogListener
+ */
+public interface LogEntry {
+	/**
+	 * Returns the bundle that created this <code>LogEntry</code> object.
+	 * 
+	 * @return The bundle that created this <code>LogEntry</code> object;
+	 *         <code>null</code> if no bundle is associated with this
+	 *         <code>LogEntry</code> object.
+	 */
+	public Bundle getBundle();
+
+	/**
+	 * Returns the <code>ServiceReference</code> object for the service associated
+	 * with this <code>LogEntry</code> object.
+	 * 
+	 * @return <code>ServiceReference</code> object for the service associated
+	 *         with this <code>LogEntry</code> object; <code>null</code> if no
+	 *         <code>ServiceReference</code> object was provided.
+	 */
+	public ServiceReference getServiceReference();
+
+	/**
+	 * Returns the severity level of this <code>LogEntry</code> object.
+	 * 
+	 * <p>
+	 * This is one of the severity levels defined by the <code>LogService</code>
+	 * interface.
+	 * 
+	 * @return Severity level of this <code>LogEntry</code> object.
+	 * 
+	 * @see LogService#LOG_ERROR
+	 * @see LogService#LOG_WARNING
+	 * @see LogService#LOG_INFO
+	 * @see LogService#LOG_DEBUG
+	 */
+	public int getLevel();
+
+	/**
+	 * Returns the human readable message associated with this <code>LogEntry</code>
+	 * object.
+	 * 
+	 * @return <code>String</code> containing the message associated with this
+	 *         <code>LogEntry</code> object.
+	 */
+	public String getMessage();
+
+	/**
+	 * Returns the exception object associated with this <code>LogEntry</code>
+	 * object.
+	 * 
+	 * <p>
+	 * In some implementations, the returned exception may not be the original
+	 * exception. To avoid references to a bundle defined exception class, thus
+	 * preventing an uninstalled bundle from being garbage collected, the Log
+	 * Service may return an exception object of an implementation defined
+	 * Throwable subclass. The returned object will attempt to provide as much
+	 * information as possible from the original exception object such as the
+	 * message and stack trace.
+	 * 
+	 * @return <code>Throwable</code> object of the exception associated with this
+	 *         <code>LogEntry</code>;<code>null</code> if no exception is
+	 *         associated with this <code>LogEntry</code> object.
+	 */
+	public Throwable getException();
+
+	/**
+	 * Returns the value of <code>currentTimeMillis()</code> at the time this
+	 * <code>LogEntry</code> object was created.
+	 * 
+	 * @return The system time in milliseconds when this <code>LogEntry</code>
+	 *         object was created.
+	 * @see "System.currentTimeMillis()"
+	 */
+	public long getTime();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/log/LogListener.java b/org.osgi.compendium/src/main/java/org/osgi/service/log/LogListener.java
new file mode 100644
index 0000000..d611a4c
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/log/LogListener.java
@@ -0,0 +1,51 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.log/src/org/osgi/service/log/LogListener.java,v 1.8 2006/03/14 01:21:24 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2000, 2005). 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.log;
+
+import java.util.EventListener;
+
+/**
+ * Subscribes to <code>LogEntry</code> objects from the <code>LogReaderService</code>.
+ * 
+ * <p>
+ * A <code>LogListener</code> object may be registered with the Log Reader Service
+ * using the <code>LogReaderService.addLogListener</code> method. After the
+ * listener is registered, the <code>logged</code> method will be called for each
+ * <code>LogEntry</code> object created. The <code>LogListener</code> object may be
+ * unregistered by calling the <code>LogReaderService.removeLogListener</code>
+ * method.
+ * 
+ * @version $Revision: 1.8 $
+ * @see LogReaderService
+ * @see LogEntry
+ * @see LogReaderService#addLogListener(LogListener)
+ * @see LogReaderService#removeLogListener(LogListener)
+ */
+public interface LogListener extends EventListener {
+	/**
+	 * Listener method called for each LogEntry object created.
+	 * 
+	 * <p>
+	 * As with all event listeners, this method should return to its caller as
+	 * soon as possible.
+	 * 
+	 * @param entry A <code>LogEntry</code> object containing log information.
+	 * @see LogEntry
+	 */
+	public void logged(LogEntry entry);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/log/LogReaderService.java b/org.osgi.compendium/src/main/java/org/osgi/service/log/LogReaderService.java
new file mode 100644
index 0000000..4e2e1db
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/log/LogReaderService.java
@@ -0,0 +1,98 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.log/src/org/osgi/service/log/LogReaderService.java,v 1.9 2006/03/14 01:21:24 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2000, 2005). 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.log;
+
+import java.util.Enumeration;
+
+/**
+ * Provides methods to retrieve <code>LogEntry</code> objects from the log.
+ * <p>
+ * There are two ways to retrieve <code>LogEntry</code> objects:
+ * <ul>
+ * <li>The primary way to retrieve <code>LogEntry</code> objects is to register a
+ * <code>LogListener</code> object whose <code>LogListener.logged</code> method will
+ * be called for each entry added to the log.
+ * <li>To retrieve past <code>LogEntry</code> objects, the <code>getLog</code>
+ * method can be called which will return an <code>Enumeration</code> of all
+ * <code>LogEntry</code> objects in the log.
+ * 
+ * @version $Revision: 1.9 $
+ * @see LogEntry
+ * @see LogListener
+ * @see LogListener#logged(LogEntry)
+ */
+public interface LogReaderService {
+	/**
+	 * Subscribes to <code>LogEntry</code> objects.
+	 * 
+	 * <p>
+	 * This method registers a <code>LogListener</code> object with the Log Reader
+	 * Service. The <code>LogListener.logged(LogEntry)</code> method will be
+	 * called for each <code>LogEntry</code> object placed into the log.
+	 * 
+	 * <p>
+	 * When a bundle which registers a <code>LogListener</code> object is stopped
+	 * or otherwise releases the Log Reader Service, the Log Reader Service must
+	 * remove all of the bundle's listeners.
+	 * 
+	 * <p>
+	 * If this Log Reader Service's list of listeners already contains a
+	 * listener <code>l</code> such that <code>(l==listener)</code>, this method
+	 * does nothing.
+	 * 
+	 * @param listener A <code>LogListener</code> object to register; the
+	 *        <code>LogListener</code> object is used to receive <code>LogEntry</code>
+	 *        objects.
+	 * @see LogListener
+	 * @see LogEntry
+	 * @see LogListener#logged(LogEntry)
+	 */
+	public void addLogListener(LogListener listener);
+
+	/**
+	 * Unsubscribes to <code>LogEntry</code> objects.
+	 * 
+	 * <p>
+	 * This method unregisters a <code>LogListener</code> object from the Log
+	 * Reader Service.
+	 * 
+	 * <p>
+	 * If <code>listener</code> is not contained in this Log Reader Service's list
+	 * of listeners, this method does nothing.
+	 * 
+	 * @param listener A <code>LogListener</code> object to unregister.
+	 * @see LogListener
+	 */
+	public void removeLogListener(LogListener listener);
+
+	/**
+	 * Returns an <code>Enumeration</code> of all <code>LogEntry</code> objects in
+	 * the log.
+	 * 
+	 * <p>
+	 * Each element of the enumeration is a <code>LogEntry</code> object, ordered
+	 * with the most recent entry first. Whether the enumeration is of all
+	 * <code>LogEntry</code> objects since the Log Service was started or some
+	 * recent past is implementation-specific. Also implementation-specific is
+	 * whether informational and debug <code>LogEntry</code> objects are included
+	 * in the enumeration.
+	 * @return An <code>Enumeration</code> of all <code>LogEntry</code> objects in
+	 * the log.
+	 */
+	public Enumeration getLog();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/log/LogService.java b/org.osgi.compendium/src/main/java/org/osgi/service/log/LogService.java
new file mode 100644
index 0000000..ee263ef
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/log/LogService.java
@@ -0,0 +1,156 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.log/src/org/osgi/service/log/LogService.java,v 1.8 2006/03/14 01:21:24 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2000, 2005). 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.log;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Provides methods for bundles to write messages to the log.
+ * 
+ * <p>
+ * <code>LogService</code> methods are provided to log messages; optionally with a
+ * <code>ServiceReference</code> object or an exception.
+ * 
+ * <p>
+ * Bundles must log messages in the OSGi environment with a severity level
+ * according to the following hierarchy:
+ * <ol>
+ * <li>{@link #LOG_ERROR}
+ * <li>{@link #LOG_WARNING}
+ * <li>{@link #LOG_INFO}
+ * <li>{@link #LOG_DEBUG}
+ * </ol>
+ * 
+ * @version $Revision: 1.8 $
+ */
+public interface LogService {
+	/**
+	 * An error message (Value 1).
+	 * 
+	 * <p>
+	 * This log entry indicates the bundle or service may not be functional.
+	 */
+	public static final int	LOG_ERROR	= 1;
+	/**
+	 * A warning message (Value 2).
+	 * 
+	 * <p>
+	 * This log entry indicates a bundle or service is still functioning but may
+	 * experience problems in the future because of the warning condition.
+	 */
+	public static final int	LOG_WARNING	= 2;
+	/**
+	 * An informational message (Value 3).
+	 * 
+	 * <p>
+	 * This log entry may be the result of any change in the bundle or service
+	 * and does not indicate a problem.
+	 */
+	public static final int	LOG_INFO	= 3;
+	/**
+	 * A debugging message (Value 4).
+	 * 
+	 * <p>
+	 * This log entry is used for problem determination and may be irrelevant to
+	 * anyone but the bundle developer.
+	 */
+	public static final int	LOG_DEBUG	= 4;
+
+	/**
+	 * Logs a message.
+	 * 
+	 * <p>
+	 * The <code>ServiceReference</code> field and the <code>Throwable</code> field
+	 * of the <code>LogEntry</code> object will be set to <code>null</code>.
+	 * 
+	 * @param level The severity of the message. This should be one of the
+	 *        defined log levels but may be any integer that is interpreted in a
+	 *        user defined way.
+	 * @param message Human readable string describing the condition or
+	 *        <code>null</code>.
+	 * @see #LOG_ERROR
+	 * @see #LOG_WARNING
+	 * @see #LOG_INFO
+	 * @see #LOG_DEBUG
+	 */
+	public void log(int level, String message);
+
+	/**
+	 * Logs a message with an exception.
+	 * 
+	 * <p>
+	 * The <code>ServiceReference</code> field of the <code>LogEntry</code> object
+	 * will be set to <code>null</code>.
+	 * 
+	 * @param level The severity of the message. This should be one of the
+	 *        defined log levels but may be any integer that is interpreted in a
+	 *        user defined way.
+	 * @param message The human readable string describing the condition or
+	 *        <code>null</code>.
+	 * @param exception The exception that reflects the condition or
+	 *        <code>null</code>.
+	 * @see #LOG_ERROR
+	 * @see #LOG_WARNING
+	 * @see #LOG_INFO
+	 * @see #LOG_DEBUG
+	 */
+	public void log(int level, String message, Throwable exception);
+
+	/**
+	 * Logs a message associated with a specific <code>ServiceReference</code>
+	 * object.
+	 * 
+	 * <p>
+	 * The <code>Throwable</code> field of the <code>LogEntry</code> will be set to
+	 * <code>null</code>.
+	 * 
+	 * @param sr The <code>ServiceReference</code> object of the service that this
+	 *        message is associated with or <code>null</code>.
+	 * @param level The severity of the message. This should be one of the
+	 *        defined log levels but may be any integer that is interpreted in a
+	 *        user defined way.
+	 * @param message Human readable string describing the condition or
+	 *        <code>null</code>.
+	 * @see #LOG_ERROR
+	 * @see #LOG_WARNING
+	 * @see #LOG_INFO
+	 * @see #LOG_DEBUG
+	 */
+	public void log(ServiceReference sr, int level, String message);
+
+	/**
+	 * Logs a message with an exception associated and a
+	 * <code>ServiceReference</code> object.
+	 * 
+	 * @param sr The <code>ServiceReference</code> object of the service that this
+	 *        message is associated with.
+	 * @param level The severity of the message. This should be one of the
+	 *        defined log levels but may be any integer that is interpreted in a
+	 *        user defined way.
+	 * @param message Human readable string describing the condition or
+	 *        <code>null</code>.
+	 * @param exception The exception that reflects the condition or
+	 *        <code>null</code>.
+	 * @see #LOG_ERROR
+	 * @see #LOG_WARNING
+	 * @see #LOG_INFO
+	 * @see #LOG_DEBUG
+	 */
+	public void log(ServiceReference sr, int level, String message,
+			Throwable exception);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/log/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/log/package.html
new file mode 100644
index 0000000..dd1932b
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/log/package.html
@@ -0,0 +1,11 @@
+<!-- $Header: /cvshome/build/org.osgi.service.log/src/org/osgi/service/log/package.html,v 1.3 2005/08/10 01:43:20 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Log Service Package. Specification Version 1.3.
+<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.log; version=1.3
+</pre>
+</BODY>
+
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/log/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/log/packageinfo
new file mode 100644
index 0000000..0117a56
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/log/packageinfo
@@ -0,0 +1 @@
+version 1.3
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/metatype/AttributeDefinition.java b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/AttributeDefinition.java
new file mode 100644
index 0000000..27ed253
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/AttributeDefinition.java
@@ -0,0 +1,279 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.metatype/src/org/osgi/service/metatype/AttributeDefinition.java,v 1.11 2006/03/14 01:20:46 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.metatype;
+
+/**
+ * An interface to describe an attribute.
+ * 
+ * <p>
+ * An <code>AttributeDefinition</code> object defines a description of the data
+ * type of a property/attribute.
+ * 
+ * @version $Revision: 1.11 $
+ */
+public interface AttributeDefinition {
+	/**
+	 * The <code>STRING</code> (1) type.
+	 * 
+	 * <p>
+	 * Attributes of this type should be stored as <code>String</code>,
+	 * <code>Vector</code> with <code>String</code> or <code>String[]</code> objects,
+	 * depending on the <code>getCardinality()</code> value.
+	 */
+	public static final int	STRING		= 1;
+	/**
+	 * The <code>LONG</code> (2) type.
+	 * 
+	 * Attributes of this type should be stored as <code>Long</code>,
+	 * <code>Vector</code> with <code>Long</code> or <code>long[]</code> objects,
+	 * depending on the <code>getCardinality()</code> value.
+	 */
+	public static final int	LONG		= 2;
+	/**
+	 * The <code>INTEGER</code> (3) type.
+	 * 
+	 * Attributes of this type should be stored as <code>Integer</code>,
+	 * <code>Vector</code> with <code>Integer</code> or <code>int[]</code> objects,
+	 * depending on the <code>getCardinality()</code> value.
+	 */
+	public static final int	INTEGER		= 3;
+	/**
+	 * The <code>SHORT</code> (4) type.
+	 * 
+	 * Attributes of this type should be stored as <code>Short</code>,
+	 * <code>Vector</code> with <code>Short</code> or <code>short[]</code> objects,
+	 * depending on the <code>getCardinality()</code> value.
+	 */
+	public static final int	SHORT		= 4;
+	/**
+	 * The <code>CHARACTER</code> (5) type.
+	 * 
+	 * Attributes of this type should be stored as <code>Character</code>,
+	 * <code>Vector</code> with <code>Character</code> or <code>char[]</code> objects,
+	 * depending on the <code>getCardinality()</code> value.
+	 */
+	public static final int	CHARACTER	= 5;
+	/**
+	 * The <code>BYTE</code> (6) type.
+	 * 
+	 * Attributes of this type should be stored as <code>Byte</code>,
+	 * <code>Vector</code> with <code>Byte</code> or <code>byte[]</code> objects,
+	 * depending on the <code>getCardinality()</code> value.
+	 */
+	public static final int	BYTE		= 6;
+	/**
+	 * The <code>DOUBLE</code> (7) type.
+	 * 
+	 * Attributes of this type should be stored as <code>Double</code>,
+	 * <code>Vector</code> with <code>Double</code> or <code>double[]</code> objects,
+	 * depending on the <code>getCardinality()</code> value.
+	 */
+	public static final int	DOUBLE		= 7;
+	/**
+	 * The <code>FLOAT</code> (8) type.
+	 * 
+	 * Attributes of this type should be stored as <code>Float</code>,
+	 * <code>Vector</code> with <code>Float</code> or <code>float[]</code> objects,
+	 * depending on the <code>getCardinality()</code> value.
+	 */
+	public static final int	FLOAT		= 8;
+	/**
+	 * The <code>BIGINTEGER</code> (9) type.
+	 * 
+	 * Attributes of this type should be stored as <code>BigInteger</code>,
+	 * <code>Vector</code> with <code>BigInteger</code> or <code>BigInteger[]</code>
+	 * objects, depending on the <code>getCardinality()</code> value.
+	 * 
+	 * @deprecated Since 1.1
+	 */
+	public static final int	BIGINTEGER	= 9;
+	/**
+	 * The <code>BIGDECIMAL</code> (10) type.
+	 * 
+	 * Attributes of this type should be stored as <code>BigDecimal</code>,
+	 * <code>Vector</code> with <code>BigDecimal</code> or <code>BigDecimal[]</code>
+	 * objects depending on <code>getCardinality()</code>.
+	 * 
+	 * @deprecated Since 1.1
+	 */
+	public static final int	BIGDECIMAL	= 10;
+	/**
+	 * The <code>BOOLEAN</code> (11) type.
+	 * 
+	 * Attributes of this type should be stored as <code>Boolean</code>,
+	 * <code>Vector</code> with <code>Boolean</code> or <code>boolean[]</code> objects
+	 * depending on <code>getCardinality()</code>.
+	 */
+	public static final int	BOOLEAN		= 11;
+
+	/**
+	 * Get the name of the attribute. This name may be localized.
+	 * 
+	 * @return The localized name of the definition.
+	 */
+	public String getName();
+
+	/**
+	 * Unique identity for this attribute.
+	 * 
+	 * Attributes share a global namespace in the registry. E.g. an attribute
+	 * <code>cn</code> or <code>commonName</code> must always be a <code>String</code>
+	 * and the semantics are always a name of some object. They share this
+	 * aspect with LDAP/X.500 attributes. In these standards the OSI Object
+	 * Identifier (OID) is used to uniquely identify an attribute. If such an
+	 * OID exists, (which can be requested at several standard organisations and
+	 * many companies already have a node in the tree) it can be returned here.
+	 * Otherwise, a unique id should be returned which can be a Java class name
+	 * (reverse domain name) or generated with a GUID algorithm. Note that all
+	 * LDAP defined attributes already have an OID. It is strongly advised to
+	 * define the attributes from existing LDAP schemes which will give the OID.
+	 * Many such schemes exist ranging from postal addresses to DHCP parameters.
+	 * 
+	 * @return The id or oid
+	 */
+	public String getID();
+
+	/**
+	 * Return a description of this attribute.
+	 * 
+	 * The description may be localized and must describe the semantics of this
+	 * type and any constraints.
+	 * 
+	 * @return The localized description of the definition.
+	 */
+	public String getDescription();
+
+	/**
+	 * Return the cardinality of this attribute.
+	 * 
+	 * The OSGi environment handles multi valued attributes in arrays ([]) or in
+	 * <code>Vector</code> objects. The return value is defined as follows:
+	 * 
+	 * <pre>
+	 * 
+	 *    x = Integer.MIN_VALUE    no limit, but use Vector
+	 *    x &lt; 0                    -x = max occurrences, store in Vector
+	 *    x &gt; 0                     x = max occurrences, store in array []
+	 *    x = Integer.MAX_VALUE    no limit, but use array []
+	 *    x = 0                     1 occurrence required
+	 *  
+	 * </pre>
+	 * 
+	 * @return The cardinality of this attribute. 
+	 */
+	public int getCardinality();
+
+	/**
+	 * Return the type for this attribute.
+	 * 
+	 * <p>
+	 * Defined in the following constants which map to the appropriate Java
+	 * type. <code>STRING</code>,<code>LONG</code>,<code>INTEGER</code>,
+	 * <code>CHAR</code>,<code>BYTE</code>,<code>DOUBLE</code>,<code>FLOAT</code>,
+	 * <code>BOOLEAN</code>.
+	 *
+	 * @return The type for this attribute.
+	 */
+	public int getType();
+
+	/**
+	 * Return a list of option values that this attribute can take.
+	 * 
+	 * <p>
+	 * If the function returns <code>null</code>, there are no option values
+	 * available.
+	 * 
+	 * <p>
+	 * Each value must be acceptable to validate() (return "") and must be a
+	 * <code>String</code> object that can be converted to the data type defined
+	 * by getType() for this attribute.
+	 * 
+	 * <p>
+	 * This list must be in the same sequence as <code>getOptionLabels()</code>.
+	 * I.e. for each index i in <code>getOptionValues</code>, i in
+	 * <code>getOptionLabels()</code> should be the label.
+	 * 
+	 * <p>
+	 * For example, if an attribute can have the value male, female, unknown,
+	 * this list can return
+	 * <code>new String[] { "male", "female", "unknown" }</code>.
+	 * 
+	 * @return A list values
+	 */
+	public String[] getOptionValues();
+
+	/**
+	 * Return a list of labels of option values.
+	 * 
+	 * <p>
+	 * The purpose of this method is to allow menus with localized labels. It is
+	 * associated with <code>getOptionValues</code>. The labels returned here are
+	 * ordered in the same way as the values in that method.
+	 * 
+	 * <p>
+	 * If the function returns <code>null</code>, there are no option labels
+	 * available.
+	 * <p>
+	 * This list must be in the same sequence as the <code>getOptionValues()</code>
+	 * method. I.e. for each index i in <code>getOptionLabels</code>, i in
+	 * <code>getOptionValues()</code> should be the associated value.
+	 * 
+	 * <p>
+	 * For example, if an attribute can have the value male, female, unknown,
+	 * this list can return (for dutch)
+	 * <code>new String[] { "Man", "Vrouw", "Onbekend" }</code>.
+	 * 
+	 * @return A list values
+	 */
+	public String[] getOptionLabels();
+
+	/**
+	 * Validate an attribute in <code>String</code> form.
+	 * 
+	 * An attribute might be further constrained in value. This method will
+	 * attempt to validate the attribute according to these constraints. It can
+	 * return three different values:
+	 * 
+	 * <pre>
+	 *  null           No validation present
+	 *  ""             No problems detected
+	 *  "..."          A localized description of why the value is wrong
+	 * </pre>
+	 * 
+	 * @param value The value before turning it into the basic data type
+	 * @return <code>null</code>, "", or another string
+	 */
+	public String validate(String value);
+
+	/**
+	 * Return a default for this attribute.
+	 * 
+	 * The object must be of the appropriate type as defined by the cardinality
+	 * and <code>getType()</code>. The return type is a list of <code>String</code>
+	 * objects that can be converted to the appropriate type. The cardinality of
+	 * the return array must follow the absolute cardinality of this type. E.g.
+	 * if the cardinality = 0, the array must contain 1 element. If the
+	 * cardinality is 1, it must contain 0 or 1 elements. If it is -5, it must
+	 * contain from 0 to max 5 elements. Note that the special case of a 0
+	 * cardinality, meaning a single value, does not allow arrays or vectors of
+	 * 0 elements.
+	 * 
+	 * @return Return a default value or <code>null</code> if no default exists.
+	 */
+	public String[] getDefaultValue();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/metatype/MetaTypeInformation.java b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/MetaTypeInformation.java
new file mode 100644
index 0000000..95a8a8a
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/MetaTypeInformation.java
@@ -0,0 +1,52 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.metatype/src/org/osgi/service/metatype/MetaTypeInformation.java,v 1.7 2006/03/14 01:20:46 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005). 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.metatype;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * A MetaType Information object is created by the MetaTypeService to return
+ * meta type information for a specific bundle.
+ * 
+ * @version $Revision: 1.7 $
+ * @since 1.1
+ */
+public interface MetaTypeInformation extends MetaTypeProvider {
+	/**
+	 * Return the PIDs (for ManagedServices) for which ObjectClassDefinition
+	 * information is available.
+	 * 
+	 * @return Array of PIDs.
+	 */
+	public String[] getPids();
+
+	/**
+	 * Return the Factory PIDs (for ManagedServiceFactories) for which
+	 * ObjectClassDefinition information is available.
+	 * 
+	 * @return Array of Factory PIDs.
+	 */
+	public String[] getFactoryPids();
+
+	/**
+	 * Return the bundle for which this object provides meta type information.
+	 * 
+	 * @return Bundle for which this object provides meta type information.
+	 */
+	public Bundle getBundle();
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/metatype/MetaTypeProvider.java b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/MetaTypeProvider.java
new file mode 100644
index 0000000..ef114b5
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/MetaTypeProvider.java
@@ -0,0 +1,57 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.metatype/src/org/osgi/service/metatype/MetaTypeProvider.java,v 1.10 2006/03/14 01:20:46 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.metatype;
+
+/**
+ * Provides access to metatypes.
+ * 
+ * @version $Revision: 1.10 $
+ */
+public interface MetaTypeProvider {
+	/**
+	 * Returns an object class definition for the specified id localized to the
+	 * specified locale.
+	 * 
+	 * <p>
+	 * The locale parameter must be a name that consists of <code>language</code>[
+	 * "_" <code>country</code>[ "_" <code>variation</code>] ] as is customary in
+	 * the <code>Locale</code> class. This <code>Locale</code> class is not used
+	 * because certain profiles do not contain it.
+	 * 
+	 * @param id The ID of the requested object class. This can be a pid or
+	 *        factory pid returned by getPids or getFactoryPids.
+	 * @param locale The locale of the definition or <code>null</code> for default
+	 *        locale.
+	 * @return A <code>ObjectClassDefinition</code> object.
+	 * @throws IllegalArgumentException If the id or locale arguments are not
+	 *         valid
+	 */
+	public ObjectClassDefinition getObjectClassDefinition(String id, String locale);
+
+	/**
+	 * Return a list of available locales.
+	 * 
+	 * The results must be names that consists of language [ _ country [ _
+	 * variation ]] as is customary in the <code>Locale</code> class.
+	 * 
+	 * @return An array of locale strings or <code>null</code> if there is no
+	 *         locale specific localization can be found.
+	 *  
+	 */
+	public String[] getLocales();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/metatype/MetaTypeService.java b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/MetaTypeService.java
new file mode 100644
index 0000000..4fe4a03
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/MetaTypeService.java
@@ -0,0 +1,53 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.metatype/src/org/osgi/service/metatype/MetaTypeService.java,v 1.9 2006/03/14 01:20:46 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005). 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.metatype;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * The MetaType Service can be used to obtain meta type information for a
+ * bundle. The MetaType Service will examine the specified bundle for meta type
+ * documents to create the returned <code>MetaTypeInformation</code> object.
+ * 
+ * <p>
+ * If the specified bundle does not contain any meta type documents, then a
+ * <code>MetaTypeInformation</code> object will be returned that wrappers any
+ * <code>ManagedService</code> or <code>ManagedServiceFactory</code>
+ * services registered by the specified bundle that implement
+ * <code>MetaTypeProvider</code>. Thus the MetaType Service can be used to
+ * retrieve meta type information for bundles which contain a meta type
+ * documents or which provide their own <code>MetaTypeProvider</code> objects.
+ * 
+ * @version $Revision: 1.9 $
+ * @since 1.1
+ */
+public interface MetaTypeService {
+	/**
+	 * Return the MetaType information for the specified bundle.
+	 * 
+	 * @param bundle The bundle for which meta type information is requested.
+	 * @return A MetaTypeInformation object for the specified bundle.
+	 */
+	public MetaTypeInformation getMetaTypeInformation(Bundle bundle);
+
+	/**
+	 * Location of meta type documents. The MetaType Service will process each
+	 * entry in the meta type documents directory.
+	 */
+	public final static String	METATYPE_DOCUMENTS_LOCATION	= "OSGI-INF/metatype";
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/metatype/ObjectClassDefinition.java b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/ObjectClassDefinition.java
new file mode 100644
index 0000000..09c4459
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/ObjectClassDefinition.java
@@ -0,0 +1,121 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.metatype/src/org/osgi/service/metatype/ObjectClassDefinition.java,v 1.10 2006/03/14 01:20:46 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.metatype;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Description for the data type information of an objectclass.
+ * 
+ * @version $Revision: 1.10 $
+ */
+public interface ObjectClassDefinition {
+	/**
+	 * Argument for <code>getAttributeDefinitions(int)</code>.
+	 * <p>
+	 * <code>REQUIRED</code> indicates that only the required definitions are
+	 * returned. The value is 1.
+	 */
+	public static final int	REQUIRED	= 1;
+	/**
+	 * Argument for <code>getAttributeDefinitions(int)</code>.
+	 * <p>
+	 * <code>OPTIONAL</code> indicates that only the optional definitions are
+	 * returned. The value is 2.
+	 */
+	public static final int	OPTIONAL	= 2;
+	/**
+	 * Argument for <code>getAttributeDefinitions(int)</code>.
+	 * <p>
+	 * <code>ALL</code> indicates that all the definitions are returned. The value
+	 * is -1.
+	 */
+	public static final int	ALL			= 0xFFFFFFFF;
+
+	/**
+	 * Return the name of this object class.
+	 * 
+	 * The name may be localized.
+	 * 
+	 * @return The name of this object class.
+	 */
+	public String getName();
+
+	/**
+	 * Return the id of this object class.
+	 * 
+	 * <p>
+	 * <code>ObjectDefintion</code> objects share a global namespace in the
+	 * registry. They share this aspect with LDAP/X.500 attributes. In these
+	 * standards the OSI Object Identifier (OID) is used to uniquely identify
+	 * object classes. If such an OID exists, (which can be requested at several
+	 * standard organisations and many companies already have a node in the
+	 * tree) it can be returned here. Otherwise, a unique id should be returned
+	 * which can be a java class name (reverse domain name) or generated with a
+	 * GUID algorithm. Note that all LDAP defined object classes already have an
+	 * OID associated. It is strongly advised to define the object classes from
+	 * existing LDAP schemes which will give the OID for free. Many such schemes
+	 * exist ranging from postal addresses to DHCP parameters.
+	 * 
+	 * @return The id of this object class.
+	 */
+	public String getID();
+
+	/**
+	 * Return a description of this object class.
+	 * 
+	 * The description may be localized.
+	 * 
+	 * @return The description of this object class.
+	 */
+	public String getDescription();
+
+	/**
+	 * Return the attribute definitions for this object class.
+	 * 
+	 * <p>
+	 * Return a set of attributes. The filter parameter can distinguish between
+	 * <code>ALL</code>,<code>REQUIRED</code> or the <code>OPTIONAL</code>
+	 * attributes.
+	 * 
+	 * @param filter <code>ALL</code>,<code>REQUIRED</code>,<code>OPTIONAL</code>
+	 * @return An array of attribute definitions or <code>null</code> if no
+	 *         attributes are selected
+	 */
+	public AttributeDefinition[] getAttributeDefinitions(int filter);
+
+	/**
+	 * Return an <code>InputStream</code> object that can be used to create an
+	 * icon from.
+	 * 
+	 * <p>
+	 * Indicate the size and return an <code>InputStream</code> object containing
+	 * an icon. The returned icon maybe larger or smaller than the indicated
+	 * size.
+	 * 
+	 * <p>
+	 * The icon may depend on the localization.
+	 * 
+	 * @param size Requested size of an icon, e.g. a 16x16 pixels icon then size =
+	 *        16
+	 * @return An InputStream representing an icon or <code>null</code>
+	 * @throws IOException If the <code>InputStream</code> cannot be returned.
+	 */
+	public InputStream getIcon(int size) throws IOException;
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/metatype/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/package.html
new file mode 100644
index 0000000..b723698
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/package.html
@@ -0,0 +1,11 @@
+<!-- $Header: /cvshome/build/org.osgi.service.metatype/src/org/osgi/service/metatype/package.html,v 1.4 2004/12/01 19:01:48 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Metatype Package. Specification Version 1.1.
+<p>Bundles wishing to use this package must list the package
+in the <TT>Import-Package</TT> header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.metatype; version=1.1
+</pre>
+</BODY>
+
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/metatype/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/metatype/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/prefs/BackingStoreException.java b/org.osgi.compendium/src/main/java/org/osgi/service/prefs/BackingStoreException.java
new file mode 100644
index 0000000..64e6a2a
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/prefs/BackingStoreException.java
@@ -0,0 +1,82 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.prefs/src/org/osgi/service/prefs/BackingStoreException.java,v 1.10 2006/03/14 01:21:15 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.prefs;
+
+/**
+ * Thrown to indicate that a preferences operation could not complete because of
+ * a failure in the backing store, or a failure to contact the backing store.
+ * 
+ * @version $Revision: 1.10 $
+ */
+public class BackingStoreException extends Exception {
+    static final long serialVersionUID = -1415637364122829574L;
+	/**
+	 * Nested exception.
+	 */
+	private Throwable	cause;
+
+	/**
+	 * Constructs a <code>BackingStoreException</code> with the specified detail
+	 * message.
+	 * 
+	 * @param s The detail message.
+	 */
+	public BackingStoreException(String s) {
+		super(s);
+	}
+	
+	/**
+	 * Constructs a <code>BackingStoreException</code> with the specified detail
+	 * message.
+	 * 
+	 * @param s The detail message.
+	 * @param cause The cause of the exception. May be <code>null</code>.
+	 * @since 1.1 
+	 */
+	public BackingStoreException(String s, Throwable cause) {
+		super(s);
+		this.cause = cause;
+	}
+	
+	/**
+	 * Returns the cause of this exception or <code>null</code> if no cause was
+	 * specified when this exception was created.
+	 * 
+	 * @return The cause of this exception or <code>null</code> if no cause was
+	 *         specified.
+	 * @since 1.1 
+	 */
+	public Throwable getCause() {
+		return cause;
+	}
+
+	/**
+	 * The cause of this exception can only be set when constructed.
+	 * 
+	 * @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.
+	 * @since 1.1 
+	 */
+	public Throwable initCause(Throwable cause) {
+		throw new IllegalStateException();
+	}
+
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/prefs/Preferences.java b/org.osgi.compendium/src/main/java/org/osgi/service/prefs/Preferences.java
new file mode 100644
index 0000000..3917469
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/prefs/Preferences.java
@@ -0,0 +1,702 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.prefs/src/org/osgi/service/prefs/Preferences.java,v 1.9 2006/03/14 01:21:15 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.prefs;
+
+/**
+ * A node in a hierarchical collection of preference data.
+ * 
+ * <p>
+ * This interface allows applications to store and retrieve user and system
+ * preference data. This data is stored persistently in an
+ * implementation-dependent backing store. Typical implementations include flat
+ * files, OS-specific registries, directory servers and SQL databases.
+ * 
+ * <p>
+ * For each bundle, there is a separate tree of nodes for each user, and one for
+ * system preferences. The precise description of "user" and "system" will vary
+ * from one bundle to another. Typical information stored in the user preference
+ * tree might include font choice, and color choice for a bundle which interacts
+ * with the user via a servlet. Typical information stored in the system
+ * preference tree might include installation data, or things like high score
+ * information for a game program.
+ * 
+ * <p>
+ * Nodes in a preference tree are named in a similar fashion to directories in a
+ * hierarchical file system. Every node in a preference tree has a <i>node name
+ * </i> (which is not necessarily unique), a unique <i>absolute path name </i>,
+ * and a path name <i>relative </i> to each ancestor including itself.
+ * 
+ * <p>
+ * The root node has a node name of the empty <code>String</code> object ("").
+ * Every other node has an arbitrary node name, specified at the time it is
+ * created. The only restrictions on this name are that it cannot be the empty
+ * string, and it cannot contain the slash character ('/').
+ * 
+ * <p>
+ * The root node has an absolute path name of <code>"/"</code>. Children of the
+ * root node have absolute path names of <code>"/" + </code> <i>&lt;node name&gt;
+ * </i>. All other nodes have absolute path names of <i>&lt;parent's absolute
+ * path name&gt; </i> <code> + "/" + </code> <i>&lt;node name&gt; </i>. Note that
+ * all absolute path names begin with the slash character.
+ * 
+ * <p>
+ * A node <i>n </i>'s path name relative to its ancestor <i>a </i> is simply the
+ * string that must be appended to <i>a </i>'s absolute path name in order to
+ * form <i>n </i>'s absolute path name, with the initial slash character (if
+ * present) removed. Note that:
+ * <ul>
+ * <li>No relative path names begin with the slash character.
+ * <li>Every node's path name relative to itself is the empty string.
+ * <li>Every node's path name relative to its parent is its node name (except
+ * for the root node, which does not have a parent).
+ * <li>Every node's path name relative to the root is its absolute path name
+ * with the initial slash character removed.
+ * </ul>
+ * 
+ * <p>
+ * Note finally that:
+ * <ul>
+ * <li>No path name contains multiple consecutive slash characters.
+ * <li>No path name with the exception of the root's absolute path name end in
+ * the slash character.
+ * <li>Any string that conforms to these two rules is a valid path name.
+ * </ul>
+ * 
+ * <p>
+ * Each <code>Preference</code> node has zero or more properties associated with
+ * it, where a property consists of a name and a value. The bundle writer is
+ * free to choose any appropriate names for properties. Their values can be of
+ * type <code>String</code>,<code>long</code>,<code>int</code>,<code>boolean</code>,
+ * <code>byte[]</code>,<code>float</code>, or <code>double</code> but they can
+ * always be accessed as if they were <code>String</code> objects.
+ * 
+ * <p>
+ * All node name and property name comparisons are case-sensitive.
+ * 
+ * <p>
+ * All of the methods that modify preference data are permitted to operate
+ * asynchronously; they may return immediately, and changes will eventually
+ * propagate to the persistent backing store, with an implementation-dependent
+ * delay. The <code>flush</code> method may be used to synchronously force updates
+ * to the backing store.
+ * 
+ * <p>
+ * Implementations must automatically attempt to flush to the backing store any
+ * pending updates for a bundle's preferences when the bundle is stopped or
+ * otherwise ungets the Preferences Service.
+ * 
+ * <p>
+ * The methods in this class may be invoked concurrently by multiple threads in
+ * a single Java Virtual Machine (JVM) without the need for external
+ * synchronization, and the results will be equivalent to some serial execution.
+ * If this class is used concurrently <i>by multiple JVMs </i> that store their
+ * preference data in the same backing store, the data store will not be
+ * corrupted, but no other guarantees are made concerning the consistency of the
+ * preference data.
+ * 
+ * 
+ * @version $Revision: 1.9 $
+ */
+public interface Preferences {
+	/**
+	 * Associates the specified value with the specified key in this node.
+	 * 
+	 * @param key key with which the specified value is to be associated.
+	 * @param value value to be associated with the specified key.
+	 * @throws NullPointerException if <code>key</code> or <code>value</code> is
+	 *         <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 */
+	public void put(String key, String value);
+
+	/**
+	 * Returns the value associated with the specified <code>key</code> in this
+	 * node. Returns the specified default if there is no value associated with
+	 * the <code>key</code>, or the backing store is inaccessible.
+	 * 
+	 * @param key key whose associated value is to be returned.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the backing store is
+	 *        inaccessible.
+	 * @return the value associated with <code>key</code>, or <code>def</code> if
+	 *         no value is associated with <code>key</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>. (A
+	 *         <code>null</code> default <i>is </i> permitted.)
+	 */
+	public String get(String key, String def);
+
+	/**
+	 * Removes the value associated with the specified <code>key</code> in this
+	 * node, if any.
+	 * 
+	 * @param key key whose mapping is to be removed from this node.
+	 * @see #get(String,String)
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 */
+	public void remove(String key);
+
+	/**
+	 * Removes all of the properties (key-value associations) in this node. This
+	 * call has no effect on any descendants of this node.
+	 * 
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #remove(String)
+	 */
+	public void clear() throws BackingStoreException;
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>int</code> value with the specified <code>key</code> in this node. The
+	 * associated string is the one that would be returned if the <code>int</code>
+	 * value were passed to <code>Integer.toString(int)</code>. This method is
+	 * intended for use in conjunction with {@link #getInt}method.
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the property value
+	 * be represented by a <code>String</code> object in the backing store. If the
+	 * backing store supports integer values, it is not unreasonable to use
+	 * them. This implementation detail is not visible through the
+	 * <code>Preferences</code> API, which allows the value to be read as an
+	 * <code>int</code> (with <code>getInt</code> or a <code>String</code> (with
+	 * <code>get</code>) type.
+	 * 
+	 * @param key key with which the string form of value is to be associated.
+	 * @param value <code>value</code> whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #getInt(String,int)
+	 */
+	public void putInt(String key, int value);
+
+	/**
+	 * Returns the <code>int</code> value represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. The
+	 * <code>String</code> object is converted to an <code>int</code> as by
+	 * <code>Integer.parseInt(String)</code>. Returns the specified default if
+	 * there is no value associated with the <code>key</code>, the backing store
+	 * is inaccessible, or if <code>Integer.parseInt(String)</code> would throw a
+	 * <code>NumberFormatException</code> if the associated <code>value</code> were
+	 * passed. This method is intended for use in conjunction with the
+	 * {@link #putInt}method.
+	 * 
+	 * @param key key whose associated value is to be returned as an
+	 *        <code>int</code>.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as an <code>int</code> or the backing store is
+	 *        inaccessible.
+	 * @return the <code>int</code> value represented by the <code>String</code>
+	 *         object associated with <code>key</code> in this node, or
+	 *         <code>def</code> if the associated value does not exist or cannot
+	 *         be interpreted as an <code>int</code> type.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #putInt(String,int)
+	 * @see #get(String,String)
+	 */
+	public int getInt(String key, int def);
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>long</code> value with the specified <code>key</code> in this node. The
+	 * associated <code>String</code> object is the one that would be returned if
+	 * the <code>long</code> value were passed to <code>Long.toString(long)</code>.
+	 * This method is intended for use in conjunction with the {@link #getLong}
+	 * method.
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the <code>value</code>
+	 * be represented by a <code>String</code> type in the backing store. If the
+	 * backing store supports <code>long</code> values, it is not unreasonable to
+	 * use them. This implementation detail is not visible through the <code>
+	 * Preferences</code> API, which allows the value to be read as a
+	 * <code>long</code> (with <code>getLong</code> or a <code>String</code> (with
+	 * <code>get</code>) type.
+	 * 
+	 * @param key <code>key</code> with which the string form of <code>value</code>
+	 *        is to be associated.
+	 * @param value <code>value</code> whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #getLong(String,long)
+	 */
+	public void putLong(String key, long value);
+
+	/**
+	 * Returns the <code>long</code> value represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. The
+	 * <code>String</code> object is converted to a <code>long</code> as by
+	 * <code>Long.parseLong(String)</code>. Returns the specified default if
+	 * there is no value associated with the <code>key</code>, the backing store
+	 * is inaccessible, or if <code>Long.parseLong(String)</code> would throw a
+	 * <code>NumberFormatException</code> if the associated <code>value</code> were
+	 * passed. This method is intended for use in conjunction with the
+	 * {@link #putLong}method.
+	 * 
+	 * @param key <code>key</code> whose associated value is to be returned as a
+	 *        <code>long</code> value.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as a <code>long</code> type or the backing
+	 *        store is inaccessible.
+	 * @return the <code>long</code> value represented by the <code>String</code>
+	 *         object associated with <code>key</code> in this node, or
+	 *         <code>def</code> if the associated value does not exist or cannot
+	 *         be interpreted as a <code>long</code> type.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #putLong(String,long)
+	 * @see #get(String,String)
+	 */
+	public long getLong(String key, long def);
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>boolean</code> value with the specified key in this node. The
+	 * associated string is "true" if the value is <code>true</code>, and "false"
+	 * if it is <code>false</code>. This method is intended for use in
+	 * conjunction with the {@link #getBoolean}method.
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the value be
+	 * represented by a string in the backing store. If the backing store
+	 * supports <code>boolean</code> values, it is not unreasonable to use them.
+	 * This implementation detail is not visible through the <code>Preferences
+	 * </code> API, which allows the value to be read as a <code>boolean</code>
+	 * (with <code>getBoolean</code>) or a <code>String</code> (with <code>get</code>)
+	 * type.
+	 * 
+	 * @param key <code>key</code> with which the string form of value is to be
+	 *        associated.
+	 * @param value value whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #getBoolean(String,boolean)
+	 * @see #get(String,String)
+	 */
+	public void putBoolean(String key, boolean value);
+
+	/**
+	 * Returns the <code>boolean</code> value represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. Valid
+	 * strings are "true", which represents <code>true</code>, and "false", which
+	 * represents <code>false</code>. Case is ignored, so, for example, "TRUE"
+	 * and "False" are also valid. This method is intended for use in
+	 * conjunction with the {@link #putBoolean}method.
+	 * 
+	 * <p>
+	 * Returns the specified default if there is no value associated with the
+	 * <code>key</code>, the backing store is inaccessible, or if the associated
+	 * value is something other than "true" or "false", ignoring case.
+	 * 
+	 * @param key <code>key</code> whose associated value is to be returned as a
+	 *        <code>boolean</code>.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as a <code>boolean</code> or the backing store
+	 *        is inaccessible.
+	 * @return the <code>boolean</code> value represented by the <code>String</code>
+	 *         object associated with <code>key</code> in this node, or
+	 *         <code>null</code> if the associated value does not exist or cannot
+	 *         be interpreted as a <code>boolean</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #get(String,String)
+	 * @see #putBoolean(String,boolean)
+	 */
+	public boolean getBoolean(String key, boolean def);
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>float</code> value with the specified <code>key</code> in this node.
+	 * The associated <code>String</code> object is the one that would be returned
+	 * if the <code>float</code> value were passed to
+	 * <code>Float.toString(float)</code>. This method is intended for use in
+	 * conjunction with the {@link #getFloat}method.
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the value be
+	 * represented by a string in the backing store. If the backing store
+	 * supports <code>float</code> values, it is not unreasonable to use them.
+	 * This implementation detail is not visible through the <code>Preferences
+	 * </code> API, which allows the value to be read as a <code>float</code> (with
+	 * <code>getFloat</code>) or a <code>String</code> (with <code>get</code>) type.
+	 * 
+	 * @param key <code>key</code> with which the string form of value is to be
+	 *        associated.
+	 * @param value value whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #getFloat(String,float)
+	 */
+	public void putFloat(String key, float value);
+
+	/**
+	 * Returns the float <code>value</code> represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. The
+	 * <code>String</code> object is converted to a <code>float</code> value as by
+	 * <code>Float.parseFloat(String)</code>. Returns the specified default if
+	 * there is no value associated with the <code>key</code>, the backing store
+	 * is inaccessible, or if <code>Float.parseFloat(String)</code> would throw a
+	 * <code>NumberFormatException</code> if the associated value were passed.
+	 * This method is intended for use in conjunction with the {@link #putFloat}
+	 * method.
+	 * 
+	 * @param key <code>key</code> whose associated value is to be returned as a
+	 *        <code>float</code> value.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as a <code>float</code> type or the backing
+	 *        store is inaccessible.
+	 * @return the <code>float</code> value represented by the string associated
+	 *         with <code>key</code> in this node, or <code>def</code> if the
+	 *         associated value does not exist or cannot be interpreted as a
+	 *         <code>float</code> type.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @see #putFloat(String,float)
+	 * @see #get(String,String)
+	 */
+	public float getFloat(String key, float def);
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>double</code> value with the specified <code>key</code> in this node.
+	 * The associated <code>String</code> object is the one that would be returned
+	 * if the <code>double</code> value were passed to
+	 * <code>Double.toString(double)</code>. This method is intended for use in
+	 * conjunction with the {@link #getDouble}method
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the value be
+	 * represented by a string in the backing store. If the backing store
+	 * supports <code>double</code> values, it is not unreasonable to use them.
+	 * This implementation detail is not visible through the <code>Preferences
+	 * </code> API, which allows the value to be read as a <code>double</code> (with
+	 * <code>getDouble</code>) or a <code>String</code> (with <code>get</code>)
+	 * type.
+	 * 
+	 * @param key <code>key</code> with which the string form of value is to be
+	 *        associated.
+	 * @param value value whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #getDouble(String,double)
+	 */
+	public void putDouble(String key, double value);
+
+	/**
+	 * Returns the <code>double</code> value represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. The
+	 * <code>String</code> object is converted to a <code>double</code> value as by
+	 * <code>Double.parseDouble(String)</code>. Returns the specified default if
+	 * there is no value associated with the <code>key</code>, the backing store
+	 * is inaccessible, or if <code>Double.parseDouble(String)</code> would throw
+	 * a <code>NumberFormatException</code> if the associated value were passed.
+	 * This method is intended for use in conjunction with the
+	 * {@link #putDouble}method.
+	 * 
+	 * @param key <code>key</code> whose associated value is to be returned as a
+	 *        <code>double</code> value.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as a <code>double</code> type or the backing
+	 *        store is inaccessible.
+	 * @return the <code>double</code> value represented by the <code>String</code>
+	 *         object associated with <code>key</code> in this node, or
+	 *         <code>def</code> if the associated value does not exist or cannot
+	 *         be interpreted as a <code>double</code> type.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the the {@link #removeNode()}method.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @see #putDouble(String,double)
+	 * @see #get(String,String)
+	 */
+	public double getDouble(String key, double def);
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>byte[]</code> with the specified <code>key</code> in this node. The
+	 * associated <code>String</code> object the <i>Base64 </i> encoding of the
+	 * <code>byte[]</code>, as defined in <a
+	 * href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 </a>, Section 6.8,
+	 * with one minor change: the string will consist solely of characters from
+	 * the <i>Base64 Alphabet </i>; it will not contain any newline characters.
+	 * This method is intended for use in conjunction with the
+	 * {@link #getByteArray}method.
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the value be
+	 * represented by a <code>String</code> type in the backing store. If the
+	 * backing store supports <code>byte[]</code> values, it is not unreasonable
+	 * to use them. This implementation detail is not visible through the <code>
+	 * Preferences</code> API, which allows the value to be read as an a
+	 * <code>byte[]</code> object (with <code>getByteArray</code>) or a
+	 * <code>String</code> object (with <code>get</code>).
+	 * 
+	 * @param key <code>key</code> with which the string form of <code>value</code>
+	 *        is to be associated.
+	 * @param value <code>value</code> whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> or <code>value</code> is
+	 *         <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #getByteArray(String,byte[])
+	 * @see #get(String,String)
+	 */
+	public void putByteArray(String key, byte[] value);
+
+	/**
+	 * Returns the <code>byte[]</code> value represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. Valid
+	 * <code>String</code> objects are <i>Base64 </i> encoded binary data, as
+	 * defined in <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 </a>,
+	 * Section 6.8, with one minor change: the string must consist solely of
+	 * characters from the <i>Base64 Alphabet </i>; no newline characters or
+	 * extraneous characters are permitted. This method is intended for use in
+	 * conjunction with the {@link #putByteArray}method.
+	 * 
+	 * <p>
+	 * Returns the specified default if there is no value associated with the
+	 * <code>key</code>, the backing store is inaccessible, or if the associated
+	 * value is not a valid Base64 encoded byte array (as defined above).
+	 * 
+	 * @param key <code>key</code> whose associated value is to be returned as a
+	 *        <code>byte[]</code> object.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as a <code>byte[]</code> type, or the backing
+	 *        store is inaccessible.
+	 * @return the <code>byte[]</code> value represented by the <code>String</code>
+	 *         object associated with <code>key</code> in this node, or
+	 *         <code>def</code> if the associated value does not exist or cannot
+	 *         be interpreted as a <code>byte[]</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>. (A
+	 *         <code>null</code> value for <code>def</code> <i>is </i> permitted.)
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #get(String,String)
+	 * @see #putByteArray(String,byte[])
+	 */
+	public byte[] getByteArray(String key, byte[] def);
+
+	/**
+	 * Returns all of the keys that have an associated value in this node. (The
+	 * returned array will be of size zero if this node has no preferences and
+	 * not <code>null</code>!)
+	 * 
+	 * @return an array of the keys that have an associated value in this node.
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 */
+	public String[] keys() throws BackingStoreException;
+
+	/**
+	 * Returns the names of the children of this node. (The returned array will
+	 * be of size zero if this node has no children and not <code>null</code>!)
+	 * 
+	 * @return the names of the children of this node.
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 */
+	public String[] childrenNames() throws BackingStoreException;
+
+	/**
+	 * Returns the parent of this node, or <code>null</code> if this is the root.
+	 * 
+	 * @return the parent of this node.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 */
+	public Preferences parent();
+
+	/**
+	 * Returns a named <code>Preferences</code> object (node), creating it and any
+	 * of its ancestors if they do not already exist. Accepts a relative or
+	 * absolute pathname. Absolute pathnames (which begin with <code>'/'</code>)
+	 * are interpreted relative to the root of this node. Relative pathnames
+	 * (which begin with any character other than <code>'/'</code>) are
+	 * interpreted relative to this node itself. The empty string (<code>""</code>)
+	 * is a valid relative pathname, referring to this node itself.
+	 * 
+	 * <p>
+	 * If the returned node did not exist prior to this call, this node and any
+	 * ancestors that were created by this call are not guaranteed to become
+	 * persistent until the <code>flush</code> method is called on the returned
+	 * node (or one of its descendants).
+	 * 
+	 * @param pathName the path name of the <code>Preferences</code> object to
+	 *        return.
+	 * @return the specified <code>Preferences</code> object.
+	 * @throws IllegalArgumentException if the path name is invalid.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @throws NullPointerException if path name is <code>null</code>.
+	 * @see #flush()
+	 */
+	public Preferences node(String pathName);
+
+	/**
+	 * Returns true if the named node exists. Accepts a relative or absolute
+	 * pathname. Absolute pathnames (which begin with <code>'/'</code>) are
+	 * interpreted relative to the root of this node. Relative pathnames (which
+	 * begin with any character other than <code>'/'</code>) are interpreted
+	 * relative to this node itself. The pathname <code>""</code> is valid, and
+	 * refers to this node itself.
+	 * 
+	 * <p>
+	 * If this node (or an ancestor) has already been removed with the
+	 * {@link #removeNode()}method, it <i>is </i> legal to invoke this method,
+	 * but only with the pathname <code>""</code>; the invocation will return
+	 * <code>false</code>. Thus, the idiom <code>p.nodeExists("")</code> may be
+	 * used to test whether <code>p</code> has been removed.
+	 * 
+	 * @param pathName the path name of the node whose existence is to be
+	 *        checked.
+	 * @return true if the specified node exists.
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method and
+	 *         <code>pathname</code> is not the empty string (<code>""</code>).
+	 * @throws IllegalArgumentException if the path name is invalid (i.e., it
+	 *         contains multiple consecutive slash characters, or ends with a
+	 *         slash character and is more than one character long).
+	 */
+	public boolean nodeExists(String pathName)
+			throws BackingStoreException;
+
+	/**
+	 * Removes this node and all of its descendants, invalidating any properties
+	 * contained in the removed nodes. Once a node has been removed, attempting
+	 * any method other than <code>name()</code>,<code>absolutePath()</code> or
+	 * <code>nodeExists("")</code> on the corresponding <code>Preferences</code>
+	 * instance will fail with an <code>IllegalStateException</code>. (The
+	 * methods defined on <code>Object</code> can still be invoked on a node after
+	 * it has been removed; they will not throw <code>IllegalStateException</code>.)
+	 * 
+	 * <p>
+	 * The removal is not guaranteed to be persistent until the <code>flush</code>
+	 * method is called on the parent of this node.
+	 * 
+	 * @throws IllegalStateException if this node (or an ancestor) has already
+	 *         been removed with the {@link #removeNode()}method.
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @see #flush()
+	 */
+	public void removeNode() throws BackingStoreException;
+
+	/**
+	 * Returns this node's name, relative to its parent.
+	 * 
+	 * @return this node's name, relative to its parent.
+	 */
+	public String name();
+
+	/**
+	 * Returns this node's absolute path name. Note that:
+	 * <ul>
+	 * <li>Root node - The path name of the root node is <code>"/"</code>.
+	 * <li>Slash at end - Path names other than that of the root node may not
+	 * end in slash (<code>'/'</code>).
+	 * <li>Unusual names -<code>"."</code> and <code>".."</code> have <i>no </i>
+	 * special significance in path names.
+	 * <li>Illegal names - The only illegal path names are those that contain
+	 * multiple consecutive slashes, or that end in slash and are not the root.
+	 * </ul>
+	 * 
+	 * @return this node's absolute path name.
+	 */
+	public String absolutePath();
+
+	/**
+	 * Forces any changes in the contents of this node and its descendants to
+	 * the persistent store.
+	 * 
+	 * <p>
+	 * Once this method returns successfully, it is safe to assume that all
+	 * changes made in the subtree rooted at this node prior to the method
+	 * invocation have become permanent.
+	 * 
+	 * <p>
+	 * Implementations are free to flush changes into the persistent store at
+	 * any time. They do not need to wait for this method to be called.
+	 * 
+	 * <p>
+	 * When a flush occurs on a newly created node, it is made persistent, as
+	 * are any ancestors (and descendants) that have yet to be made persistent.
+	 * Note however that any properties value changes in ancestors are <i>not
+	 * </i> guaranteed to be made persistent.
+	 * 
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #sync()
+	 */
+	public void flush() throws BackingStoreException;
+
+	/**
+	 * Ensures that future reads from this node and its descendants reflect any
+	 * changes that were committed to the persistent store (from any VM) prior
+	 * to the <code>sync</code> invocation. As a side-effect, forces any changes
+	 * in the contents of this node and its descendants to the persistent store,
+	 * as if the <code>flush</code> method had been invoked on this node.
+	 * 
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()}method.
+	 * @see #flush()
+	 */
+	public void sync() throws BackingStoreException;
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/prefs/PreferencesService.java b/org.osgi.compendium/src/main/java/org/osgi/service/prefs/PreferencesService.java
new file mode 100644
index 0000000..7f28b3a
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/prefs/PreferencesService.java
@@ -0,0 +1,56 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.prefs/src/org/osgi/service/prefs/PreferencesService.java,v 1.9 2006/03/14 01:21:15 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.prefs;
+
+/**
+ * The Preferences Service.
+ * 
+ * <p>
+ * Each bundle using this service has its own set of preference trees: one for
+ * system preferences, and one for each user.
+ * 
+ * <p>
+ * A <code>PreferencesService</code> object is specific to the bundle which
+ * obtained it from the service registry. If a bundle wishes to allow another
+ * bundle to access its preferences, it should pass its
+ * <code>PreferencesService</code> object to that bundle.
+ *  
+ */
+public interface PreferencesService {
+	/**
+	 * Returns the root system node for the calling bundle.
+	 * 
+	 * @return The root system node for the calling bundle.
+	 */
+	public Preferences getSystemPreferences();
+
+	/**
+	 * Returns the root node for the specified user and the calling bundle.
+	 * 
+	 * @param name The user for which to return the preference root node. 
+	 * @return The root node for the specified user and the calling bundle.
+	 */
+	public Preferences getUserPreferences(String name);
+
+	/**
+	 * Returns the names of users for which node trees exist.
+	 * 
+	 * @return The names of users for which node trees exist.
+	 */
+	public String[] getUsers();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/prefs/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/prefs/package.html
new file mode 100644
index 0000000..38e8d80
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/prefs/package.html
@@ -0,0 +1,11 @@
+<!-- $Header: /cvshome/build/org.osgi.service.prefs/src/org/osgi/service/prefs/package.html,v 1.3 2004/12/03 19:30:27 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Preferences Service Package. Specification 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.prefs; version=1.1
+</pre>
+</BODY>
+
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/prefs/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/prefs/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/prefs/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/provisioning/ProvisioningService.java b/org.osgi.compendium/src/main/java/org/osgi/service/provisioning/ProvisioningService.java
new file mode 100644
index 0000000..0678357
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/provisioning/ProvisioningService.java
@@ -0,0 +1,181 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.provisioning/src/org/osgi/service/provisioning/ProvisioningService.java,v 1.9 2006/03/14 01:21:04 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.provisioning;
+
+import java.util.Dictionary;
+import java.util.zip.ZipInputStream;
+import java.io.IOException;
+
+/**
+ * Service for managing the initial provisioning information.
+ * <p>
+ * Initial provisioning of an OSGi device is a multi step process that
+ * culminates with the installation and execution of the initial management
+ * agent. At each step of the process, information is collected for the next
+ * step. Multiple bundles may be involved and this service provides a means for
+ * these bundles to exchange information. It also provides a means for the
+ * initial Management Bundle to get its initial configuration information.
+ * <p>
+ * The provisioning information is collected in a <code>Dictionary</code> object,
+ * called the Provisioning Dictionary. Any bundle that can access the service
+ * can get a reference to this object and read and update provisioning
+ * information. The key of the dictionary is a <code>String</code> object and the
+ * value is a <code>String</code> or <code>byte[]</code> object. The single
+ * exception is the PROVISIONING_UPDATE_COUNT value which is an Integer. The
+ * <code>provisioning</code> prefix is reserved for keys defined by OSGi, other
+ * key names may be used for implementation dependent provisioning systems.
+ * <p>
+ * Any changes to the provisioning information will be reflected immediately in
+ * all the dictionary objects obtained from the Provisioning Service.
+ * <p>
+ * Because of the specific application of the Provisioning Service, there should
+ * be only one Provisioning Service registered. This restriction will not be
+ * enforced by the Framework. Gateway operators or manufactures should ensure
+ * that a Provisioning Service bundle is not installed on a device that already
+ * has a bundle providing the Provisioning Service.
+ * <p>
+ * The provisioning information has the potential to contain sensitive
+ * information. Also, the ability to modify provisioning information can have
+ * drastic consequences. Thus, only trusted bundles should be allowed to
+ * register and get the Provisioning Service. The <code>ServicePermission</code>
+ * is used to limit the bundles that can gain access to the Provisioning
+ * Service. There is no check of <code>Permission</code> objects to read or modify
+ * the provisioning information, so care must be taken not to leak the
+ * Provisioning Dictionary received from <code>getInformation</code> method.
+ * 
+ * @version $Revision: 1.9 $
+ */
+public interface ProvisioningService {
+	/**
+	 * The key to the provisioning information that uniquely identifies the
+	 * Service Platform. The value must be of type <code>String</code>.
+	 */
+	public final static String	PROVISIONING_SPID			= "provisioning.spid";
+	/**
+	 * The key to the provisioning information that contains the location of the
+	 * provision data provider. The value must be of type <code>String</code>.
+	 */
+	public final static String	PROVISIONING_REFERENCE		= "provisioning.reference";
+	/**
+	 * The key to the provisioning information that contains the initial
+	 * configuration information of the initial Management Agent. The value will
+	 * be of type <code>byte[]</code>.
+	 */
+	public final static String	PROVISIONING_AGENT_CONFIG	= "provisioning.agent.config";
+	/**
+	 * The key to the provisioning information that contains the update count of
+	 * the info data. Each set of changes to the provisioning information must
+	 * end with this value being incremented. The value must be of type
+	 * <code>Integer</code>. This key/value pair is also reflected in the
+	 * properties of the ProvisioningService in the service registry.
+	 */
+	public final static String	PROVISIONING_UPDATE_COUNT	= "provisioning.update.count";
+	/**
+	 * The key to the provisioning information that contains the location of the
+	 * bundle to start with <code>AllPermission</code>. The bundle must have be
+	 * previously installed for this entry to have any effect.
+	 */
+	public final static String	PROVISIONING_START_BUNDLE	= "provisioning.start.bundle";
+	/**
+	 * The key to the provisioning information that contains the root X509
+	 * certificate used to esatblish trust with operator when using HTTPS.
+	 */
+	public final static String	PROVISIONING_ROOTX509		= "provisioning.rootx509";
+	/**
+	 * The key to the provisioning information that contains the shared secret
+	 * used in conjunction with the RSH protocol.
+	 */
+	public final static String	PROVISIONING_RSH_SECRET		= "provisioning.rsh.secret";
+	/**
+	 * MIME type to be stored in the extra field of a <code>ZipEntry</code> object
+	 * for String data.
+	 */
+	public final static String	MIME_STRING					= "text/plain;charset=utf-8";
+	/**
+	 * MIME type to be stored in the extra field of a <code>ZipEntry</code> object
+	 * for <code>byte[]</code> data.
+	 */
+	public final static String	MIME_BYTE_ARRAY				= "application/octet-stream";
+	/**
+	 * MIME type to be stored in the extra field of a <code>ZipEntry</code> object
+	 * for an installable bundle file. Zip entries of this type will be
+	 * installed in the framework, but not started. The entry will also not be
+	 * put into the information dictionary.
+	 */
+	public final static String	MIME_BUNDLE					= "application/x-osgi-bundle";
+	/**
+	 * MIME type to be stored in the extra field of a ZipEntry for a String that
+	 * represents a URL for a bundle. Zip entries of this type will be used to
+	 * install (but not start) a bundle from the URL. The entry will not be put
+	 * into the information dictionary.
+	 */
+	public final static String	MIME_BUNDLE_URL				= "text/x-osgi-bundle-url";
+
+	/**
+	 * Returns a reference to the Provisioning Dictionary. Any change operations
+	 * (put and remove) to the dictionary will cause an
+	 * <code>UnsupportedOperationException</code> to be thrown. Changes must be
+	 * done using the <code>setInformation</code> and <code>addInformation</code>
+	 * methods of this service.
+	 * @return A reference to the Provisioning Dictionary.
+	 */
+	public Dictionary getInformation();
+
+	/**
+	 * Replaces the Provisioning Information dictionary with the key/value pairs
+	 * contained in <code>info</code>. Any key/value pairs not in <code>info</code>
+	 * will be removed from the Provisioning Information dictionary. This method
+	 * causes the <code>PROVISIONING_UPDATE_COUNT</code> to be incremented.
+	 * 
+	 * @param info the new set of Provisioning Information key/value pairs. Any
+	 *        keys are values that are of an invalid type will be silently
+	 *        ignored.
+	 */
+	public void setInformation(Dictionary info);
+
+	/**
+	 * Adds the key/value pairs contained in <code>info</code> to the Provisioning
+	 * Information dictionary. This method causes the
+	 * <code>PROVISIONING_UPDATE_COUNT</code> to be incremented.
+	 * 
+	 * @param info the set of Provisioning Information key/value pairs to add to
+	 *        the Provisioning Information dictionary. Any keys are values that
+	 *        are of an invalid type will be silently ignored.
+	 */
+	public void addInformation(Dictionary info);
+
+	/**
+	 * Processes the <code>ZipInputStream</code> and extracts information to add
+	 * to the Provisioning Information dictionary, as well as, install/update
+	 * and start bundles. This method causes the
+	 * <code>PROVISIONING_UPDATE_COUNT</code> to be incremented.
+	 * 
+	 * @param zis the <code>ZipInputStream</code> that will be used to add
+	 *        key/value pairs to the Provisioning Information dictionary and
+	 *        install and start bundles. If a <code>ZipEntry</code> does not have
+	 *        an <code>Extra</code> field that corresponds to one of the four
+	 *        defined MIME types (<code>MIME_STRING</code>,
+	 *        <code>MIME_BYTE_ARRAY</code>,<code>MIME_BUNDLE</code>, and
+	 *        <code>MIME_BUNDLE_URL</code>) in will be silently ignored.
+	 * @throws IOException if an error occurs while processing the
+	 *            ZipInputStream. No additions will be made to the Provisioning
+	 *            Information dictionary and no bundles must be started or
+	 *            installed.
+	 */
+	public void addInformation(ZipInputStream zis) throws IOException;
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/provisioning/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/provisioning/package.html
new file mode 100644
index 0000000..d1ed341
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/provisioning/package.html
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.service.provisioning/src/org/osgi/service/provisioning/package.html,v 1.3 2005/08/10 02:16:40 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Provisioning Service Package. Specification 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.provisioning; version=1.1
+</pre>
+</BODY>
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/provisioning/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/provisioning/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/provisioning/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPAction.java b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPAction.java
new file mode 100644
index 0000000..764f2a2
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPAction.java
@@ -0,0 +1,121 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.upnp/src/org/osgi/service/upnp/UPnPAction.java,v 1.9 2006/03/14 01:21:11 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.upnp;
+
+import java.util.Dictionary;
+
+/**
+ * A UPnP action.
+ * 
+ * Each UPnP service contains zero or more actions. Each action may have zero or
+ * more UPnP state variables as arguments.
+ *  
+ */
+public interface UPnPAction {
+	/**
+	 * Returns the action name.
+	 * 
+	 * The action name corresponds to the <code>name</code> field in the
+	 * <code>actionList</code> of the service description.
+	 * <ul>
+	 * <li>For standard actions defined by a UPnP Forum working committee,
+	 * action names must not begin with <code>X_ </code> nor <code> A_</code>.</li>
+	 * <li>For non-standard actions specified by a UPnP vendor and added to a
+	 * standard service, action names must begin with <code>X_</code>.</li>
+	 * </ul>
+	 * 
+	 * @return Name of action, must not contain a hyphen character or a hash
+	 *         character
+	 */
+	String getName();
+
+	/**
+	 * Returns the name of the designated return argument.
+	 * <p>
+	 * One of the output arguments can be flagged as a designated return
+	 * argument.
+	 * 
+	 * @return The name of the designated return argument or <code>null</code> if
+	 *         none is marked.
+	 */
+	String getReturnArgumentName();
+
+	/**
+	 * Lists all input arguments for this action.
+	 * <p>
+	 * Each action may have zero or more input arguments.
+	 * 
+	 * @return Array of input argument names or <code>null</code> if no input
+	 *         arguments.
+	 * 
+	 * @see UPnPStateVariable
+	 */
+	String[] getInputArgumentNames();
+
+	/**
+	 * List all output arguments for this action.
+	 * 
+	 * @return Array of output argument names or <code>null</code> if there are no
+	 *         output arguments.
+	 * 
+	 * @see UPnPStateVariable
+	 */
+	String[] getOutputArgumentNames();
+
+	/**
+	 * Finds the state variable associated with an argument name.
+	 * 
+	 * Helps to resolve the association of state variables with argument names
+	 * in UPnP actions.
+	 * 
+	 * @param argumentName The name of the UPnP action argument.
+	 * @return State variable associated with the named argument or
+	 *         <code>null</code> if there is no such argument.
+	 * 
+	 * @see UPnPStateVariable
+	 */
+	UPnPStateVariable getStateVariable(String argumentName);
+
+	/**
+	 * Invokes the action.
+	 * 
+	 * The input and output arguments are both passed as <code>Dictionary</code>
+	 * objects. Each entry in the <code>Dictionary</code> object has a
+	 * <code>String</code> object as key representing the argument name and the
+	 * value is the argument itself. The class of an argument value must be
+	 * assignable from the class of the associated UPnP state variable.
+	 * 
+	 * The input argument <code>Dictionary</code> object must contain exactly
+	 * those arguments listed by <code>getInputArguments</code> method. The output
+	 * argument <code>Dictionary</code> object will contain exactly those
+	 * arguments listed by <code>getOutputArguments</code> method.
+	 *
+	 * @param args A <code>Dictionary</code> of arguments. Must contain the correct set and
+	 * type of arguments for this action. May be <code>null</code> if no
+	 * input arguments exist.
+	 *
+	 * @return A <code>Dictionary</code> with the output arguments.
+	 *         <code>null</code> if the action has no output arguments.
+	 *
+	 * @throws UPnPException  A UPnP error has occured.
+	 * @throws Exception The execution fails for some reason.
+	 *
+	 * @see UPnPStateVariable
+	 */
+	Dictionary invoke(Dictionary args) throws Exception;
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPDevice.java b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPDevice.java
new file mode 100644
index 0000000..b41c242
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPDevice.java
@@ -0,0 +1,281 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.upnp/src/org/osgi/service/upnp/UPnPDevice.java,v 1.8 2006/03/14 01:21:11 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.upnp;
+
+import java.util.Dictionary;
+
+/**
+ * Represents a UPnP device.
+ * 
+ * For each UPnP root and embedded device, an object is registered with the
+ * framework under the <code>UPnPDevice</code> interface.
+ * <p>
+ * The relationship between a root device and its embedded devices can be
+ * deduced using the <code>UPnPDevice.CHILDREN_UDN</code> and
+ * <code>UPnPDevice.PARENT_UDN</code> service registration properties.
+ * <p>
+ * The values of the UPnP property names are defined by the UPnP Forum.
+ * <p>
+ * All values of the UPnP properties are obtained from the device using the
+ * device's default locale.
+ * <p>
+ * If an application wants to query for a set of localized property values, it
+ * has to use the method <code>UPnPDevice.getDescriptions(String locale)</code>.
+ *  
+ */
+public interface UPnPDevice {
+	/*
+	 * Constants for the UPnP device match scale.
+	 */
+	/**
+	 * Constant for the UPnP device match scale, indicating a generic match for
+	 * the device. Value is 1.
+	 */
+	int		MATCH_GENERIC								= 1;
+	/**
+	 * Constant for the UPnP device match scale, indicating a match with the
+	 * device type. Value is 3.
+	 */
+	int		MATCH_TYPE									= 3;
+	/**
+	 * Constant for the UPnP device match scale, indicating a match with the
+	 * device model. Value is 7.
+	 */
+	int		MATCH_MANUFACTURER_MODEL					= 7;
+	/**
+	 * Constant for the UPnP device match scale, indicating a match with the
+	 * device revision. Value is 15.
+	 */
+	int		MATCH_MANUFACTURER_MODEL_REVISION			= 15;
+	/**
+	 * Constant for the UPnP device match scale, indicating a match with the
+	 * device revision and the serial number. Value is 31.
+	 */
+	int		MATCH_MANUFACTURER_MODEL_REVISION_SERIAL	= 31;
+	/**
+	 * Constant for the value of the service property <code>DEVICE_CATEGORY</code>
+	 * used for all UPnP devices. Value is "UPnP".
+	 * 
+	 * @see "<code>org.osgi.service.device.Constants.DEVICE_CATEGORY</code>"
+	 */
+	String	DEVICE_CATEGORY								= "UPnP";
+	/**
+	 * The <code>UPnP.export</code> service property is a hint that marks a device
+	 * to be picked up and exported by the UPnP Service. Imported devices do not
+	 * have this property set. The registered property requires no value.
+	 * <p>
+	 * The UPNP_EXPORT string is "UPnP.export".
+	 */
+	String	UPNP_EXPORT									= "UPnP.export";
+	/**
+	 * Property key for the Unique Device Name (UDN) property. It is the unique
+	 * identifier of an instance of a <code>UPnPDevice</code>. The value of the
+	 * property is a <code>String</code> object of the Device UDN. Value of the
+	 * key is "UPnP.device.UDN". This property must be set.
+	 */
+	String	UDN											= "UPnP.device.UDN";
+	/**
+	 * Property key for the Unique Device ID property. This property is an alias
+	 * to <code>UPnPDevice.UDN</code>. It is merely provided for reasons of
+	 * symmetry with the <code>UPnPService.ID</code> property. The value of the
+	 * property is a <code>String</code> object of the Device UDN. The value of
+	 * the key is "UPnP.device.UDN".
+	 */
+	String	ID											= UDN;
+	/**
+	 * Property key for the UPnP Device Type property. Some standard property
+	 * values are defined by the Universal Plug and Play Forum. The type string
+	 * also includes a version number as defined in the UPnP specification. This
+	 * property must be set.
+	 * <p>
+	 * For standard devices defined by a UPnP Forum working committee, this must
+	 * consist of the following components in the given order separated by
+	 * colons:
+	 * <ul>
+	 * <li><code>urn</code></li>
+	 * <li>schemas-upnp-org</li>
+	 * <li><code>device</code></li>
+	 * <li>a device type suffix</li>
+	 * <li>an integer device version</li>
+	 * </ul>
+	 * For non-standard devices specified by UPnP vendors following components
+	 * must be specified in the given order separated by colons:
+	 * <ul>
+	 * <li><code>urn</code></li>
+	 * <li>an ICANN domain name owned by the vendor</li>
+	 * <li><code>device</code></li>
+	 * <li>a device type suffix</li>
+	 * <li>an integer device version</li>
+	 * </ul>
+	 * <p>
+	 * To allow for backward compatibility the UPnP driver must automatically
+	 * generate additional Device Type property entries for smaller versions
+	 * than the current one. If for example a device announces its type as
+	 * version 3, then properties for versions 2 and 1 must be automatically
+	 * generated.
+	 * <p>
+	 * In the case of exporting a UPnPDevice, the highest available version must
+	 * be announced on the network.
+	 * <p>
+	 * Syntax Example: <code>urn:schemas-upnp-org:device:deviceType:v</code>
+	 * <p>
+	 * The value is "UPnP.device.type".
+	 */
+	String	TYPE										= "UPnP.device.type";
+	/**
+	 * Mandatory property key for the device manufacturer's property. The
+	 * property value holds a String representation of the device manufacturer's
+	 * name. Value is "UPnP.device.manufacturer".
+	 */
+	String	MANUFACTURER								= "UPnP.device.manufacturer";
+	/**
+	 * Mandatory property key for the device model name. The property value
+	 * holds a <code>String</code> object giving more information about the device
+	 * model. Value is "UPnP.device.modelName".
+	 */
+	String	MODEL_NAME									= "UPnP.device.modelName";
+	/**
+	 * Mandatory property key for a short user friendly version of the device
+	 * name. The property value holds a <code>String</code> object with the user
+	 * friendly name of the device. Value is "UPnP.device.friendlyName".
+	 */
+	String	FRIENDLY_NAME								= "UPnP.device.friendlyName";
+	/**
+	 * Optional property key for a URL to the device manufacturers Web site. The
+	 * value of the property is a <code>String</code> object representing the URL.
+	 * Value is "UPnP.device.manufacturerURL".
+	 */
+	String	MANUFACTURER_URL							= "UPnP.device.manufacturerURL";
+	/**
+	 * Optional (but recommended) property key for a <code>String</code> object
+	 * with a long description of the device for the end user. The value is
+	 * "UPnP.device.modelDescription".
+	 */
+	String	MODEL_DESCRIPTION							= "UPnP.device.modelDescription";
+	/**
+	 * Optional (but recommended) property key for a <code>String</code> class
+	 * typed property holding the model number of the device. Value is
+	 * "UPnP.device.modelNumber".
+	 */
+	String	MODEL_NUMBER								= "UPnP.device.modelNumber";
+	/**
+	 * Optional property key for a <code>String</code> typed property holding a
+	 * string representing the URL to the Web site for this model. Value is
+	 * "UPnP.device.modelURL".
+	 */
+	String	MODEL_URL									= "UPnP.device.modelURL";
+	/**
+	 * Optional (but recommended) property key for a <code>String</code> typed
+	 * property holding the serial number of the device. Value is
+	 * "UPnP.device.serialNumber".
+	 */
+	String	SERIAL_NUMBER								= "UPnP.device.serialNumber";
+	/**
+	 * Optional property key for a <code>String</code> typed property holding the
+	 * Universal Product Code (UPC) of the device. Value is "UPnP.device.UPC".
+	 */
+	String	UPC											= "UPnP.device.UPC";
+	/**
+	 * Optional (but recommended) property key for a <code>String</code> typed
+	 * property holding a string representing the URL to a device representation
+	 * Web page. Value is "UPnP.presentationURL".
+	 */
+	String	PRESENTATION_URL							= "UPnP.presentationURL";
+	/**
+	 * The property key that must be set for all embedded devices. It contains
+	 * the UDN of the parent device. The property is not set for root devices.
+	 * The value is "UPnP.device.parentUDN".
+	 */
+	String	PARENT_UDN									= "UPnP.device.parentUDN";
+	/**
+	 * The property key that must be set for all devices containing other
+	 * embedded devices.
+	 * <p>
+	 * The value is an array of UDNs for each of the device's children (
+	 * <code>String[]</code>). The array contains UDNs for the immediate
+	 * descendants only.
+	 * </p>
+	 * <p>
+	 * If an embedded device in turn contains embedded devices, the latter are
+	 * not included in the array.
+	 * </p>
+	 * The UPnP Specification does not encourage more than two levels of
+	 * nesting.
+	 * <p>
+	 * The property is not set if the device does not contain embedded devices.
+	 * <p>
+	 * The property is of type <code>String[]</code>. Value is
+	 * "UPnP.device.childrenUDN"
+	 */
+	String	CHILDREN_UDN								= "UPnP.device.childrenUDN";
+
+	/**
+	 * Locates a specific service by its service id.
+	 * 
+	 * @param serviceId The service id
+	 * @return The requested service or null if not found.
+	 */
+	UPnPService getService(String serviceId);
+
+	/**
+	 * Lists all services provided by this device.
+	 * 
+	 * @return Array of services or <code>null</code> if no services are
+	 *         available.
+	 */
+	UPnPService[] getServices();
+
+	/**
+	 * Lists all icons for this device in a given locale.
+	 * 
+	 * The UPnP specification allows a device to present different icons based
+	 * on the client's locale.
+	 * 
+	 * @param locale A language tag as defined by RFC 1766 and maintained by ISO
+	 *        639. Examples include "<code>de</code>", "<code>en</code>" or "
+	 *        <code>en-US</code>". The default locale of the device is specified
+	 *        by passing a <code>null</code> argument.
+	 * 
+	 * @return Array of icons or null if no icons are available.
+	 */
+	UPnPIcon[] getIcons(String locale);
+
+	/**
+	 * Get a set of localized UPnP properties.
+	 * 
+	 * The UPnP specification allows a device to present different device
+	 * properties based on the client's locale. The properties used to register
+	 * the UPnPDevice service in the OSGi registry are based on the device's
+	 * default locale. To obtain a localized set of the properties, an
+	 * application can use this method.
+	 * <p>
+	 * Not all properties might be available in all locales. This method does
+	 * <b>not </b> substitute missing properties with their default locale
+	 * versions.
+	 * <p>
+	 * 
+	 * @param locale A language tag as defined by RFC 1766 and maintained by ISO
+	 *        639. Examples include "<code>de</code>", "<code>en</code>" or "
+	 *        <code>en-US</code>". The default locale of the device is specified
+	 *        by passing a <code>null</code> argument.
+	 * @return Dictionary mapping property name Strings to property value
+	 *         Strings
+	 *  
+	 */
+	Dictionary getDescriptions(String locale);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPEventListener.java b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPEventListener.java
new file mode 100644
index 0000000..fb4d893
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPEventListener.java
@@ -0,0 +1,85 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.upnp/src/org/osgi/service/upnp/UPnPEventListener.java,v 1.7 2006/03/14 01:21:11 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.upnp;
+
+import java.util.Dictionary;
+
+/**
+ * UPnP Events are mapped and delivered to applications according to the OSGi
+ * whiteboard model. An application that wishes to be notified of events
+ * generated by a particular UPnP Device registers a service extending this
+ * interface.
+ * <p>
+ * The notification call from the UPnP Service to any <code>UPnPEventListener</code>
+ * object must be done asynchronous with respect to the originator (in a
+ * separate thread).
+ * <p>
+ * Upon registration of the UPnP Event Listener service with the Framework, the
+ * service is notified for each variable which it listens for with an initial
+ * event containing the current value of the variable. Subsequent notifications
+ * only happen on changes of the value of the variable.
+ * <p>
+ * A UPnP Event Listener service filter the events it receives. This event set
+ * is limited using a standard framework filter expression which is specified
+ * when the listener service is registered.
+ * <p>
+ * The filter is specified in a property named "upnp.filter" and has as a value
+ * an object of type <code>org.osgi.framework.Filter</code>.
+ * <p>
+ * When the Filter is evaluated, the folowing keywords are recognized as defined
+ * as literal constants in the <code>UPnPDevice</code> class.
+ * <p>
+ * The valid subset of properties for the registration of UPnP Event Listener
+ * services are:
+ * <ul>
+ * <li><code>UPnPDevice.TYPE</code>-- Which type of device to listen for events.
+ * </li>
+ * <li><code>UPnPDevice.ID</code>-- The ID of a specific device to listen for
+ * events.</li>
+ * <li><code>UPnPService.TYPE</code>-- The type of a specific service to listen
+ * for events.</li>
+ * <li><code>UPnPService.ID</code>-- The ID of a specific service to listen for
+ * events.</li>
+ * </ul>
+ */
+public interface UPnPEventListener {
+	/**
+	 * Key for a service property having a value that is an object of type
+	 * <code>org.osgi.framework.Filter</code> and that is used to limit received
+	 * events.
+	 */
+	static final String	UPNP_FILTER	= "upnp.filter";
+
+	/**
+	 * Callback method that is invoked for received events.
+	 * 
+	 * The events are collected in a <code>Dictionary</code> object. Each entry
+	 * has a <code>String</code> key representing the event name (= state variable
+	 * name) and the new value of the state variable. The class of the value
+	 * object must match the class specified by the UPnP State Variable
+	 * associated with the event. This method must be called asynchronously
+	 * 
+	 * @param deviceId ID of the device sending the events
+	 * @param serviceId ID of the service sending the events
+	 * @param events <code>Dictionary</code> object containing the new values for
+	 *        the state variables that have changed.
+	 * 
+	 *  
+	 */
+	void notifyUPnPEvent(String deviceId, String serviceId, Dictionary events);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPException.java b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPException.java
new file mode 100644
index 0000000..c594801
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPException.java
@@ -0,0 +1,84 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.upnp/src/org/osgi/service/upnp/UPnPException.java,v 1.11 2006/03/14 01:21:11 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2005). 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.upnp;
+
+import java.lang.Exception;
+
+/**
+ * There are several defined error situations describing UPnP problems while a
+ * control point invokes actions to UPnPDevices.
+ * 
+ * @since 1.1
+ */
+public class UPnPException extends Exception {
+	static final long		serialVersionUID		= -262013318122195146L;
+
+	/**
+	 * No Action found by that name at this service.
+	 */
+	public final static int	INVALID_ACTION			= 401;
+
+	/**
+	 * Not enough arguments, too many arguments with a specific name, or one of
+	 * more of the arguments are of the wrong type.
+	 */
+	public final static int	INVALID_ARGS			= 402;
+
+	/**
+	 * The different end-points are no longer in synchronization.
+	 */
+	public final static int	INVALID_SEQUENCE_NUMBER	= 403;
+
+	/**
+	 * Refers to a non existing variable.
+	 */
+	public final static int	INVALID_VARIABLE		= 404;
+
+	/**
+	 * The invoked action failed during execution.
+	 */
+	public final static int	DEVICE_INTERNAL_ERROR	= 501;
+
+	/**
+	 * Key for an error information that is an int type variable and that is
+	 * used to identify occured errors.
+	 */
+	private int				errorCode;
+
+	/**
+	 * This constructor creates a UPnPException on the specified error code and
+	 * error description.
+	 * 
+	 * @param errorCode errorCode which defined UPnP Device Architecture V1.0.
+	 * @param errordesc errorDescription which explain the type of propblem.
+	 */
+	public UPnPException(int errorCode, String errordesc) {
+		super(errordesc);
+		this.errorCode = errorCode;
+	}
+
+	/**
+	 * Returns the UPnPError Code occured by UPnPDevices during invocation.
+	 * 
+	 * @return The UPnPErrorCode defined by a UPnP Forum working committee or
+	 *         specified by a UPnP vendor.
+	 */
+	public int getUPnPError_Code() {
+		return errorCode;
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPIcon.java b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPIcon.java
new file mode 100644
index 0000000..835d8b9
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPIcon.java
@@ -0,0 +1,99 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.upnp/src/org/osgi/service/upnp/UPnPIcon.java,v 1.10 2006/03/14 01:21:11 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.upnp;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * A UPnP icon representation.
+ * 
+ * Each UPnP device can contain zero or more icons.
+ */
+public interface UPnPIcon {
+	/**
+	 * Returns the MIME type of the icon.
+	 * 
+	 * This method returns the format in which the icon graphics, read from the
+	 * <code>InputStream</code> object obtained by the <code>getInputStream()</code>
+	 * method, is encoded.
+	 * <p>
+	 * The format of the returned string is in accordance to RFC2046. A list of
+	 * valid MIME types is maintained by the <a
+	 * href="http://www.iana.org/assignments/media-types/">IANA</a>.
+	 * <p>
+	 * Typical values returned include: "image/jpeg" or "image/gif"
+	 * 
+	 * @return The MIME type of the encoded icon.
+	 */
+	String getMimeType();
+
+	/**
+	 * Returns the width of the icon in pixels.
+	 * 
+	 * If the actual width of the icon is unknown, -1 is returned.
+	 * 
+	 * @return The width in pixels, or -1 if unknown.
+	 */
+	int getWidth();
+
+	/**
+	 * Returns the height of the icon in pixels.
+	 * 
+	 * If the actual height of the icon is unknown, -1 is returned.
+	 * 
+	 * @return The height in pixels, or -1 if unknown.
+	 */
+	int getHeight();
+
+	/**
+	 * Returns the size of the icon in bytes.
+	 * 
+	 * This method returns the number of bytes of the icon available to read
+	 * from the <code>InputStream</code> object obtained by the
+	 * <code>getInputStream()</code> method. If the actual size can not be
+	 * determined, -1 is returned.
+	 * 
+	 * @return The icon size in bytes, or -1 if the size is unknown.
+	 */
+	int getSize();
+
+	/**
+	 * Returns the color depth of the icon in bits.
+	 * 
+	 * @return The color depth in bits. If the actual color depth of the icon is
+	 *         unknown, -1 is returned.
+	 */
+	int getDepth();
+
+	/**
+	 * Returns an <code>InputStream</code> object for the icon data.
+	 * 
+	 * The <code>InputStream</code> object provides a way for a client to read the
+	 * actual icon graphics data. The number of bytes available from this
+	 * <code>InputStream</code> object can be determined via the
+	 * <code>getSize()</code> method. The format of the data encoded can be
+	 * determined by the MIME type availble via the <code>getMimeType()</code>
+	 * method.
+	 * 
+	 * @return An InputStream to read the icon graphics data from.
+	 * @throws IOException If the <code>InputStream</code> cannot be returned.
+	 * @see UPnPIcon#getMimeType()
+	 */
+	InputStream getInputStream() throws IOException;
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPLocalStateVariable.java b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPLocalStateVariable.java
new file mode 100644
index 0000000..7ab6fa3
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPLocalStateVariable.java
@@ -0,0 +1,44 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.upnp/src/org/osgi/service/upnp/UPnPLocalStateVariable.java,v 1.11 2006/03/14 01:21:11 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2005). 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.
+ */
+/**
+ * To keep the current values getting from subscribed UPnPDevices. 
+ * 
+ * The actual values of the UPnPStateVaraible are passed as Java object type. 
+ * 
+ * @since 1.1
+ **/
+package org.osgi.service.upnp;
+
+/**
+ * A local UPnP state variable which allows the value of the state variable to
+ * be queried.
+ * 
+ * @since 1.1
+ */
+public interface UPnPLocalStateVariable extends UPnPStateVariable {
+	/**
+	 * This method will keep the current values of UPnPStateVariables of a
+	 * UPnPDevice whenever UPnPStateVariable's value is changed , this method
+	 * must be called.
+	 * 
+	 * @return <code>Object</code> current value of UPnPStateVariable. if the
+	 *         current value is initialized with the default value defined UPnP
+	 *         service description.
+	 */
+	public Object getCurrentValue();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPService.java b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPService.java
new file mode 100644
index 0000000..6b0406c
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPService.java
@@ -0,0 +1,173 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.upnp/src/org/osgi/service/upnp/UPnPService.java,v 1.7 2006/03/14 01:21:11 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.upnp;
+
+/**
+ * A representation of a UPnP Service.
+ * 
+ * Each UPnP device contains zero or more services. The UPnP description for a
+ * service defines actions, their arguments, and event characteristics.
+ */
+public interface UPnPService {
+	/**
+	 * Property key for the optional service type uri.
+	 * 
+	 * The service type property is used when registering UPnP Device services
+	 * and UPnP Event Listener services. The property contains a <code>String</code>
+	 * array (<code>String[]</code>) of service types. A UPnP Device service can
+	 * thus announce what types of services it contains. A UPnP Event Listener
+	 * service can announce for what type of UPnP services it wants
+	 * notifications. The service version is encoded in the type string as
+	 * specified in the UPnP specification. A <code>null</code> value is a
+	 * wildcard, matching <b>all </b> service types. Value is
+	 * "UPnP.service.type".
+	 * 
+	 * @see UPnPService#getType()
+	 */
+	String	TYPE	= "UPnP.service.type";
+	/**
+	 * Property key for the optional service id.
+	 * 
+	 * The service id property is used when registering UPnP Device services or
+	 * UPnP Event Listener services. The value of the property contains a
+	 * <code>String</code> array (<code>String[]</code>) of service ids. A UPnP
+	 * Device service can thus announce what service ids it contains. A UPnP
+	 * Event Listener service can announce for what UPnP service ids it wants
+	 * notifications. A service id does <b>not </b> have to be universally
+	 * unique. It must be unique only within a device. A <code>null</code> value
+	 * is a wildcard, matching <b>all </b> services. The value is
+	 * "UPnP.service.id".
+	 */
+	String	ID		= "UPnP.service.id";
+
+	/**
+	 * Returns the <code>serviceId</code> field in the UPnP service description.
+	 * 
+	 * 
+	 * <p>
+	 * For standard services defined by a UPnP Forum working committee, the
+	 * serviceId must contain the following components in the indicated order:
+	 * <ul>
+	 * <li><code>urn:upnp-org:serviceId:</code></li>
+	 * <li>service ID suffix</li>
+	 * </ul>
+	 * Example: <code>urn:upnp-org:serviceId:serviceID</code>.
+	 * 
+	 * <p>
+	 * Note that <code>upnp-org</code> is used instead of
+	 * <code>schemas-upnp-org</code> in this example because an XML schema is not
+	 * defined for each serviceId.
+	 * </p>
+	 * 
+	 * <p>
+	 * For non-standard services specified by UPnP vendors, the serviceId must
+	 * contain the following components in the indicated order:
+	 * <ul>
+	 * <li><code>urn:</code></li>
+	 * <li>ICANN domain name owned by the vendor</li>
+	 * <li><code>:serviceId:</code></li>
+	 * <li>service ID suffix</li>
+	 * </ul>
+	 * Example: <code>urn:domain-name:serviceId:serviceID</code>.
+	 * 
+	 * @return The service ID suffix defined by a UPnP Forum working committee
+	 *         or specified by a UPnP vendor. Must be &lt;= 64 characters.
+	 *         Single URI.
+	 */
+	String getId();
+
+	/**
+	 * Returns the <code>serviceType</code> field in the UPnP service description.
+	 * 
+	 * <p>
+	 * For standard services defined by a UPnP Forum working committee, the
+	 * serviceType must contain the following components in the indicated order:
+	 * <ul>
+	 * <li><code>urn:schemas-upnp-org:service:</code></li>
+	 * <li>service type suffix:</li>
+	 * <li>integer service version</li>
+	 * </ul>
+	 * Example: <code>urn:schemas-upnp-org:service:serviceType:v</code>.
+	 * 
+	 * <p>
+	 * For non-standard services specified by UPnP vendors, the
+	 * <code>serviceType</code> must contain the following components in the
+	 * indicated order:
+	 * <ul>
+	 * <li><code>urn:</code></li>
+	 * <li>ICANN domain name owned by the vendor</li>
+	 * <li><code>:service:</code></li>
+	 * <li>service type suffix:</li>
+	 * <li>integer service version</li>
+	 * </ul>
+	 * Example: <code>urn:domain-name:service:serviceType:v</code>.
+	 * 
+	 * @return The service type suffix defined by a UPnP Forum working committee
+	 *         or specified by a UPnP vendor. Must be &lt;= 64 characters, not
+	 *         including the version suffix and separating colon. Single URI.
+	 */
+	String getType();
+
+	/**
+	 * Returns the version suffix encoded in the <code>serviceType</code> field in
+	 * the UPnP service description.
+	 * 
+	 * @return The integer service version defined by a UPnP Forum working
+	 *         committee or specified by a UPnP vendor.
+	 */
+	String getVersion();
+
+	/**
+	 * Locates a specific action by name.
+	 * 
+	 * Looks up an action by its name.
+	 * 
+	 * @param name Name of action. Must not contain hyphen or hash characters.
+	 *        Should be &lt; 32 characters.
+	 * 
+	 * @return The requested action or <code>null</code> if no action is found.
+	 */
+	UPnPAction getAction(String name);
+
+	/**
+	 * Lists all actions provided by this service.
+	 * 
+	 * @return Array of actions (<code>UPnPAction[]</code> )or <code>null</code> if
+	 *         no actions are defined for this service.
+	 */
+	UPnPAction[] getActions();
+
+	/**
+	 * Lists all <code>UPnPStateVariable</code> objects provided by this service.
+	 * 
+	 * @return Array of state variables or <code>null</code> if none are defined
+	 *         for this service.
+	 */
+	UPnPStateVariable[] getStateVariables();
+
+	/**
+	 * Gets a <code>UPnPStateVariable</code> objects provided by this service by
+	 * name
+	 * 
+	 * @param name Name of the State Variable
+	 * 
+	 * @return State variable or <code>null</code> if no such state variable
+	 *         exists for this service.
+	 */
+	UPnPStateVariable getStateVariable(String name);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPStateVariable.java b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPStateVariable.java
new file mode 100644
index 0000000..9d34ed8
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/UPnPStateVariable.java
@@ -0,0 +1,342 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.upnp/src/org/osgi/service/upnp/UPnPStateVariable.java,v 1.7 2006/03/14 01:21:11 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.upnp;
+
+/**
+ * The meta-information of a UPnP state variable as declared in the device's
+ * service state table (SST).
+ * <p>
+ * Method calls to interact with a device (e.g. <code>UPnPAction.invoke(...);</code>)
+ * use this class to encapsulate meta information about the input and output
+ * arguments.
+ * <p>
+ * The actual values of the arguments are passed as Java objects. The mapping of
+ * types from UPnP data types to Java data types is described with the field
+ * definitions.
+ */
+public interface UPnPStateVariable {
+	/**
+	 * Unsigned 1 <code>Byte</code> int.
+	 * <p>
+	 * Mapped to an <code>Integer</code> object.
+	 */
+	static final String	TYPE_UI1			= "ui1";
+	/**
+	 * Unsigned 2 Byte int.
+	 * <p>
+	 * Mapped to <code>Integer</code> object.
+	 */
+	static final String	TYPE_UI2			= "ui2";
+	/**
+	 * Unsigned 4 Byte int.
+	 * <p>
+	 * Mapped to <code>Long</code> object.
+	 */
+	static final String	TYPE_UI4			= "ui4";
+	/**
+	 * 1 Byte int.
+	 * <p>
+	 * Mapped to <code>Integer</code> object.
+	 */
+	static final String	TYPE_I1				= "i1";
+	/**
+	 * 2 Byte int.
+	 * <p>
+	 * Mapped to <code>Integer</code> object.
+	 */
+	static final String	TYPE_I2				= "i2";
+	/**
+	 * 4 Byte int.
+	 * <p>
+	 * Must be between -2147483648 and 2147483647
+	 * <p>
+	 * Mapped to <code>Integer</code> object.
+	 */
+	static final String	TYPE_I4				= "i4";
+	/**
+	 * Integer number.
+	 * <p>
+	 * Mapped to <code>Integer</code> object.
+	 */
+	static final String	TYPE_INT			= "int";
+	/**
+	 * 4 Byte float.
+	 * <p>
+	 * Same format as float. Must be between 3.40282347E+38 to 1.17549435E-38.
+	 * <p>
+	 * Mapped to <code>Float</code> object.
+	 */
+	static final String	TYPE_R4				= "r4";
+	/**
+	 * 8 Byte float.
+	 * <p>
+	 * Same format as float. Must be between -1.79769313486232E308 and
+	 * -4.94065645841247E-324 for negative values, and between
+	 * 4.94065645841247E-324 and 1.79769313486232E308 for positive values, i.e.,
+	 * IEEE 64-bit (8-Byte) double.
+	 * <p>
+	 * Mapped to <code>Double</code> object.
+	 */
+	static final String	TYPE_R8				= "r8";
+	/**
+	 * Same as r8.
+	 * <p>
+	 * Mapped to <code>Double</code> object.
+	 */
+	static final String	TYPE_NUMBER			= "number";
+	/**
+	 * Same as r8 but no more than 14 digits to the left of the decimal point
+	 * and no more than 4 to the right.
+	 * <p>
+	 * Mapped to <code>Double</code> object.
+	 */
+	static final String	TYPE_FIXED_14_4		= "fixed.14.4";
+	/**
+	 * Floating-point number.
+	 * <p>
+	 * Mantissa (left of the decimal) and/or exponent may have a leading sign.
+	 * Mantissa and/or exponent may have leading zeros. Decimal character in
+	 * mantissa is a period, i.e., whole digits in mantissa separated from
+	 * fractional digits by period. Mantissa separated from exponent by E. (No
+	 * currency symbol.) (No grouping of digits in the mantissa, e.g., no
+	 * commas.)
+	 * <p>
+	 * Mapped to <code>Float</code> object.
+	 */
+	static final String	TYPE_FLOAT			= "float";
+	/**
+	 * Unicode string.
+	 * <p>
+	 * One character long.
+	 * <p>
+	 * Mapped to <code>Character</code> object.
+	 */
+	static final String	TYPE_CHAR			= "char";
+	/**
+	 * Unicode string.
+	 * <p>
+	 * No limit on length.
+	 * <p>
+	 * Mapped to <code>String</code> object.
+	 */
+	static final String	TYPE_STRING			= "string";
+	/**
+	 * A calendar date.
+	 * <p>
+	 * Date in a subset of ISO 8601 format without time data.
+	 * <p>
+	 * See <a
+	 * href="http://www.w3.org/TR/xmlschema-2/#date">http://www.w3.org/TR/xmlschema-2/#date
+	 * </a>.
+	 * <p>
+	 * Mapped to <code>java.util.Date</code> object. Always 00:00 hours.
+	 */
+	static final String	TYPE_DATE			= "date";
+	/**
+	 * A specific instant of time.
+	 * <p>
+	 * Date in ISO 8601 format with optional time but no time zone.
+	 * <p>
+	 * See <a
+	 * href="http://www.w3.org/TR/xmlschema-2/#dateTime">http://www.w3.org/TR/xmlschema-2/#dateTime
+	 * </a>.
+	 * <p>
+	 * Mapped to <code>java.util.Date</code> object using default time zone.
+	 */
+	static final String	TYPE_DATETIME		= "dateTime";
+	/**
+	 * A specific instant of time.
+	 * <p>
+	 * Date in ISO 8601 format with optional time and optional time zone.
+	 * <p>
+	 * See <a
+	 * href="http://www.w3.org/TR/xmlschema-2/#dateTime">http://www.w3.org/TR/xmlschema-2/#dateTime
+	 * </a>.
+	 * <p>
+	 * Mapped to <code>java.util.Date</code> object adjusted to default time zone.
+	 */
+	static final String	TYPE_DATETIME_TZ	= "dateTime.tz";
+	/**
+	 * An instant of time that recurs every day.
+	 * <p>
+	 * Time in a subset of ISO 8601 format with no date and no time zone.
+	 * <p>
+	 * See <a
+	 * href="http://www.w3.org/TR/xmlschema-2/#dateTime">http://www.w3.org/TR/xmlschema-2/#time
+	 * </a>.
+	 * <p>
+	 * Mapped to <code>Long</code>. Converted to milliseconds since midnight.
+	 */
+	static final String	TYPE_TIME			= "time";
+	/**
+	 * An instant of time that recurs every day.
+	 * <p>
+	 * Time in a subset of ISO 8601 format with optional time zone but no date.
+	 * <p>
+	 * See <a
+	 * href="http://www.w3.org/TR/xmlschema-2/#dateTime">http://www.w3.org/TR/xmlschema-2/#time
+	 * </a>.
+	 * <p>
+	 * Mapped to <code>Long</code> object. Converted to milliseconds since
+	 * midnight and adjusted to default time zone, wrapping at 0 and
+	 * 24*60*60*1000.
+	 */
+	static final String	TYPE_TIME_TZ		= "time.tz";
+	/**
+	 * True or false.
+	 * <p>
+	 * Mapped to <code>Boolean</code> object.
+	 */
+	static final String	TYPE_BOOLEAN		= "boolean";
+	/**
+	 * MIME-style Base64 encoded binary BLOB.
+	 * <p>
+	 * Takes 3 Bytes, splits them into 4 parts, and maps each 6 bit piece to an
+	 * octet. (3 octets are encoded as 4.) No limit on size.
+	 * <p>
+	 * Mapped to <code>byte[]</code> object. The Java byte array will hold the
+	 * decoded content of the BLOB.
+	 */
+	static final String	TYPE_BIN_BASE64		= "bin.base64";
+	/**
+	 * Hexadecimal digits representing octets.
+	 * <p>
+	 * Treats each nibble as a hex digit and encodes as a separate Byte. (1
+	 * octet is encoded as 2.) No limit on size.
+	 * <p>
+	 * Mapped to <code>byte[]</code> object. The Java byte array will hold the
+	 * decoded content of the BLOB.
+	 */
+	static final String	TYPE_BIN_HEX		= "bin.hex";
+	/**
+	 * Universal Resource Identifier.
+	 * <p>
+	 * Mapped to <code>String</code> object.
+	 */
+	static final String	TYPE_URI			= "uri";
+	/**
+	 * Universally Unique ID.
+	 * <p>
+	 * Hexadecimal digits representing octets. Optional embedded hyphens are
+	 * ignored.
+	 * <p>
+	 * Mapped to <code>String</code> object.
+	 */
+	static final String	TYPE_UUID			= "uuid";
+
+	/**
+	 * Returns the variable name.
+	 * 
+	 * <ul>
+	 * <li>All standard variables defined by a UPnP Forum working committee
+	 * must not begin with <code>X_</code> nor <code>A_</code>.</li>
+	 * <li>All non-standard variables specified by a UPnP vendor and added to a
+	 * standard service must begin with <code>X_</code>.</li>
+	 * </ul>
+	 * 
+	 * @return Name of state variable. Must not contain a hyphen character nor a
+	 *         hash character. Should be &lt; 32 characters.
+	 */
+	String getName();
+
+	/**
+	 * Returns the Java class associated with the UPnP data type of this state
+	 * variable.
+	 * <P>
+	 * Mapping between the UPnP data types and Java classes is performed
+	 * according to the schema mentioned above.
+	 * 
+	 * <pre>
+	 * 
+	 *  Integer              ui1, ui2, i1, i2, i4, int
+	 *  Long                 ui4, time, time.tz
+	 *  Float                r4, float
+	 *  Double               r8, number, fixed.14.4
+	 *  Character            char
+	 *  String               string, uri, uuid
+	 *  Date                 date, dateTime, dateTime.tz
+	 *  Boolean              boolean
+	 *  byte[]               bin.base64, bin.hex
+	 *  
+	 * </pre>
+	 * 
+	 * @return A class object corresponding to the Java type of this argument.
+	 */
+	Class getJavaDataType();
+
+	/**
+	 * Returns the UPnP type of this state variable. Valid types are defined as
+	 * constants.
+	 * 
+	 * @return The UPnP data type of this state variable, as defined in above
+	 *         constants.
+	 */
+	String getUPnPDataType();
+
+	/**
+	 * Returns the default value, if defined.
+	 * 
+	 * @return The default value or <code>null</code> if not defined. The type of
+	 *         the returned object can be determined by <code>getJavaDataType</code>.
+	 */
+	Object getDefaultValue();
+
+	/**
+	 * Returns the allowed values, if defined. Allowed values can be defined
+	 * only for String types.
+	 * 
+	 * @return The allowed values or <code>null</code> if not defined. Should be
+	 *         less than 32 characters.
+	 */
+	String[] getAllowedValues();
+
+	/**
+	 * Returns the minimum value, if defined. Minimum values can only be defined
+	 * for numeric types.
+	 * 
+	 * @return The minimum value or <code>null</code> if not defined.
+	 */
+	Number getMinimum();
+
+	/**
+	 * Returns the maximum value, if defined. Maximum values can only be defined
+	 * for numeric types.
+	 * 
+	 * @return The maximum value or <code>null</code> if not defined.
+	 */
+	Number getMaximum();
+
+	/**
+	 * Returns the size of an increment operation, if defined. Step sizes can be
+	 * defined only for numeric types.
+	 * 
+	 * @return The increment size or null if not defined.
+	 */
+	Number getStep();
+
+	/**
+	 * Tells if this StateVariable can be used as an event source.
+	 * 
+	 * If the StateVariable is eventable, an event listener service can be
+	 * registered to be notified when changes to the variable appear.
+	 * 
+	 * @return <code>true</code> if the <code>StateVariable</code> generates events,
+	 *         <code>false</code> otherwise.
+	 */
+	boolean sendsEvents();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/upnp/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/package.html
new file mode 100644
index 0000000..2c5c268
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/package.html
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.service.upnp/src/org/osgi/service/upnp/package.html,v 1.3 2004/12/09 20:04:20 hargrave Exp $ -->
+<BODY>
+<P>The OSGi UPnP API Package. Specification 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.upnp; version=1.1
+</pre>
+</BODY>
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/upnp/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/upnp/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/Authorization.java b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/Authorization.java
new file mode 100644
index 0000000..6e780ad
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/Authorization.java
@@ -0,0 +1,104 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.useradmin/src/org/osgi/service/useradmin/Authorization.java,v 1.7 2006/03/14 01:20:47 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.useradmin;
+
+/**
+ * The <code>Authorization</code> interface encapsulates an authorization context
+ * on which bundles can base authorization decisions, where appropriate.
+ * <p>
+ * Bundles associate the privilege to access restricted resources or operations
+ * with roles. Before granting access to a restricted resource or operation, a
+ * bundle will check if the <code>Authorization</code> object passed to it possess
+ * the required role, by calling its <code>hasRole</code> method.
+ * <p>
+ * Authorization contexts are instantiated by calling the
+ * {@link UserAdmin#getAuthorization}method.
+ * 
+ * <p>
+ * <i>Trusting Authorization objects </i>
+ * <p>
+ * There are no restrictions regarding the creation of <code>Authorization</code>
+ * objects. Hence, a service must only accept <code>Authorization</code> objects
+ * from bundles that has been authorized to use the service using code based (or
+ * Java 2) permissions.
+ * 
+ * <p>
+ * In some cases it is useful to use <code>ServicePermission</code> to do the code
+ * based access control. A service basing user access control on
+ * <code>Authorization</code> objects passed to it, will then require that a
+ * calling bundle has the <code>ServicePermission</code> to get the service in
+ * question. This is the most convenient way. The OSGi environment will do the
+ * code based permission check when the calling bundle attempts to get the
+ * service from the service registry.
+ * <p>
+ * Example: A servlet using a service on a user's behalf. The bundle with the
+ * servlet must be given the <code>ServicePermission</code> to get the Http
+ * Service.
+ * <p>
+ * However, in some cases the code based permission checks need to be more
+ * fine-grained. A service might allow all bundles to get it, but require
+ * certain code based permissions for some of its methods.
+ * <p>
+ * Example: A servlet using a service on a user's behalf, where some service
+ * functionality is open to anyone, and some is restricted by code based
+ * permissions. When a restricted method is called (e.g., one handing over an
+ * <code>Authorization</code> object), the service explicitly checks that the
+ * calling bundle has permission to make the call.
+ * 
+ * @version $Revision: 1.7 $
+ */
+public interface Authorization {
+	/**
+	 * Gets the name of the {@link User}that this <code>Authorization</code>
+	 * context was created for.
+	 * 
+	 * @return The name of the {@link User}object that this
+	 *         <code>Authorization</code> context was created for, or
+	 *         <code>null</code> if no user was specified when this
+	 *         <code>Authorization</code> context was created.
+	 */
+	public String getName();
+
+	/**
+	 * Checks if the role with the specified name is implied by this
+	 * <code>Authorization</code> context.
+	 * <p>
+	 * 
+	 * Bundles must define globally unique role names that are associated with
+	 * the privilege of accessing restricted resources or operations. Operators
+	 * will grant users access to these resources, by creating a {@link Group}
+	 * object for each role and adding {@link User}objects to it.
+	 * 
+	 * @param name The name of the role to check for.
+	 * 
+	 * @return <code>true</code> if this <code>Authorization</code> context implies
+	 *         the specified role, otherwise <code>false</code>.
+	 */
+	public boolean hasRole(String name);
+
+	/**
+	 * Gets the names of all roles encapsulated by this <code>Authorization</code>
+	 * context.
+	 * 
+	 * @return The names of all roles encapsulated by this
+	 *         <code>Authorization</code> context, or <code>null</code> if no roles
+	 *         are in the context. The predefined role <code>user.anyone</code>
+	 *         will not be included in this list.
+	 */
+	public String[] getRoles();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/Group.java b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/Group.java
new file mode 100644
index 0000000..2687354
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/Group.java
@@ -0,0 +1,160 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.useradmin/src/org/osgi/service/useradmin/Group.java,v 1.7 2006/03/14 01:20:47 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.useradmin;
+
+/**
+ * A named grouping of roles (<code>Role</code> objects).
+ * <p>
+ * Whether or not a given <code>Authorization</code> context implies a
+ * <code>Group</code> object depends on the members of that <code>Group</code>
+ * object.
+ * <p>
+ * A <code>Group</code> object can have two kinds of members: <i>basic </i> and
+ * <i>required </i>. A <code>Group</code> object is implied by an
+ * <code>Authorization</code> context if all of its required members are implied
+ * and at least one of its basic members is implied.
+ * <p>
+ * A <code>Group</code> object must contain at least one basic member in order to
+ * be implied. In other words, a <code>Group</code> object without any basic
+ * member roles is never implied by any <code>Authorization</code> context.
+ * <p>
+ * A <code>User</code> object always implies itself.
+ * <p>
+ * No loop detection is performed when adding members to <code>Group</code>
+ * objects, which means that it is possible to create circular implications.
+ * Loop detection is instead done when roles are checked. The semantics is that
+ * if a role depends on itself (i.e., there is an implication loop), the role is
+ * not implied.
+ * <p>
+ * The rule that a <code>Group</code> object must have at least one basic member
+ * to be implied is motivated by the following example:
+ * 
+ * <pre>
+ * 
+ *  group foo
+ *    required members: marketing
+ *    basic members: alice, bob
+ *  
+ * </pre>
+ * 
+ * Privileged operations that require membership in "foo" can be performed only
+ * by "alice" and "bob", who are in marketing.
+ * <p>
+ * If "alice" and "bob" ever transfer to a different department, anybody in
+ * marketing will be able to assume the "foo" role, which certainly must be
+ * prevented. Requiring that "foo" (or any <code>Group</code> object for that
+ * matter) must have at least one basic member accomplishes that.
+ * <p>
+ * However, this would make it impossible for a <code>Group</code> object to be
+ * implied by just its required members. An example where this implication might
+ * be useful is the following declaration: "Any citizen who is an adult is
+ * allowed to vote." An intuitive configuration of "voter" would be:
+ * 
+ * <pre>
+ * 
+ *  group voter
+ *    required members: citizen, adult
+ *       basic members:
+ *  
+ * </pre>
+ * 
+ * However, according to the above rule, the "voter" role could never be assumed
+ * by anybody, since it lacks any basic members. In order to address this issue
+ * a predefined role named "user.anyone" can be specified, which is always
+ * implied. The desired implication of the "voter" group can then be achieved by
+ * specifying "user.anyone" as its basic member, as follows:
+ * 
+ * <pre>
+ * 
+ *  group voter
+ *    required members: citizen, adult
+ *       basic members: user.anyone
+ *  
+ * </pre>
+ * 
+ * @version $Revision: 1.7 $
+ */
+public interface Group extends User {
+	/**
+	 * Adds the specified <code>Role</code> object as a basic member to this
+	 * <code>Group</code> object.
+	 * 
+	 * @param role The role to add as a basic member.
+	 * 
+	 * @return <code>true</code> if the given role could be added as a basic
+	 *         member, and <code>false</code> if this <code>Group</code> object
+	 *         already contains a <code>Role</code> object whose name matches that
+	 *         of the specified role.
+	 * 
+	 * @throws SecurityException If a security manager exists and the caller
+	 *         does not have the <code>UserAdminPermission</code> with name
+	 *         <code>admin</code>.
+	 */
+	public boolean addMember(Role role);
+
+	/**
+	 * Adds the specified <code>Role</code> object as a required member to this
+	 * <code>Group</code> object.
+	 * 
+	 * @param role The <code>Role</code> object to add as a required member.
+	 * 
+	 * @return <code>true</code> if the given <code>Role</code> object could be
+	 *         added as a required member, and <code>false</code> if this
+	 *         <code>Group</code> object already contains a <code>Role</code> object
+	 *         whose name matches that of the specified role.
+	 * 
+	 * @throws SecurityException If a security manager exists and the caller
+	 *         does not have the <code>UserAdminPermission</code> with name
+	 *         <code>admin</code>.
+	 */
+	public boolean addRequiredMember(Role role);
+
+	/**
+	 * Removes the specified <code>Role</code> object from this <code>Group</code>
+	 * object.
+	 * 
+	 * @param role The <code>Role</code> object to remove from this <code>Group</code>
+	 *        object.
+	 * 
+	 * @return <code>true</code> if the <code>Role</code> object could be removed,
+	 *         otherwise <code>false</code>.
+	 * 
+	 * @throws SecurityException If a security manager exists and the caller
+	 *         does not have the <code>UserAdminPermission</code> with name
+	 *         <code>admin</code>.
+	 */
+	public boolean removeMember(Role role);
+
+	/**
+	 * Gets the basic members of this <code>Group</code> object.
+	 * 
+	 * @return The basic members of this <code>Group</code> object, or
+	 *         <code>null</code> if this <code>Group</code> object does not contain
+	 *         any basic members.
+	 */
+	public Role[] getMembers();
+
+	/**
+	 * Gets the required members of this <code>Group</code> object.
+	 * 
+	 * @return The required members of this <code>Group</code> object, or
+	 *         <code>null</code> if this <code>Group</code> object does not contain
+	 *         any required members.
+	 */
+	public Role[] getRequiredMembers();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/Role.java b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/Role.java
new file mode 100644
index 0000000..147fd5c
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/Role.java
@@ -0,0 +1,119 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.useradmin/src/org/osgi/service/useradmin/Role.java,v 1.8 2006/03/14 01:20:47 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.useradmin;
+
+import java.util.Dictionary;
+
+/**
+ * The base interface for <code>Role</code> objects managed by the User Admin
+ * service.
+ * 
+ * <p>
+ * This interface exposes the characteristics shared by all <code>Role</code>
+ * classes: a name, a type, and a set of properties.
+ * <p>
+ * Properties represent public information about the <code>Role</code> object that
+ * can be read by anyone. Specific {@link UserAdminPermission}objects are
+ * required to change a <code>Role</code> object's properties.
+ * <p>
+ * <code>Role</code> object properties are <code>Dictionary</code> objects. Changes
+ * to these objects are propagated to the User Admin service and made
+ * persistent.
+ * <p>
+ * Every User Admin service contains a set of predefined <code>Role</code> objects
+ * that are always present and cannot be removed. All predefined <code>Role</code>
+ * objects are of type <code>ROLE</code>. This version of the
+ * <code>org.osgi.service.useradmin</code> package defines a single predefined
+ * role named &quot;user.anyone&quot;, which is inherited by any other role.
+ * Other predefined roles may be added in the future. Since
+ * &quot;user.anyone&quot; is a <code>Role</code> object that has properties
+ * associated with it that can be read and modified. Access to these properties
+ * and their use is application specific and is controlled using
+ * <code>UserAdminPermission</code> in the same way that properties for other
+ * <code>Role</code> objects are.
+ * 
+ * @version $Revision: 1.8 $
+ */
+public interface Role {
+	/**
+	 * The name of the predefined role, user.anyone, that all users and groups
+	 * belong to.
+	 * @since 1.1
+	 */
+	public static final String	USER_ANYONE	= "user.anyone";
+	/**
+	 * The type of a predefined role.
+	 * 
+	 * <p>
+	 * The value of <code>ROLE</code> is 0.
+	 */
+	public static final int		ROLE		= 0;
+	/**
+	 * The type of a {@link User}role.
+	 * 
+	 * <p>
+	 * The value of <code>USER</code> is 1.
+	 */
+	public static final int		USER		= 1;
+	/**
+	 * The type of a {@link Group}role.
+	 * 
+	 * <p>
+	 * The value of <code>GROUP</code> is 2.
+	 */
+	public static final int		GROUP		= 2;
+
+	/**
+	 * Returns the name of this role.
+	 * 
+	 * @return The role's name.
+	 */
+	public String getName();
+
+	/**
+	 * Returns the type of this role.
+	 * 
+	 * @return The role's type.
+	 */
+	public int getType();
+
+	/**
+	 * Returns a <code>Dictionary</code> of the (public) properties of this
+	 * <code>Role</code> object. Any changes to the returned <code>Dictionary</code>
+	 * will change the properties of this <code>Role</code> object. This will
+	 * cause a <code>UserAdminEvent</code> object of type
+	 * {@link UserAdminEvent#ROLE_CHANGED}to be broadcast to any
+	 * <code>UserAdminListener</code> objects.
+	 * 
+	 * <p>
+	 * Only objects of type <code>String</code> may be used as property keys, and
+	 * only objects of type <code>String</code> or <code>byte[]</code> may be used
+	 * as property values. Any other types will cause an exception of type
+	 * <code>IllegalArgumentException</code> to be raised.
+	 * 
+	 * <p>
+	 * In order to add, change, or remove a property in the returned
+	 * <code>Dictionary</code>, a {@link UserAdminPermission}named after the
+	 * property name (or a prefix of it) with action <code>changeProperty</code>
+	 * is required.
+	 * 
+	 * @return <code>Dictionary</code> containing the properties of this
+	 *         <code>Role</code> object.
+	 */
+	public Dictionary getProperties();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/User.java b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/User.java
new file mode 100644
index 0000000..b321388
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/User.java
@@ -0,0 +1,96 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.useradmin/src/org/osgi/service/useradmin/User.java,v 1.7 2006/03/14 01:20:47 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.useradmin;
+
+import java.util.Dictionary;
+
+/**
+ * A <code>User</code> role managed by a User Admin service.
+ * 
+ * <p>
+ * In this context, the term &quot;user&quot; is not limited to just human
+ * beings. Instead, it refers to any entity that may have any number of
+ * credentials associated with it that it may use to authenticate itself.
+ * <p>
+ * In general, <code>User</code> objects are associated with a specific User Admin
+ * service (namely the one that created them), and cannot be used with other
+ * User Admin services.
+ * <p>
+ * A <code>User</code> object may have credentials (and properties, inherited from
+ * the {@link Role}class) associated with it. Specific
+ * {@link UserAdminPermission}objects are required to read or change a
+ * <code>User</code> object's credentials.
+ * <p>
+ * Credentials are <code>Dictionary</code> objects and have semantics that are
+ * similar to the properties in the <code>Role</code> class.
+ * 
+ * @version $Revision: 1.7 $
+ */
+public interface User extends Role {
+	/**
+	 * Returns a <code>Dictionary</code> of the credentials of this <code>User</code>
+	 * object. Any changes to the returned <code>Dictionary</code> object will
+	 * change the credentials of this <code>User</code> object. This will cause a
+	 * <code>UserAdminEvent</code> object of type
+	 * {@link UserAdminEvent#ROLE_CHANGED}to be broadcast to any
+	 * <code>UserAdminListeners</code> objects.
+	 * 
+	 * <p>
+	 * Only objects of type <code>String</code> may be used as credential keys,
+	 * and only objects of type <code>String</code> or of type <code>byte[]</code>
+	 * may be used as credential values. Any other types will cause an exception
+	 * of type <code>IllegalArgumentException</code> to be raised.
+	 * 
+	 * <p>
+	 * In order to retrieve a credential from the returned <code>Dictionary</code>
+	 * object, a {@link UserAdminPermission}named after the credential name (or
+	 * a prefix of it) with action <code>getCredential</code> is required.
+	 * <p>
+	 * In order to add or remove a credential from the returned
+	 * <code>Dictionary</code> object, a {@link UserAdminPermission}named after
+	 * the credential name (or a prefix of it) with action
+	 * <code>changeCredential</code> is required.
+	 * 
+	 * @return <code>Dictionary</code> object containing the credentials of this
+	 *         <code>User</code> object.
+	 */
+	public Dictionary getCredentials();
+
+	/**
+	 * Checks to see if this <code>User</code> object has a credential with the
+	 * specified <code>key</code> set to the specified <code>value</code>.
+	 * 
+	 * <p>
+	 * If the specified credential <code>value</code> is not of type
+	 * <code>String</code> or <code>byte[]</code>, it is ignored, that is,
+	 * <code>false</code> is returned (as opposed to an
+	 * <code>IllegalArgumentException</code> being raised).
+	 * 
+	 * @param key The credential <code>key</code>.
+	 * @param value The credential <code>value</code>.
+	 * 
+	 * @return <code>true</code> if this user has the specified credential;
+	 *         <code>false</code> otherwise.
+	 * 
+	 * @throws SecurityException If a security manager exists and the caller
+	 *         does not have the <code>UserAdminPermission</code> named after the
+	 *         credential key (or a prefix of it) with action
+	 *         <code>getCredential</code>.
+	 */
+	public boolean hasCredential(String key, Object value);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdmin.java b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdmin.java
new file mode 100644
index 0000000..14ccbbf
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdmin.java
@@ -0,0 +1,159 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.useradmin/src/org/osgi/service/useradmin/UserAdmin.java,v 1.9 2006/03/14 01:20:47 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.useradmin;
+
+import org.osgi.framework.*;
+
+/**
+ * This interface is used to manage a database of named <code>Role</code> objects,
+ * which can be used for authentication and authorization purposes.
+ * 
+ * <p>
+ * This version of the User Admin service defines two types of <code>Role</code>
+ * objects: "User" and "Group". Each type of role is represented by an
+ * <code>int</code> constant and an interface. The range of positive integers is
+ * reserved for new types of roles that may be added in the future. When
+ * defining proprietary role types, negative constant values must be used.
+ * 
+ * <p>
+ * Every role has a name and a type.
+ * 
+ * <p>
+ * A {@link User}object can be configured with credentials (e.g., a password)
+ * and properties (e.g., a street address, phone number, etc.).
+ * <p>
+ * A {@link Group}object represents an aggregation of {@link User}and
+ * {@link Group}objects. In other words, the members of a <code>Group</code>
+ * object are roles themselves.
+ * <p>
+ * Every User Admin service manages and maintains its own namespace of
+ * <code>Role</code> objects, in which each <code>Role</code> object has a unique
+ * name.
+ * 
+ * @version $Revision: 1.9 $
+ */
+public interface UserAdmin {
+	/**
+	 * Creates a <code>Role</code> object with the given name and of the given
+	 * type.
+	 * 
+	 * <p>
+	 * If a <code>Role</code> object was created, a <code>UserAdminEvent</code>
+	 * object of type {@link UserAdminEvent#ROLE_CREATED}is broadcast to any
+	 * <code>UserAdminListener</code> object.
+	 * 
+	 * @param name The <code>name</code> of the <code>Role</code> object to create.
+	 * @param type The type of the <code>Role</code> object to create. Must be
+	 *        either a {@link Role#USER}type or {@link Role#GROUP}type.
+	 * 
+	 * @return The newly created <code>Role</code> object, or <code>null</code> if a
+	 *         role with the given name already exists.
+	 * 
+	 * @throws IllegalArgumentException if <code>type</code> is invalid.
+	 * 
+	 * @throws SecurityException If a security manager exists and the caller
+	 *         does not have the <code>UserAdminPermission</code> with name
+	 *         <code>admin</code>.
+	 */
+	public Role createRole(String name, int type);
+
+	/**
+	 * Removes the <code>Role</code> object with the given name from this User
+	 * Admin service.
+	 * 
+	 * <p>
+	 * If the <code>Role</code> object was removed, a <code>UserAdminEvent</code>
+	 * object of type {@link UserAdminEvent#ROLE_REMOVED}is broadcast to any
+	 * <code>UserAdminListener</code> object.
+	 * 
+	 * @param name The name of the <code>Role</code> object to remove.
+	 * 
+	 * @return <code>true</code> If a <code>Role</code> object with the given name
+	 *         is present in this User Admin service and could be removed,
+	 *         otherwise <code>false</code>.
+	 * 
+	 * @throws SecurityException If a security manager exists and the caller
+	 *         does not have the <code>UserAdminPermission</code> with name
+	 *         <code>admin</code>.
+	 */
+	public boolean removeRole(String name);
+
+	/**
+	 * Gets the <code>Role</code> object with the given <code>name</code> from this
+	 * User Admin service.
+	 * 
+	 * @param name The name of the <code>Role</code> object to get.
+	 * 
+	 * @return The requested <code>Role</code> object, or <code>null</code> if this
+	 *         User Admin service does not have a <code>Role</code> object with
+	 *         the given <code>name</code>.
+	 */
+	public Role getRole(String name);
+
+	/**
+	 * Gets the <code>Role</code> objects managed by this User Admin service that
+	 * have properties matching the specified LDAP filter criteria. See
+	 * <code>org.osgi.framework.Filter</code> for a description of the filter
+	 * syntax. If a <code>null</code> filter is specified, all Role objects
+	 * managed by this User Admin service are returned.
+	 * 
+	 * @param filter The filter criteria to match.
+	 * 
+	 * @return The <code>Role</code> objects managed by this User Admin service
+	 *         whose properties match the specified filter criteria, or all
+	 *         <code>Role</code> objects if a <code>null</code> filter is specified.
+	 *         If no roles match the filter, <code>null</code> will be returned.
+	 * @throws InvalidSyntaxException If the filter is not well formed.
+	 *  
+	 */
+	public Role[] getRoles(String filter) throws InvalidSyntaxException;
+
+	/**
+	 * Gets the user with the given property <code>key</code>-<code>value</code>
+	 * pair from the User Admin service database. This is a convenience method
+	 * for retrieving a <code>User</code> object based on a property for which
+	 * every <code>User</code> object is supposed to have a unique value (within
+	 * the scope of this User Admin service), such as for example a X.500
+	 * distinguished name.
+	 * 
+	 * @param key The property key to look for.
+	 * @param value The property value to compare with.
+	 * 
+	 * @return A matching user, if <em>exactly</em> one is found. If zero or
+	 *         more than one matching users are found, <code>null</code> is
+	 *         returned.
+	 */
+	public User getUser(String key, String value);
+
+	/**
+	 * Creates an <code>Authorization</code> object that encapsulates the
+	 * specified <code>User</code> object and the <code>Role</code> objects it
+	 * possesses. The <code>null</code> user is interpreted as the anonymous user.
+	 * The anonymous user represents a user that has not been authenticated. An
+	 * <code>Authorization</code> object for an anonymous user will be unnamed,
+	 * and will only imply groups that user.anyone implies.
+	 * 
+	 * @param user The <code>User</code> object to create an
+	 *        <code>Authorization</code> object for, or <code>null</code> for the
+	 *        anonymous user.
+	 * 
+	 * @return the <code>Authorization</code> object for the specified
+	 *         <code>User</code> object.
+	 */
+	public Authorization getAuthorization(User user);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdminEvent.java b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdminEvent.java
new file mode 100644
index 0000000..e66fc09
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdminEvent.java
@@ -0,0 +1,113 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.useradmin/src/org/osgi/service/useradmin/UserAdminEvent.java,v 1.7 2006/03/14 01:20:47 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.useradmin;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * <code>Role</code> change event.
+ * <p>
+ * <code>UserAdminEvent</code> objects are delivered asynchronously to any
+ * <code>UserAdminListener</code> objects when a change occurs in any of the
+ * <code>Role</code> objects managed by a User Admin service.
+ * 
+ * <p>
+ * A type code is used to identify the event. The following event types are
+ * defined: {@link #ROLE_CREATED}type, {@link #ROLE_CHANGED}type, and
+ * {@link #ROLE_REMOVED}type. Additional event types may be defined in the
+ * future.
+ * 
+ * @see UserAdmin
+ * @see UserAdminListener
+ * 
+ * @version $Revision: 1.7 $
+ */
+public class UserAdminEvent {
+	private ServiceReference	ref;
+	private int					type;
+	private Role				role;
+	/**
+	 * A <code>Role</code> object has been created.
+	 * 
+	 * <p>
+	 * The value of <code>ROLE_CREATED</code> is 0x00000001.
+	 */
+	public static final int		ROLE_CREATED	= 0x00000001;
+	/**
+	 * A <code>Role</code> object has been modified.
+	 * 
+	 * <p>
+	 * The value of <code>ROLE_CHANGED</code> is 0x00000002.
+	 */
+	public static final int		ROLE_CHANGED	= 0x00000002;
+	/**
+	 * A <code>Role</code> object has been removed.
+	 * 
+	 * <p>
+	 * The value of <code>ROLE_REMOVED</code> is 0x00000004.
+	 */
+	public static final int		ROLE_REMOVED	= 0x00000004;
+
+	/**
+	 * Constructs a <code>UserAdminEvent</code> object from the given
+	 * <code>ServiceReference</code> object, event type, and <code>Role</code>
+	 * object.
+	 * 
+	 * @param ref The <code>ServiceReference</code> object of the User Admin
+	 *        service that generated this event.
+	 * @param type The event type.
+	 * @param role The <code>Role</code> object on which this event occurred.
+	 */
+	public UserAdminEvent(ServiceReference ref, int type, Role role) {
+		this.ref = ref;
+		this.type = type;
+		this.role = role;
+	}
+
+	/**
+	 * Gets the <code>ServiceReference</code> object of the User Admin service
+	 * that generated this event.
+	 * 
+	 * @return The User Admin service's <code>ServiceReference</code> object.
+	 */
+	public ServiceReference getServiceReference() {
+		return ref;
+	}
+
+	/**
+	 * Returns the type of this event.
+	 * 
+	 * <p>
+	 * The type values are {@link #ROLE_CREATED}type, {@link #ROLE_CHANGED}
+	 * type, and {@link #ROLE_REMOVED}type.
+	 * 
+	 * @return The event type.
+	 */
+	public int getType() {
+		return type;
+	}
+
+	/**
+	 * Gets the <code>Role</code> object this event was generated for.
+	 * 
+	 * @return The <code>Role</code> object this event was generated for.
+	 */
+	public Role getRole() {
+		return role;
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdminListener.java b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdminListener.java
new file mode 100644
index 0000000..06f79b8
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdminListener.java
@@ -0,0 +1,45 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.useradmin/src/org/osgi/service/useradmin/UserAdminListener.java,v 1.7 2006/03/14 01:20:47 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.useradmin;
+
+/**
+ * Listener for UserAdminEvents.
+ * 
+ * <p>
+ * <code>UserAdminListener</code> objects are registered with the Framework
+ * service registry and notified with a <code>UserAdminEvent</code> object when a
+ * <code>Role</code> object has been created, removed, or modified.
+ * <p>
+ * <code>UserAdminListener</code> objects can further inspect the received
+ * <code>UserAdminEvent</code> object to determine its type, the <code>Role</code>
+ * object it occurred on, and the User Admin service that generated it.
+ * 
+ * @see UserAdmin
+ * @see UserAdminEvent
+ * 
+ * @version $Revision: 1.7 $
+ */
+public interface UserAdminListener {
+	/**
+	 * Receives notification that a <code>Role</code> object has been created,
+	 * removed, or modified.
+	 * 
+	 * @param event The <code>UserAdminEvent</code> object.
+	 */
+	public void roleChanged(UserAdminEvent event);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdminPermission.java b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdminPermission.java
new file mode 100644
index 0000000..49b9e12
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/UserAdminPermission.java
@@ -0,0 +1,630 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.useradmin/src/org/osgi/service/useradmin/UserAdminPermission.java,v 1.10 2006/03/14 01:20:47 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). 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.useradmin;
+
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.security.Permission;
+import java.security.BasicPermission;
+import java.security.PermissionCollection;
+
+/**
+ * Permission to configure and access the {@link Role}objects managed by a User
+ * Admin service.
+ * 
+ * <p>
+ * This class represents access to the <code>Role</code> objects managed by a User
+ * Admin service and their properties and credentials (in the case of
+ * {@link User}objects).
+ * <p>
+ * The permission name is the name (or name prefix) of a property or credential.
+ * The naming convention follows the hierarchical property naming convention.
+ * Also, an asterisk may appear at the end of the name, following a
+ * &quot;.&quot;, or by itself, to signify a wildcard match. For example:
+ * &quot;org.osgi.security.protocol.*&quot; or &quot;*&quot; is valid, but
+ * &quot;*protocol&quot; or &quot;a*b&quot; are not valid.
+ * 
+ * <p>
+ * The <code>UserAdminPermission</code> with the reserved name &quot;admin&quot;
+ * represents the permission required for creating and removing <code>Role</code>
+ * objects in the User Admin service, as well as adding and removing members in
+ * a <code>Group</code> object. This <code>UserAdminPermission</code> does not have
+ * any actions associated with it.
+ * 
+ * <p>
+ * The actions to be granted are passed to the constructor in a string
+ * containing a list of one or more comma-separated keywords. The possible
+ * keywords are: <code>changeProperty</code>,<code>changeCredential</code>, and
+ * <code>getCredential</code>. Their meaning is defined as follows:
+ * 
+ * <pre>
+ * 
+ *  action
+ *  changeProperty    Permission to change (i.e., add and remove)
+ *                    Role object properties whose names start with
+ *                    the name argument specified in the constructor.
+ *  changeCredential  Permission to change (i.e., add and remove)
+ *                    User object credentials whose names start
+ *                    with the name argument specified in the constructor.
+ *  getCredential     Permission to retrieve and check for the
+ *                    existence of User object credentials whose names
+ *                    start with the name argument specified in the
+ *                    constructor.
+ *  
+ * </pre>
+ * 
+ * The action string is converted to lowercase before processing.
+ * 
+ * <p>
+ * Following is a PermissionInfo style policy entry which grants a user
+ * administration bundle a number of <code>UserAdminPermission</code> object:
+ * 
+ * <pre>
+ * 
+ *  (org.osgi.service.useradmin.UserAdminPermission &quot;admin&quot;)
+ *  (org.osgi.service.useradmin.UserAdminPermission &quot;com.foo.*&quot; &quot;changeProperty,getCredential,changeCredential&quot;)
+ *  (org.osgi.service.useradmin.UserAdminPermission &quot;user.*&quot;, &quot;changeProperty,changeCredential&quot;)
+ *  
+ * </pre>
+ * 
+ * The first permission statement grants the bundle the permission to perform
+ * any User Admin service operations of type "admin", that is, create and remove
+ * roles and configure <code>Group</code> objects.
+ * 
+ * <p>
+ * The second permission statement grants the bundle the permission to change
+ * any properties as well as get and change any credentials whose names start
+ * with <code>com.foo.</code>.
+ * 
+ * <p>
+ * The third permission statement grants the bundle the permission to change any
+ * properties and credentials whose names start with <code>user.</code>. This
+ * means that the bundle is allowed to change, but not retrieve any credentials
+ * with the given prefix.
+ * 
+ * <p>
+ * The following policy entry empowers the Http Service bundle to perform user
+ * authentication:
+ * 
+ * <pre>
+ * 
+ *  grant codeBase &quot;${jars}http.jar&quot; {
+ *    permission org.osgi.service.useradmin.UserAdminPermission
+ *      &quot;user.password&quot;, &quot;getCredential&quot;;
+ *  };
+ *  
+ * </pre>
+ * 
+ * <p>
+ * The permission statement grants the Http Service bundle the permission to
+ * validate any password credentials (for authentication purposes), but the
+ * bundle is not allowed to change any properties or credentials.
+ * 
+ * @version $Revision: 1.10 $
+ */
+public final class UserAdminPermission extends BasicPermission {
+    static final long serialVersionUID = -1179971692401603789L;
+	/**
+	 * The permission name &quot;admin&quot;.
+	 */
+	public static final String	ADMIN						= "admin";
+	/**
+	 * The action string &quot;changeProperty&quot;.
+	 */
+	public static final String	CHANGE_PROPERTY				= "changeProperty";
+	private static final int	ACTION_CHANGE_PROPERTY		= 0x1;
+	/**
+	 * The action string &quot;changeCredential&quot;.
+	 */
+	public static final String	CHANGE_CREDENTIAL			= "changeCredential";
+	private static final int	ACTION_CHANGE_CREDENTIAL	= 0x2;
+	/**
+	 * The action string &quot;getCredential&quot;.
+	 */
+	public static final String	GET_CREDENTIAL				= "getCredential";
+	private static final int	ACTION_GET_CREDENTIAL		= 0x4;
+	/**
+	 * All actions
+	 */
+	private static final int	ACTION_ALL					= ACTION_CHANGE_PROPERTY
+																	| ACTION_CHANGE_CREDENTIAL
+																	| ACTION_GET_CREDENTIAL;
+	/**
+	 * No actions.
+	 */
+	static final int			ACTION_NONE					= 0x0;
+	/**
+	 * The actions in canonical form.
+	 * 
+	 * @serial
+	 */
+	private String				actions						= null;
+	/**
+	 * The actions mask.
+	 */
+	private transient int		action_mask					= ACTION_NONE;
+	/*
+	 * Description of this <code> UserAdminPermission </code> (returned by <code>
+	 * toString </code> )
+	 */
+	private transient String	description;
+
+	/**
+	 * Creates a new <code>UserAdminPermission</code> with the specified name and
+	 * actions. <code>name</code> is either the reserved string &quot;admin&quot;
+	 * or the name of a credential or property, and <code>actions</code> contains
+	 * a comma-separated list of the actions granted on the specified name.
+	 * Valid actions are <code>changeProperty</code>,<code>changeCredential</code>,
+	 * and getCredential.
+	 * 
+	 * @param name the name of this <code>UserAdminPermission</code>
+	 * @param actions the action string.
+	 * 
+	 * @throws IllegalArgumentException If <code>name</code> equals
+	 *         &quot;admin&quot; and <code>actions</code> are specified.
+	 */
+	public UserAdminPermission(String name, String actions) {
+		this(name, getMask(actions));
+	}
+
+	/**
+	 * Package private constructor used by
+	 * <code>UserAdminPermissionCollection</code>.
+	 * 
+	 * @param name class name
+	 * @param mask action mask
+	 */
+	UserAdminPermission(String name, int mask) {
+		super(name);
+		init(mask);
+	}
+
+	/**
+	 * Called by constructors and when deserialized.
+	 * 
+	 * @param mask action mask
+	 */
+	private void init(int mask) {
+		if (getName().equals(ADMIN)) {
+			if (mask != ACTION_NONE) {
+				throw new IllegalArgumentException("Actions specified for "
+						+ "no-action " + "UserAdminPermission");
+			}
+		}
+		else {
+			if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
+				throw new IllegalArgumentException("Invalid action string");
+			}
+		}
+		action_mask = mask;
+	}
+
+	/**
+	 * Parses the action string into the action mask.
+	 * 
+	 * @param actions Action string.
+	 * @return action mask.
+	 */
+	private static int getMask(String actions) {
+		boolean seencomma = false;
+		int mask = ACTION_NONE;
+		if (actions == null) {
+			return (mask);
+		}
+		char[] a = actions.toCharArray();
+		int i = a.length - 1;
+		if (i < 0)
+			return (mask);
+		while (i != -1) {
+			char c;
+			// skip whitespace
+			while ((i != -1)
+					&& ((c = a[i]) == ' ' || c == '\r' || c == '\n'
+							|| c == '\f' || c == '\t'))
+				i--;
+			// check for the known strings
+			int matchlen;
+			if (i >= 12 && match_get(a, i - 10) && match_credential(a, i)) {
+				matchlen = 13;
+				mask |= ACTION_GET_CREDENTIAL;
+			}
+			else
+				if (i >= 13 && match_change(a, i - 8) && match_property(a, i)) {
+					matchlen = 14;
+					mask |= ACTION_CHANGE_PROPERTY;
+				}
+				else
+					if (i >= 15 && match_change(a, i - 10)
+							&& match_credential(a, i)) {
+						matchlen = 16;
+						mask |= ACTION_CHANGE_CREDENTIAL;
+					}
+					else {
+						// parse error
+						throw new IllegalArgumentException(
+								"invalid permission: " + actions);
+					}
+			// make sure we didn't just match the tail of a word
+			// like "ackbarfimport". Also, skip to the comma.
+			seencomma = false;
+			while (i >= matchlen && !seencomma) {
+				switch (a[i - matchlen]) {
+					case ',' :
+						seencomma = true;
+					/* FALLTHROUGH */
+					case ' ' :
+					case '\r' :
+					case '\n' :
+					case '\f' :
+					case '\t' :
+						break;
+					default :
+						throw new IllegalArgumentException(
+								"invalid permission: " + actions);
+				}
+				i--;
+			}
+			// point i at the location of the comma minus one (or -1).
+			i -= matchlen;
+		}
+		if (seencomma) {
+			throw new IllegalArgumentException("invalid permission: " + actions);
+		}
+		return (mask);
+	}
+
+	private static boolean match_change(char[] a, int i) {
+		return ((a[i - 5] == 'c' || a[i - 5] == 'C')
+				&& (a[i - 4] == 'h' || a[i - 4] == 'H')
+				&& (a[i - 3] == 'a' || a[i - 3] == 'A')
+				&& (a[i - 2] == 'n' || a[i - 2] == 'N')
+				&& (a[i - 1] == 'g' || a[i - 1] == 'G') && (a[i - 0] == 'e' || a[i - 0] == 'E'));
+	}
+
+	private static boolean match_get(char[] a, int i) {
+		return ((a[i - 2] == 'g' || a[i - 2] == 'G')
+				&& (a[i - 1] == 'e' || a[i - 1] == 'E') && (a[i - 0] == 't' || a[i - 0] == 'T'));
+	}
+
+	private static boolean match_property(char[] a, int i) {
+		return ((a[i - 7] == 'p' || a[i - 7] == 'P')
+				&& (a[i - 6] == 'r' || a[i - 6] == 'R')
+				&& (a[i - 5] == 'o' || a[i - 5] == 'O')
+				&& (a[i - 4] == 'p' || a[i - 4] == 'P')
+				&& (a[i - 3] == 'e' || a[i - 3] == 'E')
+				&& (a[i - 2] == 'r' || a[i - 2] == 'R')
+				&& (a[i - 1] == 't' || a[i - 1] == 'T') && (a[i - 0] == 'y' || a[i - 0] == 'Y'));
+	}
+
+	private static boolean match_credential(char[] a, int i) {
+		return ((a[i - 9] == 'c' || a[i - 9] == 'C')
+				&& (a[i - 8] == 'r' || a[i - 8] == 'R')
+				&& (a[i - 7] == 'e' || a[i - 7] == 'E')
+				&& (a[i - 6] == 'd' || a[i - 6] == 'D')
+				&& (a[i - 5] == 'e' || a[i - 5] == 'E')
+				&& (a[i - 4] == 'n' || a[i - 4] == 'N')
+				&& (a[i - 3] == 't' || a[i - 3] == 'T')
+				&& (a[i - 2] == 'i' || a[i - 2] == 'I')
+				&& (a[i - 1] == 'a' || a[i - 1] == 'A') && (a[i - 0] == 'l' || a[i - 0] == 'L'));
+	}
+
+	/**
+	 * Checks if this <code>UserAdminPermission</code> object &quot;implies&quot;
+	 * the specified permission.
+	 * <P>
+	 * More specifically, this method returns <code>true</code> if:
+	 * <p>
+	 * <ul>
+	 * <li><i>p </i> is an instanceof <code>UserAdminPermission</code>,
+	 * <li><i>p </i>'s actions are a proper subset of this object's actions,
+	 * and
+	 * <li><i>p </i>'s name is implied by this object's name. For example,
+	 * &quot;java.*&quot; implies &quot;java.home&quot;.
+	 * </ul>
+	 * 
+	 * @param p the permission to check against.
+	 * 
+	 * @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 UserAdminPermission) {
+			UserAdminPermission target = (UserAdminPermission) p;
+			return (// Check that the we have the requested action
+			((target.action_mask & action_mask) == target.action_mask)
+					&&
+					// If the target action mask is ACTION_NONE, it must be an
+					// admin permission, and then we must be that too
+					(target.action_mask != ACTION_NONE || action_mask == ACTION_NONE) &&
+			// Check that name name matches
+			super.implies(p));
+		}
+		else {
+			return (false);
+		}
+	}
+
+	/**
+	 * Returns the canonical string representation of the actions, separated by
+	 * comma.
+	 * 
+	 * @return the canonical string representation of the actions.
+	 */
+	public String getActions() {
+		if (actions == null) {
+			StringBuffer sb = new StringBuffer();
+			boolean comma = false;
+			if ((action_mask & ACTION_CHANGE_CREDENTIAL) == ACTION_CHANGE_CREDENTIAL) {
+				sb.append(CHANGE_CREDENTIAL);
+				comma = true;
+			}
+			if ((action_mask & ACTION_CHANGE_PROPERTY) == ACTION_CHANGE_PROPERTY) {
+				if (comma)
+					sb.append(',');
+				sb.append(CHANGE_PROPERTY);
+				comma = true;
+			}
+			if ((action_mask & ACTION_GET_CREDENTIAL) == ACTION_GET_CREDENTIAL) {
+				if (comma)
+					sb.append(',');
+				sb.append(GET_CREDENTIAL);
+			}
+			actions = sb.toString();
+		}
+		return (actions);
+	}
+
+	/**
+	 * Returns a new <code>PermissionCollection</code> object for storing
+	 * <code>UserAdminPermission</code> objects.
+	 * 
+	 * @return a new <code>PermissionCollection</code> object suitable for storing
+	 *         <code>UserAdminPermission</code> objects.
+	 */
+	public PermissionCollection newPermissionCollection() {
+		return (new UserAdminPermissionCollection());
+	}
+
+	/**
+	 * Checks two <code>UserAdminPermission</code> objects for equality. Checks
+	 * that <code>obj</code> is a <code>UserAdminPermission</code>, and has the
+	 * same name and actions as this object.
+	 * 
+	 * @param obj the object to be compared for equality with this object.
+	 * 
+	 * @return <code>true</code> if <code>obj</code> is a
+	 *         <code>UserAdminPermission</code> object, and has the same name and
+	 *         actions as this <code>UserAdminPermission</code> object.
+	 */
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return (true);
+		}
+		if (obj instanceof UserAdminPermission) {
+			UserAdminPermission uap = (UserAdminPermission) obj;
+			return ((action_mask == uap.action_mask) && getName().equals(
+					uap.getName()));
+		}
+		else {
+			return (false);
+		}
+	}
+
+	/**
+	 * Returns the hash code of this <code>UserAdminPermission</code> object.
+	 */
+	public int hashCode() {
+		return (getName().hashCode() ^ getActions().hashCode());
+	}
+
+	/**
+	 * Returns the current action mask. Used by the
+	 * <code>UserAdminPermissionCollection</code> class.
+	 * 
+	 * @return the actions mask.
+	 */
+	int getMask() {
+		return (action_mask);
+	}
+
+	/**
+	 * writeObject is called to save the state of this object to a stream. The
+	 * actions are serialized, and the superclass takes care of the name.
+	 */
+	private synchronized void writeObject(java.io.ObjectOutputStream s)
+			throws IOException {
+		// Write out the actions. The superclass takes care of the name
+		// call getActions to make sure actions field is initialized
+		if (actions == null)
+			getActions();
+		s.defaultWriteObject();
+	}
+
+	/*
+	 * Restores this object from a stream (i.e., deserializes it).
+	 */
+	private synchronized void readObject(java.io.ObjectInputStream ois)
+			throws IOException, ClassNotFoundException {
+		ois.defaultReadObject();
+		init(getMask(actions));
+	}
+
+	/**
+	 * Returns a string describing this <code>UserAdminPermission</code> object.
+	 * This string must be in <code>PermissionInfo</code> encoded format.
+	 * 
+	 * @return The <code>PermissionInfo</code> encoded string for this
+	 *         <code>UserAdminPermission</code> object.
+	 * @see "<code>org.osgi.service.permissionadmin.PermissionInfo.getEncoded</code>"
+	 */
+	public String toString() {
+		if (description == null) {
+			StringBuffer sb = new StringBuffer();
+			sb.append('(');
+			sb.append(getClass().getName());
+			sb.append(" \"");
+			sb.append(getName());
+			String actions = getActions();
+			if (actions.length() > 0) {
+				sb.append("\" \"");
+				sb.append(actions);
+			}
+			sb.append("\")");
+			description = sb.toString();
+		}
+		return (description);
+	}
+}
+/**
+ * A <code>UserAdminPermissionCollection</code> stores a set of
+ * <code>UserAdminPermission</code> permissions.
+ */
+
+final class UserAdminPermissionCollection extends PermissionCollection {
+    static final long serialVersionUID = -7222111885230120581L;
+	/**
+	 * Table of permissions.
+	 * 
+	 * @serial
+	 */
+	private Hashtable	permissions;
+	/**
+	 * Boolean saying if "*" is in the collection.
+	 * 
+	 * @serial
+	 */
+	private boolean		all_allowed;
+
+	/**
+	 * Creates an empty <code>UserAdminPermissionCollection</code> object.
+	 */
+	public UserAdminPermissionCollection() {
+		permissions = new Hashtable();
+		all_allowed = false;
+	}
+
+	/**
+	 * Adds the given permission to this <code>UserAdminPermissionCollection</code>.
+	 * The key for the hash is the name.
+	 * 
+	 * @param permission the <code>Permission</code> object to add.
+	 * 
+	 * @throws IllegalArgumentException If the given permission is not a
+	 *         <code>UserAdminPermission</code>
+	 * @throws SecurityException If this <code>UserAdminPermissionCollection</code>
+	 *         object has been marked readonly
+	 */
+	public void add(Permission permission) {
+		if (!(permission instanceof UserAdminPermission))
+			throw new IllegalArgumentException("Invalid permission: "
+					+ permission);
+		if (isReadOnly()) {
+			throw new SecurityException("Attempt to add a Permission to a "
+					+ "readonly PermissionCollection");
+		}
+		UserAdminPermission uap = (UserAdminPermission) permission;
+		String name = uap.getName();
+		UserAdminPermission existing = (UserAdminPermission) permissions
+				.get(name);
+		if (existing != null) {
+			int oldMask = existing.getMask();
+			int newMask = uap.getMask();
+			if (oldMask != newMask) {
+				permissions.put(name, new UserAdminPermission(name, oldMask
+						| newMask));
+			}
+		}
+		else {
+			permissions.put(name, permission);
+		}
+		if (!all_allowed) {
+			if (name.equals("*"))
+				all_allowed = true;
+		}
+	}
+
+	/**
+	 * Checks to see if this <code>PermissionCollection</code> implies the given
+	 * permission.
+	 * 
+	 * @param permission the <code>Permission</code> object to check against
+	 * 
+	 * @return true if the given permission is implied by this
+	 *         <code>PermissionCollection</code>, false otherwise.
+	 */
+	public boolean implies(Permission permission) {
+		if (!(permission instanceof UserAdminPermission)) {
+			return (false);
+		}
+		UserAdminPermission uap = (UserAdminPermission) permission;
+		UserAdminPermission x;
+		int desired = uap.getMask();
+		int effective = 0;
+		// Short circuit if the "*" Permission was added.
+		// desired can only be ACTION_NONE when name is "admin".
+		if (all_allowed && desired != UserAdminPermission.ACTION_NONE) {
+			x = (UserAdminPermission) permissions.get("*");
+			if (x != null) {
+				effective |= x.getMask();
+				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 = uap.getName();
+		x = (UserAdminPermission) 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;
+		int offset = name.length() - 1;
+		while ((last = name.lastIndexOf(".", offset)) != -1) {
+			name = name.substring(0, last + 1) + "*";
+			x = (UserAdminPermission) 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);
+	}
+
+	/**
+	 * Returns an enumeration of all the <code>UserAdminPermission</code> objects
+	 * in the container.
+	 * 
+	 * @return an enumeration of all the <code>UserAdminPermission</code> objects.
+	 */
+	public Enumeration elements() {
+		return (permissions.elements());
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/package.html
new file mode 100644
index 0000000..8c92abd
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/package.html
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.service.useradmin/src/org/osgi/service/useradmin/package.html,v 1.3 2005/08/11 03:07:42 hargrave Exp $ -->
+<BODY>
+<P>The OSGi User Admin service Package. Specification 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.useradmin; version=1.1
+</pre>
+</BODY>
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/packageinfo
new file mode 100644
index 0000000..3987f9c
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/useradmin/packageinfo
@@ -0,0 +1 @@
+version 1.1
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/BasicEnvelope.java b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/BasicEnvelope.java
new file mode 100644
index 0000000..df076ca
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/BasicEnvelope.java
@@ -0,0 +1,66 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.wireadmin/src/org/osgi/service/wireadmin/BasicEnvelope.java,v 1.8 2006/03/14 01:20:55 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.wireadmin;
+
+/**
+ * <code>BasicEnvelope</code> is an implementation of the {@link Envelope}
+ * interface
+ * 
+ * @version $Revision: 1.8 $
+ */
+public class BasicEnvelope implements Envelope {
+	Object	value;
+	Object	identification;
+	String	scope;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param value Content of this envelope, may be <code>null</code>.
+	 * @param identification Identifying object for this <code>Envelope</code>
+	 *        object, must not be <code>null</code>
+	 * @param scope Scope name for this object, must not be <code>null</code>
+	 * @see Envelope
+	 */
+	public BasicEnvelope(Object value, Object identification, String scope) {
+		this.value = value;
+		this.identification = identification;
+		this.scope = scope;
+	}
+
+	/**
+	 * @see org.osgi.service.wireadmin.Envelope#getValue()
+	 */
+	public Object getValue() {
+		return value;
+	}
+
+	/**
+	 * @see org.osgi.service.wireadmin.Envelope#getIdentification()
+	 */
+	public Object getIdentification() {
+		return identification;
+	}
+
+	/**
+	 * @see org.osgi.service.wireadmin.Envelope#getScope()
+	 */
+	public String getScope() {
+		return scope;
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Consumer.java b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Consumer.java
new file mode 100644
index 0000000..238041a
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Consumer.java
@@ -0,0 +1,103 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.wireadmin/src/org/osgi/service/wireadmin/Consumer.java,v 1.8 2006/03/14 01:20:55 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.wireadmin;
+
+/**
+ * Data Consumer, a service that can receive udpated values from
+ * {@link Producer}services.
+ * 
+ * <p>
+ * Service objects registered under the <code>Consumer</code> interface are
+ * expected to consume values from a Producer service via a <code>Wire</code>
+ * object. A Consumer service may poll the Producer service by calling the
+ * {@link Wire#poll}method. The Consumer service will also receive an updated
+ * value when called at it's {@link #updated}method. The Producer service
+ * should have coerced the value to be an instance of one of the types specified
+ * by the {@link Wire#getFlavors}method, or one of their subclasses.
+ * 
+ * <p>
+ * Consumer service objects must register with a <code>service.pid</code> and a
+ * {@link WireConstants#WIREADMIN_CONSUMER_FLAVORS}property. It is recommended
+ * that Consumer service objects also register with a
+ * <code>service.description</code> property.
+ * 
+ * <p>
+ * If an <code>Exception</code> is thrown by any of the <code>Consumer</code>
+ * methods, a <code>WireAdminEvent</code> of type
+ * {@link WireAdminEvent#CONSUMER_EXCEPTION}is broadcast by the Wire Admin
+ * service.
+ * 
+ * <p>
+ * Security Considerations - Data consuming bundles will require
+ * <code>ServicePermission[Consumer,REGISTER]</code>. In general, only the Wire
+ * Admin service bundle should have this permission. Thus only the Wire Admin
+ * service may directly call a Consumer service. Care must be taken in the
+ * sharing of <code>Wire</code> objects with other bundles.
+ * <p>
+ * Consumer services must be registered with their scope when they can receive
+ * different types of objects from the Producer service. The Consumer service
+ * should have <code>WirePermission</code> for each of these scope names.
+ * 
+ * @version $Revision: 1.8 $
+ */
+public interface Consumer {
+	/**
+	 * Update the value. This Consumer service is called by the <code>Wire</code>
+	 * object with an updated value from the Producer service.
+	 * 
+	 * <p>
+	 * Note: This method may be called by a <code>Wire</code> object prior to this
+	 * object being notified that it is connected to that <code>Wire</code> object
+	 * (via the {@link #producersConnected}method).
+	 * <p>
+	 * When the Consumer service can receive <code>Envelope</code> objects, it
+	 * must have registered all scope names together with the service object,
+	 * and each of those names must be permitted by the bundle's
+	 * <code>WirePermission</code>. If an <code>Envelope</code> object is delivered
+	 * with the <code>updated</code> method, then the Consumer service should
+	 * assume that the security check has been performed.
+	 * 
+	 * @param wire The <code>Wire</code> object which is delivering the updated
+	 *        value.
+	 * @param value The updated value. The value should be an instance of one of
+	 *        the types specified by the {@link Wire#getFlavors}method.
+	 */
+	public void updated(Wire wire, Object value);
+
+	/**
+	 * Update the list of <code>Wire</code> objects to which this Consumer service
+	 * is connected.
+	 * 
+	 * <p>
+	 * This method is called when the Consumer service is first registered and
+	 * subsequently whenever a <code>Wire</code> associated with this Consumer
+	 * service becomes connected, is modified or becomes disconnected.
+	 * 
+	 * <p>
+	 * The Wire Admin service must call this method asynchronously. This implies
+	 * that implementors of Consumer can be assured that the callback will not
+	 * take place during registration when they execute the registration in a
+	 * synchronized method.
+	 * 
+	 * @param wires An array of the current and complete list of <code>Wire</code>
+	 *        objects to which this Consumer service is connected. May be
+	 *        <code>null</code> if the Consumer service is not currently connected
+	 *        to any <code>Wire</code> objects.
+	 */
+	public void producersConnected(Wire[] wires);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Envelope.java b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Envelope.java
new file mode 100644
index 0000000..c3f6605
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Envelope.java
@@ -0,0 +1,81 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.wireadmin/src/org/osgi/service/wireadmin/Envelope.java,v 1.7 2006/03/14 01:20:55 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.wireadmin;
+
+/**
+ * Identifies a contained value.
+ * 
+ * An <code>Envelope</code> object combines a status value, an identification
+ * object and a scope name. The <code>Envelope</code> object allows the use of
+ * standard Java types when a Producer service can produce more than one kind of
+ * object. The <code>Envelope</code> object allows the Consumer service to
+ * recognize the kind of object that is received. For example, a door lock could
+ * be represented by a <code>Boolean</code> object. If the <code>Producer</code>
+ * service would send such a <code>Boolean</code> object, then the Consumer
+ * service would not know what door the <code>Boolean</code> object represented.
+ * The <code>Envelope</code> object contains an identification object so the
+ * Consumer service can discriminate between different kinds of values. The
+ * identification object may be a simple <code>String</code> object, but it can
+ * also be a domain specific object that is mutually agreed by the Producer and
+ * the Consumer service. This object can then contain relevant information that
+ * makes the identification easier.
+ * <p>
+ * The scope name of the envelope is used for security. The Wire object must
+ * verify that any <code>Envelope</code> object send through the <code>update</code>
+ * method or coming from the <code>poll</code> method has a scope name that
+ * matches the permissions of both the Producer service and the Consumer service
+ * involved. The wireadmin package also contains a class <code>BasicEnvelope</code>
+ * that implements the methods of this interface.
+ * 
+ * @see WirePermission
+ * @see BasicEnvelope
+ * 
+ * @version $Revision: 1.7 $
+ */
+public interface Envelope {
+	/**
+	 * Return the value associated with this <code>Envelope</code> object.
+	 * 
+	 * @return the value of the status item, or <code>null</code> when no item is
+	 *         associated with this object.
+	 */
+	public Object getValue();
+
+	/**
+	 * Return the identification of this <code>Envelope</code> object.
+	 * 
+	 * An identification may be of any Java type. The type must be mutually
+	 * agreed between the Consumer and Producer services.
+	 * 
+	 * @return an object which identifies the status item in the address space
+	 *         of the composite producer, must not be null.
+	 */
+	public Object getIdentification();
+
+	/**
+	 * Return the scope name of this <code>Envelope</code> object.
+	 * 
+	 * Scope names are used to restrict the communication between the Producer
+	 * and Consumer services. Only <code>Envelopes</code> objects with a scope
+	 * name that is permitted for the Producer and the Consumer services must be
+	 * passed through a <code>Wire</code> object.
+	 * 
+	 * @return the security scope for the status item, must not be null.
+	 */
+	public String getScope();
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Producer.java b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Producer.java
new file mode 100644
index 0000000..e50bbbd
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Producer.java
@@ -0,0 +1,125 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.wireadmin/src/org/osgi/service/wireadmin/Producer.java,v 1.8 2006/03/14 01:20:55 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.wireadmin;
+
+/**
+ * Data Producer, a service that can generate values to be used by
+ * {@link Consumer}services.
+ * 
+ * <p>
+ * Service objects registered under the Producer interface are expected to
+ * produce values (internally generated or from external sensors). The value can
+ * be of different types. When delivering a value to a <code>Wire</code> object,
+ * the Producer service should coerce the value to be an instance of one of the
+ * types specified by {@link Wire#getFlavors}. The classes are specified in
+ * order of preference.
+ * 
+ * <p>
+ * When the data represented by the Producer object changes, this object should
+ * send the updated value by calling the <code>update</code> method on each of
+ * <code>Wire</code> objects passed in the most recent call to this object's
+ * {@link #consumersConnected}method. These <code>Wire</code> objects will pass
+ * the value on to the associated <code>Consumer</code> service object.
+ * 
+ * <p>
+ * The Producer service may use the information in the <code>Wire</code> object's
+ * properties to schedule the delivery of values to the <code>Wire</code> object.
+ * 
+ * <p>
+ * Producer service objects must register with a <code>service.pid</code> and a
+ * {@link WireConstants#WIREADMIN_PRODUCER_FLAVORS}property. It is recommended
+ * that a Producer service object also registers with a
+ * <code>service.description</code> property. Producer service objects must
+ * register with a {@link WireConstants#WIREADMIN_PRODUCER_FILTERS}property if
+ * the Producer service will be performing filtering instead of the
+ * <code>Wire</code> object.
+ * 
+ * <p>
+ * If an exception is thrown by a Producer object method, a
+ * <code>WireAdminEvent</code> of type {@link WireAdminEvent#PRODUCER_EXCEPTION}
+ * is broadcast by the Wire Admin service.
+ * 
+ * <p>
+ * Security Considerations. Data producing bundles will require
+ * <code>ServicePermission[Producer,REGISTER]</code> to register a Producer
+ * service. In general, only the Wire Admin service should have
+ * <code>ServicePermission[Producer,GET]</code>. Thus only the Wire Admin service
+ * may directly call a Producer service. Care must be taken in the sharing of
+ * <code>Wire</code> objects with other bundles.
+ * <p>
+ * Producer services must be registered with scope names when they can send
+ * different types of objects (composite) to the Consumer service. The Producer
+ * service should have <code>WirePermission</code> for each of these scope names.
+ * 
+ * @version $Revision: 1.8 $
+ */
+public interface Producer {
+	/**
+	 * Return the current value of this <code>Producer</code> object.
+	 * 
+	 * <p>
+	 * This method is called by a <code>Wire</code> object in response to the
+	 * Consumer service calling the <code>Wire</code> object's <code>poll</code>
+	 * method. The Producer should coerce the value to be an instance of one of
+	 * the types specified by {@link Wire#getFlavors}. The types are specified
+	 * in order of of preference. The returned value should be as new or newer
+	 * than the last value furnished by this object.
+	 * 
+	 * <p>
+	 * Note: This method may be called by a <code>Wire</code> object prior to this
+	 * object being notified that it is connected to that <code>Wire</code> object
+	 * (via the {@link #consumersConnected}method).
+	 * <p>
+	 * If the Producer service returns an <code>Envelope</code> object that has an
+	 * unpermitted scope name, then the Wire object must ignore (or remove) the
+	 * transfer.
+	 * <p>
+	 * If the <code>Wire</code> object has a scope set, the return value must be
+	 * an array of <code>Envelope</code> objects (<code>Envelope[]</code>). The
+	 * <code>Wire</code> object must have removed any <code>Envelope</code> objects
+	 * that have a scope name that is not in the Wire object's scope.
+	 * 
+	 * @param wire The <code>Wire</code> object which is polling this service.
+	 * @return The current value of the Producer service or <code>null</code> if
+	 *         the value cannot be coerced into a compatible type. Or an array
+	 *         of <code>Envelope</code> objects.
+	 */
+	public Object polled(Wire wire);
+
+	/**
+	 * Update the list of <code>Wire</code> objects to which this
+	 * <code>Producer</code> object is connected.
+	 * 
+	 * <p>
+	 * This method is called when the Producer service is first registered and
+	 * subsequently whenever a <code>Wire</code> associated with this Producer
+	 * becomes connected, is modified or becomes disconnected.
+	 * 
+	 * <p>
+	 * The Wire Admin service must call this method asynchronously. This implies
+	 * that implementors of a Producer service can be assured that the callback
+	 * will not take place during registration when they execute the
+	 * registration in a synchronized method.
+	 * 
+	 * @param wires An array of the current and complete list of <code>Wire</code>
+	 *        objects to which this Producer service is connected. May be
+	 *        <code>null</code> if the Producer is not currently connected to any
+	 *        <code>Wire</code> objects.
+	 */
+	public void consumersConnected(Wire[] wires);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Wire.java b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Wire.java
new file mode 100644
index 0000000..7a1c278
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/Wire.java
@@ -0,0 +1,270 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.wireadmin/src/org/osgi/service/wireadmin/Wire.java,v 1.8 2006/03/14 01:20:55 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.wireadmin;
+
+import java.util.Dictionary;
+
+/**
+ * A connection between a Producer service and a Consumer service.
+ * 
+ * <p>
+ * A <code>Wire</code> object connects a Producer service to a Consumer service.
+ * Both the Producer and Consumer services are identified by their unique
+ * <code>service.pid</code> values. The Producer and Consumer services may
+ * communicate with each other via <code>Wire</code> objects that connect them.
+ * The Producer service may send updated values to the Consumer service by
+ * calling the {@link #update}method. The Consumer service may request an
+ * updated value from the Producer service by calling the {@link #poll}method.
+ * 
+ * <p>
+ * A Producer service and a Consumer service may be connected through multiple
+ * <code>Wire</code> objects.
+ * 
+ * <p>
+ * Security Considerations. <code>Wire</code> objects are available to Producer
+ * and Consumer services connected to a given <code>Wire</code> object and to
+ * bundles which can access the <code>WireAdmin</code> service. A bundle must have
+ * <code>ServicePermission[WireAdmin,GET]</code> to get the <code>WireAdmin</code>
+ * service to access all <code>Wire</code> objects. A bundle registering a
+ * Producer service or a Consumer service must have the appropriate
+ * <code>ServicePermission[Consumer|Producer,REGISTER]</code> to register the
+ * service and will be passed <code>Wire</code> objects when the service object's
+ * <code>consumersConnected</code> or <code>producersConnected</code> method is
+ * called.
+ * 
+ * <p>
+ * Scope. Each Wire object can have a scope set with the <code>setScope</code>
+ * method. This method should be called by a Consumer service when it assumes a
+ * Producer service that is composite (supports multiple information items). The
+ * names in the scope must be verified by the <code>Wire</code> object before it
+ * is used in communication. The semantics of the names depend on the Producer
+ * service and must not be interpreted by the Wire Admin service.
+ * 
+ * @version $Revision: 1.8 $
+ */
+public interface Wire {
+	/**
+	 * Return the state of this <code>Wire</code> object.
+	 * 
+	 * <p>
+	 * A connected <code>Wire</code> must always be disconnected before becoming
+	 * invalid.
+	 * 
+	 * @return <code>false</code> if this <code>Wire</code> object is invalid
+	 *         because it has been deleted via {@link WireAdmin#deleteWire};
+	 *         <code>true</code> otherwise.
+	 */
+	public boolean isValid();
+
+	/**
+	 * Return the connection state of this <code>Wire</code> object.
+	 * 
+	 * <p>
+	 * A <code>Wire</code> is connected after the Wire Admin service receives
+	 * notification that the Producer service and the Consumer service for this
+	 * <code>Wire</code> object are both registered. This method will return
+	 * <code>true</code> prior to notifying the Producer and Consumer services via
+	 * calls to their respective <code>consumersConnected</code> and
+	 * <code>producersConnected</code> methods.
+	 * <p>
+	 * A <code>WireAdminEvent</code> of type {@link WireAdminEvent#WIRE_CONNECTED}
+	 * must be broadcast by the Wire Admin service when the <code>Wire</code>
+	 * becomes connected.
+	 * 
+	 * <p>
+	 * A <code>Wire</code> object is disconnected when either the Consumer or
+	 * Producer service is unregistered or the <code>Wire</code> object is
+	 * deleted.
+	 * <p>
+	 * A <code>WireAdminEvent</code> of type
+	 * {@link WireAdminEvent#WIRE_DISCONNECTED}must be broadcast by the Wire
+	 * Admin service when the <code>Wire</code> becomes disconnected.
+	 * 
+	 * @return <code>true</code> if both the Producer and Consumer for this
+	 *         <code>Wire</code> object are connected to the <code>Wire</code>
+	 *         object; <code>false</code> otherwise.
+	 */
+	public boolean isConnected();
+
+	/**
+	 * Return the list of data types understood by the Consumer service
+	 * connected to this <code>Wire</code> object. Note that subclasses of the
+	 * classes in this list are acceptable data types as well.
+	 * 
+	 * <p>
+	 * The list is the value of the
+	 * {@link WireConstants#WIREADMIN_CONSUMER_FLAVORS}service property of the
+	 * Consumer service object connected to this object. If no such property was
+	 * registered or the type of the property value is not <code>Class[]</code>,
+	 * this method must return <code>null</code>.
+	 * 
+	 * @return An array containing the list of classes understood by the
+	 *         Consumer service or <code>null</code> if the <code>Wire</code> is not
+	 *         connected, or the consumer did not register a
+	 *         {@link WireConstants#WIREADMIN_CONSUMER_FLAVORS}property or the
+	 *         value of the property is not of type <code>Class[]</code>.
+	 */
+	public Class[] getFlavors();
+
+	/**
+	 * Update the value.
+	 * 
+	 * <p>
+	 * This methods is called by the Producer service to notify the Consumer
+	 * service connected to this <code>Wire</code> object of an updated value.
+	 * <p>
+	 * If the properties of this <code>Wire</code> object contain a
+	 * {@link WireConstants#WIREADMIN_FILTER}property, then filtering is
+	 * performed. If the Producer service connected to this <code>Wire</code>
+	 * object was registered with the service property
+	 * {@link WireConstants#WIREADMIN_PRODUCER_FILTERS}, the Producer service
+	 * will perform the filtering according to the rules specified for the
+	 * filter. Otherwise, this <code>Wire</code> object will perform the filtering
+	 * of the value.
+	 * <p>
+	 * If no filtering is done, or the filter indicates the updated value should
+	 * be delivered to the Consumer service, then this <code>Wire</code> object
+	 * must call the {@link Consumer#updated}method with the updated value. If
+	 * this <code>Wire</code> object is not connected, then the Consumer service
+	 * must not be called and the value is ignored.
+	 * <p>
+	 * If the value is an <code>Envelope</code> object, and the scope name is not
+	 * permitted, then the <code>Wire</code> object must ignore this call and not
+	 * transfer the object to the Consumer service.
+	 * 
+	 * <p>
+	 * A <code>WireAdminEvent</code> of type {@link WireAdminEvent#WIRE_TRACE}
+	 * must be broadcast by the Wire Admin service after the Consumer service
+	 * has been successfully called.
+	 * 
+	 * @param value The updated value. The value should be an instance of one of
+	 *        the types returned by {@link #getFlavors}.
+	 * @see WireConstants#WIREADMIN_FILTER
+	 */
+	public void update(Object value);
+
+	/**
+	 * Poll for an updated value.
+	 * 
+	 * <p>
+	 * This methods is normally called by the Consumer service to request an
+	 * updated value from the Producer service connected to this <code>Wire</code>
+	 * object. This <code>Wire</code> object will call the {@link Producer#polled}
+	 * method to obtain an updated value. If this <code>Wire</code> object is not
+	 * connected, then the Producer service must not be called.
+	 * <p>
+	 * 
+	 * If this <code>Wire</code> object has a scope, then this method must return
+	 * an array of <code>Envelope</code> objects. The objects returned must match
+	 * the scope of this object. The <code>Wire</code> object must remove all
+	 * <code>Envelope</code> objects with a scope name that is not in the
+	 * <code>Wire</code> object's scope. Thus, the list of objects returned must
+	 * only contain <code>Envelope</code> objects with a permitted scope name. If
+	 * the array becomes empty, <code>null</code> must be returned.
+	 * 
+	 * <p>
+	 * A <code>WireAdminEvent</code> of type {@link WireAdminEvent#WIRE_TRACE}
+	 * must be broadcast by the Wire Admin service after the Producer service
+	 * has been successfully called.
+	 * 
+	 * @return A value whose type should be one of the types returned by
+	 *         {@link #getFlavors},<code>Envelope[]</code>, or <code>null</code>
+	 *         if the <code>Wire</code> object is not connected, the Producer
+	 *         service threw an exception, or the Producer service returned a
+	 *         value which is not an instance of one of the types returned by
+	 *         {@link #getFlavors}.
+	 */
+	public Object poll();
+
+	/**
+	 * Return the last value sent through this <code>Wire</code> object.
+	 * 
+	 * <p>
+	 * The returned value is the most recent, valid value passed to the
+	 * {@link #update}method or returned by the {@link #poll}method of this
+	 * object. If filtering is performed by this <code>Wire</code> object, this
+	 * methods returns the last value provided by the Producer service. This
+	 * value may be an <code>Envelope[]</code> when the Producer service uses
+	 * scoping. If the return value is an Envelope object (or array), it must be
+	 * verified that the Consumer service has the proper WirePermission to see
+	 * it.
+	 * 
+	 * @return The last value passed though this <code>Wire</code> object or
+	 *         <code>null</code> if no valid values have been passed or the
+	 *         Consumer service has no permission.
+	 */
+	public Object getLastValue();
+
+	/**
+	 * Return the wire properties for this <code>Wire</code> object.
+	 * 
+	 * @return The properties for this <code>Wire</code> object. The returned
+	 *         <code>Dictionary</code> must be read only.
+	 */
+	public Dictionary getProperties();
+
+	/**
+	 * Return the calculated scope of this <code>Wire</code> object.
+	 * 
+	 * The purpose of the <code>Wire</code> object's scope is to allow a Producer
+	 * and/or Consumer service to produce/consume different types over a single
+	 * <code>Wire</code> object (this was deemed necessary for efficiency
+	 * reasons). Both the Consumer service and the Producer service must set an
+	 * array of scope names (their scope) with the service registration property
+	 * <code>WIREADMIN_PRODUCER_SCOPE</code>, or
+	 * <code>WIREADMIN_CONSUMER_SCOPE</code> when they can produce multiple types.
+	 * If a Producer service can produce different types, it should set this
+	 * property to the array of scope names it can produce, the Consumer service
+	 * must set the array of scope names it can consume. The scope of a
+	 * <code>Wire</code> object is defined as the intersection of permitted scope
+	 * names of the Producer service and Consumer service.
+	 * <p>
+	 * If neither the Consumer, or the Producer service registers scope names
+	 * with its service registration, then the <code>Wire</code> object's scope
+	 * must be <code>null</code>.
+	 * <p>
+	 * The <code>Wire</code> object's scope must not change when a Producer or
+	 * Consumer services modifies its scope.
+	 * <p>
+	 * A scope name is permitted for a Producer service when the registering
+	 * bundle has <code>WirePermission[name,PRODUCE]</code>, and for a Consumer
+	 * service when the registering bundle has <code>WirePermission[name,CONSUME]</code>.
+	 * <p>
+	 * If either Consumer service or Producer service has not set a
+	 * <code>WIREADMIN_*_SCOPE</code> property, then the returned value must be
+	 * <code>null</code>.
+	 * <p>
+	 * If the scope is set, the <code>Wire</code> object must enforce the scope
+	 * names when <code>Envelope</code> objects are used as a parameter to update
+	 * or returned from the <code>poll</code> method. The <code>Wire</code> object
+	 * must then remove all <code>Envelope</code> objects with a scope name that
+	 * is not permitted.
+	 * 
+	 * @return A list of permitted scope names or null if the Produce or
+	 *         Consumer service has set no scope names.
+	 */
+	public String[] getScope();
+
+	/**
+	 * Return true if the given name is in this <code>Wire</code> object's scope.
+	 * 
+	 * @param name The scope name
+	 * @return true if the name is listed in the permitted scope names
+	 */
+	public boolean hasScope(String name);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireAdmin.java b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireAdmin.java
new file mode 100644
index 0000000..7752937
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireAdmin.java
@@ -0,0 +1,169 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.wireadmin/src/org/osgi/service/wireadmin/WireAdmin.java,v 1.8 2006/03/14 01:20:55 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.wireadmin;
+
+import java.util.Dictionary;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * Wire Administration service.
+ * 
+ * <p>
+ * This service can be used to create <code>Wire</code> objects connecting a
+ * Producer service and a Consumer service. <code>Wire</code> objects also have
+ * wire properties that may be specified when a <code>Wire</code> object is
+ * created. The Producer and Consumer services may use the <code>Wire</code>
+ * object's properties to manage or control their interaction. The use of
+ * <code>Wire</code> object's properties by a Producer or Consumer services is
+ * optional.
+ * 
+ * <p>
+ * Security Considerations. A bundle must have
+ * <code>ServicePermission[WireAdmin,GET]</code> to get the Wire Admin service to
+ * create, modify, find, and delete <code>Wire</code> objects.
+ * 
+ * @version $Revision: 1.8 $
+ */
+public interface WireAdmin {
+	/**
+	 * Create a new <code>Wire</code> object that connects a Producer service to a
+	 * Consumer service.
+	 * 
+	 * The Producer service and Consumer service do not have to be registered
+	 * when the <code>Wire</code> object is created.
+	 * 
+	 * <p>
+	 * The <code>Wire</code> configuration data must be persistently stored. All
+	 * <code>Wire</code> connections are reestablished when the <code>WireAdmin</code>
+	 * service is registered. A <code>Wire</code> can be permanently removed by
+	 * using the {@link #deleteWire}method.
+	 * 
+	 * <p>
+	 * The <code>Wire</code> object's properties must have case insensitive
+	 * <code>String</code> objects as keys (like the Framework). However, the case
+	 * of the key must be preserved.
+	 * 
+	 * <p>
+	 * The <code>WireAdmin</code> service must automatically add the following
+	 * <code>Wire</code> properties:
+	 * <ul>
+	 * <li>{@link WireConstants#WIREADMIN_PID}set to the value of the
+	 * <code>Wire</code> object's persistent identity (PID). This value is
+	 * generated by the Wire Admin service when a <code>Wire</code> object is
+	 * created.</li>
+	 * <li>{@link WireConstants#WIREADMIN_PRODUCER_PID}set to the value of
+	 * Producer service's PID.</li>
+	 * <li>{@link WireConstants#WIREADMIN_CONSUMER_PID}set to the value of
+	 * Consumer service's PID.</li>
+	 * </ul>
+	 * If the <code>properties</code> argument already contains any of these keys,
+	 * then the supplied values are replaced with the values assigned by the
+	 * Wire Admin service.
+	 * 
+	 * <p>
+	 * The Wire Admin service must broadcast a <code>WireAdminEvent</code> of type
+	 * {@link WireAdminEvent#WIRE_CREATED}after the new <code>Wire</code> object
+	 * becomes available from {@link #getWires}.
+	 * 
+	 * @param producerPID The <code>service.pid</code> of the Producer service to
+	 *        be connected to the <code>Wire</code> object.
+	 * @param consumerPID The <code>service.pid</code> of the Consumer service to
+	 *        be connected to the <code>Wire</code> object.
+	 * @param properties The <code>Wire</code> object's properties. This argument
+	 *        may be <code>null</code> if the caller does not wish to define any
+	 *        <code>Wire</code> object's properties.
+	 * @return The <code>Wire</code> object for this connection.
+	 * 
+	 * @throws java.lang.IllegalArgumentException If <code>properties</code>
+	 *         contains invalid wire types or case variants of the same key
+	 *         name.
+	 */
+	public Wire createWire(String producerPID, String consumerPID,
+			Dictionary properties);
+
+	/**
+	 * Delete a <code>Wire</code> object.
+	 * 
+	 * <p>
+	 * The <code>Wire</code> object representing a connection between a Producer
+	 * service and a Consumer service must be removed. The persistently stored
+	 * configuration data for the <code>Wire</code> object must destroyed. The
+	 * <code>Wire</code> object's method {@link Wire#isValid}will return
+	 * <code>false</code> after it is deleted.
+	 * 
+	 * <p>
+	 * The Wire Admin service must broadcast a <code>WireAdminEvent</code> of type
+	 * {@link WireAdminEvent#WIRE_DELETED}after the <code>Wire</code> object
+	 * becomes invalid.
+	 * 
+	 * @param wire The <code>Wire</code> object which is to be deleted.
+	 */
+	public void deleteWire(Wire wire);
+
+	/**
+	 * Update the properties of a <code>Wire</code> object.
+	 * 
+	 * The persistently stored configuration data for the <code>Wire</code> object
+	 * is updated with the new properties and then the Consumer and Producer
+	 * services will be called at the respective
+	 * {@link Consumer#producersConnected}and
+	 * {@link Producer#consumersConnected}methods.
+	 * 
+	 * <p>
+	 * The Wire Admin service must broadcast a <code>WireAdminEvent</code> of type
+	 * {@link WireAdminEvent#WIRE_UPDATED}after the updated properties are
+	 * available from the <code>Wire</code> object.
+	 * 
+	 * @param wire The <code>Wire</code> object which is to be updated.
+	 * @param properties The new <code>Wire</code> object's properties or
+	 *        <code>null</code> if no properties are required.
+	 * 
+	 * @throws java.lang.IllegalArgumentException If <code>properties</code>
+	 *         contains invalid wire types or case variants of the same key
+	 *         name.
+	 */
+	public void updateWire(Wire wire, Dictionary properties);
+
+	/**
+	 * Return the <code>Wire</code> objects that match the given <code>filter</code>.
+	 * 
+	 * <p>
+	 * The list of available <code>Wire</code> objects is matched against the
+	 * specified <code>filter</code>.<code>Wire</code> objects which match the
+	 * <code>filter</code> must be returned. These <code>Wire</code> objects are not
+	 * necessarily connected. The Wire Admin service should not return invalid
+	 * <code>Wire</code> objects, but it is possible that a <code>Wire</code> object
+	 * is deleted after it was placed in the list.
+	 * 
+	 * <p>
+	 * The filter matches against the <code>Wire</code> object's properties
+	 * including {@link WireConstants#WIREADMIN_PRODUCER_PID},
+	 * {@link WireConstants#WIREADMIN_CONSUMER_PID}and
+	 * {@link WireConstants#WIREADMIN_PID}.
+	 * 
+	 * @param filter Filter string to select <code>Wire</code> objects or
+	 *        <code>null</code> to select all <code>Wire</code> objects.
+	 * @return An array of <code>Wire</code> objects which match the
+	 *         <code>filter</code> or <code>null</code> if no <code>Wire</code>
+	 *         objects match the <code>filter</code>.
+	 * @throws org.osgi.framework.InvalidSyntaxException If the specified
+	 *         <code>filter</code> has an invalid syntax.
+	 * @see org.osgi.framework.Filter
+	 */
+	public Wire[] getWires(String filter) throws InvalidSyntaxException;
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireAdminEvent.java b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireAdminEvent.java
new file mode 100644
index 0000000..e3981bb
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireAdminEvent.java
@@ -0,0 +1,268 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.wireadmin/src/org/osgi/service/wireadmin/WireAdminEvent.java,v 1.7 2006/03/14 01:20:55 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.wireadmin;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A Wire Admin Event.
+ * 
+ * <p>
+ * <code>WireAdminEvent</code> objects are delivered to all registered
+ * <code>WireAdminListener</code> service objects which specify an interest in the
+ * <code>WireAdminEvent</code> type. Events must be delivered in chronological
+ * order with respect to each listener. For example, a <code>WireAdminEvent</code>
+ * of type {@link #WIRE_CONNECTED}must be delivered before a
+ * <code>WireAdminEvent</code> of type {@link #WIRE_DISCONNECTED}for a particular
+ * <code>Wire</code> object.
+ * 
+ * <p>
+ * A type code is used to identify the type of event. The following event types
+ * are defined:
+ * <ul>
+ * <li>{@link #WIRE_CREATED}
+ * <li>{@link #WIRE_CONNECTED}
+ * <li>{@link #WIRE_UPDATED}
+ * <li>{@link #WIRE_TRACE}
+ * <li>{@link #WIRE_DISCONNECTED}
+ * <li>{@link #WIRE_DELETED}
+ * <li>{@link #PRODUCER_EXCEPTION}
+ * <li>{@link #CONSUMER_EXCEPTION}
+ * </ul>
+ * Additional event types may be defined in the future.
+ * 
+ * <p>
+ * Event type values must be unique and disjoint bit values. Event types must be
+ * defined as a bit in a 32 bit integer and can thus be bitwise OR'ed together.
+ * <p>
+ * Security Considerations. <code>WireAdminEvent</code> objects contain
+ * <code>Wire</code> objects. Care must be taken in the sharing of <code>Wire</code>
+ * objects with other bundles.
+ * 
+ * @see WireAdminListener
+ * 
+ * @version $Revision: 1.7 $
+ */
+public class WireAdminEvent {
+	/**
+	 * The WireAdmin service which created this event.
+	 */
+	private ServiceReference	reference;
+	/**
+	 * The <code>Wire</code> object associated with this event.
+	 */
+	private Wire				wire;
+	/**
+	 * Type of this event.
+	 * 
+	 * @see #getType
+	 */
+	private int					type;
+	/**
+	 * Exception associates with this the event.
+	 */
+	private Throwable			throwable;
+	/**
+	 * A Producer service method has thrown an exception.
+	 * 
+	 * <p>
+	 * This <code>WireAdminEvent</code> type indicates that a Producer service
+	 * method has thrown an exception. The {@link WireAdminEvent#getThrowable}
+	 * method will return the exception that the Producer service method raised.
+	 * 
+	 * <p>
+	 * The value of <code>PRODUCER_EXCEPTION</code> is 0x00000001.
+	 */
+	public final static int		PRODUCER_EXCEPTION	= 0x00000001;
+	/**
+	 * A Consumer service method has thrown an exception.
+	 * 
+	 * <p>
+	 * This <code>WireAdminEvent</code> type indicates that a Consumer service
+	 * method has thrown an exception. The {@link WireAdminEvent#getThrowable}
+	 * method will return the exception that the Consumer service method raised.
+	 * 
+	 * <p>
+	 * The value of <code>CONSUMER_EXCEPTION</code> is 0x00000002.
+	 */
+	public final static int		CONSUMER_EXCEPTION	= 0x00000002;
+	/**
+	 * A <code>Wire</code> has been created.
+	 * 
+	 * <p>
+	 * This <code>WireAdminEvent</code> type that indicates that a new
+	 * <code>Wire</code> object has been created.
+	 * 
+	 * An event is broadcast when {@link WireAdmin#createWire}is called. The
+	 * {@link WireAdminEvent#getWire}method will return the <code>Wire</code>
+	 * object that has just been created.
+	 * 
+	 * <p>
+	 * The value of <code>WIRE_CREATED</code> is 0x00000004.
+	 */
+	public final static int		WIRE_CREATED		= 0x00000004;
+	/**
+	 * A <code>Wire</code> has been updated.
+	 * 
+	 * <p>
+	 * This <code>WireAdminEvent</code> type that indicates that an existing
+	 * <code>Wire</code> object has been updated with new properties.
+	 * 
+	 * An event is broadcast when {@link WireAdmin#updateWire}is called with a
+	 * valid wire. The {@link WireAdminEvent#getWire}method will return the
+	 * <code>Wire</code> object that has just been updated.
+	 * 
+	 * <p>
+	 * The value of <code>WIRE_UPDATED</code> is 0x00000008.
+	 */
+	public final static int		WIRE_UPDATED		= 0x00000008;
+	/**
+	 * A <code>Wire</code> has been deleted.
+	 * 
+	 * <p>
+	 * This <code>WireAdminEvent</code> type that indicates that an existing wire
+	 * has been deleted.
+	 * 
+	 * An event is broadcast when {@link WireAdmin#deleteWire}is called with a
+	 * valid wire. {@link WireAdminEvent#getWire}will return the <code>Wire</code>
+	 * object that has just been deleted.
+	 * 
+	 * <p>
+	 * The value of <code>WIRE_DELETED</code> is 0x00000010.
+	 */
+	public final static int		WIRE_DELETED		= 0x00000010;
+	/**
+	 * The <code>WireAdminEvent</code> type that indicates that an existing
+	 * <code>Wire</code> object has become connected.
+	 * 
+	 * The Consumer object and the Producer object that are associated with the
+	 * <code>Wire</code> object have both been registered and the <code>Wire</code>
+	 * object is connected. See {@link Wire#isConnected}for a description of
+	 * the connected state. This event may come before the
+	 * <code>producersConnected</code> and <code>consumersConnected</code> method
+	 * have returned or called to allow synchronous delivery of the events. Both
+	 * methods can cause other <code>WireAdminEvent</code> s to take place and
+	 * requiring this event to be send before these methods are returned would
+	 * mandate asynchronous delivery.
+	 * 
+	 * <p>
+	 * The value of <code>WIRE_CONNECTED</code> is 0x00000020.
+	 */
+	public final static int		WIRE_CONNECTED		= 0x00000020;
+	/**
+	 * The <code>WireAdminEvent</code> type that indicates that an existing
+	 * <code>Wire</code> object has become disconnected.
+	 * 
+	 * The Consumer object or/and Producer object is/are unregistered breaking
+	 * the connection between the two. See {@link Wire#isConnected}for a
+	 * description of the connected state.
+	 * 
+	 * <p>
+	 * The value of <code>WIRE_DISCONNECTED</code> is 0x00000040.
+	 */
+	public final static int		WIRE_DISCONNECTED	= 0x00000040;
+	/**
+	 * The <code>WireAdminEvent</code> type that indicates that a new value is
+	 * transferred over the <code>Wire</code> object.
+	 * 
+	 * This event is sent after the Consumer service has been notified by
+	 * calling the {@link Consumer#updated}method or the Consumer service
+	 * requested a new value with the {@link Wire#poll}method. This is an
+	 * advisory event meaning that when this event is received, another update
+	 * may already have occurred and this the {@link Wire#getLastValue}method
+	 * returns a newer value then the value that was communicated for this
+	 * event.
+	 * 
+	 * <p>
+	 * The value of <code>WIRE_TRACE</code> is 0x00000080.
+	 */
+	public final static int		WIRE_TRACE			= 0x00000080;
+
+	/**
+	 * Constructs a <code>WireAdminEvent</code> object from the given
+	 * <code>ServiceReference</code> object, event type, <code>Wire</code> object
+	 * and exception.
+	 * 
+	 * @param reference The <code>ServiceReference</code> object of the Wire Admin
+	 *        service that created this event.
+	 * @param type The event type. See {@link #getType}.
+	 * @param wire The <code>Wire</code> object associated with this event.
+	 * @param exception An exception associated with this event. This may be
+	 *        <code>null</code> if no exception is associated with this event.
+	 */
+	public WireAdminEvent(ServiceReference reference, int type, Wire wire,
+			Throwable exception) {
+		this.reference = reference;
+		this.wire = wire;
+		this.type = type;
+		this.throwable = exception;
+	}
+
+	/**
+	 * Return the <code>ServiceReference</code> object of the Wire Admin service
+	 * that created this event.
+	 * 
+	 * @return The <code>ServiceReference</code> object for the Wire Admin service
+	 *         that created this event.
+	 */
+	public ServiceReference getServiceReference() {
+		return reference;
+	}
+
+	/**
+	 * Return the <code>Wire</code> object associated with this event.
+	 * 
+	 * @return The <code>Wire</code> object associated with this event or
+	 *         <code>null</code> when no <code>Wire</code> object is associated with
+	 *         the event.
+	 */
+	public Wire getWire() {
+		return wire;
+	}
+
+	/**
+	 * Return the type of this event.
+	 * <p>
+	 * The type values are:
+	 * <ul>
+	 * <li>{@link #WIRE_CREATED}
+	 * <li>{@link #WIRE_CONNECTED}
+	 * <li>{@link #WIRE_UPDATED}
+	 * <li>{@link #WIRE_TRACE}
+	 * <li>{@link #WIRE_DISCONNECTED}
+	 * <li>{@link #WIRE_DELETED}
+	 * <li>{@link #PRODUCER_EXCEPTION}
+	 * <li>{@link #CONSUMER_EXCEPTION}
+	 * </ul>
+	 * 
+	 * @return The type of this event.
+	 */
+	public int getType() {
+		return type;
+	}
+
+	/**
+	 * Returns the exception associated with the event, if any.
+	 * 
+	 * @return An exception or <code>null</code> if no exception is associated
+	 *         with this event.
+	 */
+	public Throwable getThrowable() {
+		return throwable;
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireAdminListener.java b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireAdminListener.java
new file mode 100644
index 0000000..2824715
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireAdminListener.java
@@ -0,0 +1,74 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.wireadmin/src/org/osgi/service/wireadmin/WireAdminListener.java,v 1.8 2006/03/14 01:20:55 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.wireadmin;
+
+/**
+ * Listener for Wire Admin Events.
+ * 
+ * <p>
+ * <code>WireAdminListener</code> objects are registered with the Framework
+ * service registry and are notified with a <code>WireAdminEvent</code> object
+ * when an event is broadcast.
+ * <p>
+ * <code>WireAdminListener</code> objects can inspect the received
+ * <code>WireAdminEvent</code> object to determine its type, the <code>Wire</code>
+ * object with which it is associated, and the Wire Admin service that
+ * broadcasts the event.
+ * 
+ * <p>
+ * <code>WireAdminListener</code> objects must be registered with a service
+ * property {@link WireConstants#WIREADMIN_EVENTS}whose value is a bitwise OR
+ * of all the event types the listener is interested in receiving.
+ * <p>
+ * For example:
+ * 
+ * <pre>
+ * Integer mask = new Integer(WIRE_TRACE | WIRE_CONNECTED | WIRE_DISCONNECTED);
+ * Hashtable ht = new Hashtable();
+ * ht.put(WIREADMIN_EVENTS, mask);
+ * context.registerService(WireAdminListener.class.getName(), this, ht);
+ * </pre>
+ * 
+ * If a <code>WireAdminListener</code> object is registered without a service
+ * property {@link WireConstants#WIREADMIN_EVENTS}, then the
+ * <code>WireAdminListener</code> will receive no events.
+ * 
+ * <p>
+ * Security Considerations. Bundles wishing to monitor <code>WireAdminEvent</code>
+ * objects will require <code>ServicePermission[WireAdminListener,REGISTER]</code>
+ * to register a <code>WireAdminListener</code> service. Since
+ * <code>WireAdminEvent</code> objects contain <code>Wire</code> objects, care must
+ * be taken in assigning permission to register a <code>WireAdminListener</code>
+ * service.
+ * 
+ * @see WireAdminEvent
+ * 
+ * @version $Revision: 1.8 $
+ */
+public interface WireAdminListener {
+	/**
+	 * Receives notification of a broadcast <code>WireAdminEvent</code> object.
+	 * 
+	 * The event object will be of an event type specified in this
+	 * <code>WireAdminListener</code> service's
+	 * {@link WireConstants#WIREADMIN_EVENTS}service property.
+	 * 
+	 * @param event The <code>WireAdminEvent</code> object.
+	 */
+	void wireAdminEvent(WireAdminEvent event);
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireConstants.java b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireConstants.java
new file mode 100644
index 0000000..80f6f0e
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WireConstants.java
@@ -0,0 +1,227 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.wireadmin/src/org/osgi/service/wireadmin/WireConstants.java,v 1.8 2006/03/14 01:20:55 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.wireadmin;
+
+/**
+ * Defines standard names for <code>Wire</code> properties, wire filter
+ * attributes, Consumer and Producer service properties.
+ * 
+ * @version $Revision: 1.8 $
+ */
+public interface WireConstants {
+	/**
+	 * <code>Wire</code> property key (named <code>wireadmin.pid</code>) specifying
+	 * the persistent identity (PID) of this <code>Wire</code> object.
+	 * 
+	 * <p>
+	 * Each <code>Wire</code> object has a PID to allow unique and persistent
+	 * identification of a specific <code>Wire</code> object. The PID must be
+	 * generated by the {@link WireAdmin}service when the <code>Wire</code>
+	 * object is created.
+	 * 
+	 * <p>
+	 * This wire property is automatically set by the Wire Admin service. The
+	 * value of the property must be of type <code>String</code>.
+	 */
+	public final static String	WIREADMIN_PID					= "wireadmin.pid";
+	/**
+	 * A service registration property for a Producer service that is composite.
+	 * It contains the names of the composite Consumer services it can
+	 * inter-operate with. Inter-operability exists when any name in this array
+	 * matches any name in the array set by the Consumer service. The type of
+	 * this property must be <code>String[]</code>.
+	 */
+	public final static String	WIREADMIN_PRODUCER_COMPOSITE	= "wireadmin.producer.composite";
+	/**
+	 * A service registration property for a Consumer service that is composite.
+	 * It contains the names of the composite Producer services it can cooperate
+	 * with. Inter-operability exists when any name in this array matches any
+	 * name in the array set by the Producer service. The type of this property
+	 * must be <code>String[]</code>.
+	 */
+	public final static String	WIREADMIN_CONSUMER_COMPOSITE	= "wireadmin.consumer.composite";
+	/**
+	 * Service registration property key (named
+	 * <code>wireadmin.producer.scope</code>) specifying a list of names that may
+	 * be used to define the scope of this <code>Wire</code> object. A Producer
+	 * service should set this service property when it can produce more than
+	 * one kind of value. This property is only used during registration,
+	 * modifying the property must not have any effect of the <code>Wire</code>
+	 * object's scope. Each name in the given list mist have
+	 * <code>WirePermission[name,PRODUCE]</code> or else is ignored. The type of
+	 * this service registration property must be <code>String[]</code>.
+	 * 
+	 * @see Wire#getScope
+	 * @see #WIREADMIN_CONSUMER_SCOPE
+	 */
+	public final static String	WIREADMIN_PRODUCER_SCOPE		= "wireadmin.producer.scope";
+	/**
+	 * Service registration property key (named
+	 * <code>wireadmin.consumer.scope</code>) specifying a list of names that may
+	 * be used to define the scope of this <code>Wire</code> object. A
+	 * <code>Consumer</code> service should set this service property when it can
+	 * produce more than one kind of value. This property is only used during
+	 * registration, modifying the property must not have any effect of the
+	 * <code>Wire</code> object's scope. Each name in the given list mist have
+	 * <code>WirePermission[name,CONSUME]</code> or else is ignored. The type of this
+	 * service registration property must be <code>String[]</code>.
+	 * 
+	 * @see Wire#getScope
+	 * @see #WIREADMIN_PRODUCER_SCOPE
+	 */
+	public final static String	WIREADMIN_CONSUMER_SCOPE		= "wireadmin.consumer.scope";
+	/**
+	 * Matches all scope names.
+	 */
+	public final static String	WIREADMIN_SCOPE_ALL[]			= {"*"};
+	/**
+	 * <code>Wire</code> property key (named <code>wireadmin.producer.pid</code>)
+	 * specifying the <code>service.pid</code> of the associated Producer service.
+	 * 
+	 * <p>
+	 * This wire property is automatically set by the WireAdmin service. The
+	 * value of the property must be of type <code>String</code>.
+	 */
+	public final static String	WIREADMIN_PRODUCER_PID			= "wireadmin.producer.pid";
+	/**
+	 * <code>Wire</code> property key (named <code>wireadmin.consumer.pid</code>)
+	 * specifying the <code>service.pid</code> of the associated Consumer service.
+	 * 
+	 * <p>
+	 * This wire property is automatically set by the Wire Admin service. The
+	 * value of the property must be of type <code>String</code>.
+	 */
+	public final static String	WIREADMIN_CONSUMER_PID			= "wireadmin.consumer.pid";
+	/**
+	 * <code>Wire</code> property key (named <code>wireadmin.filter</code>)
+	 * specifying a filter used to control the delivery rate of data between the
+	 * Producer and the Consumer service.
+	 * 
+	 * <p>
+	 * This property should contain a filter as described in the <code>Filter</code>
+	 * class. The filter can be used to specify when an updated value from the
+	 * Producer service should be delivered to the Consumer service. In many
+	 * cases the Consumer service does not need to receive the data with the
+	 * same rate that the Producer service can generate data. This property can
+	 * be used to control the delivery rate.
+	 * <p>
+	 * The filter can use a number of pre-defined attributes that can be used to
+	 * control the delivery of new data values. If the filter produces a match
+	 * upon the wire filter attributes, the Consumer service should be notifed
+	 * of the updated data value.
+	 * <p>
+	 * If the Producer service was registered with the
+	 * {@link #WIREADMIN_PRODUCER_FILTERS}service property indicating that the
+	 * Producer service will perform the data filtering then the <code>Wire</code>
+	 * object will not perform data filtering. Otherwise, the <code>Wire</code>
+	 * object must perform basic filtering. Basic filtering includes supporting
+	 * the following standard wire filter attributes:
+	 * <ul>
+	 * <li>{@link #WIREVALUE_CURRENT}- Current value
+	 * <li>{@link #WIREVALUE_PREVIOUS}- Previous value
+	 * <li>{@link #WIREVALUE_DELTA_ABSOLUTE}- Absolute delta
+	 * <li>{@link #WIREVALUE_DELTA_RELATIVE}- Relative delta
+	 * <li>{@link #WIREVALUE_ELAPSED}- Elapsed time
+	 * </ul>
+	 * 
+	 * @see org.osgi.framework.Filter
+	 */
+	public final static String	WIREADMIN_FILTER				= "wireadmin.filter";
+	/* Wire filter attribute names. */
+	/**
+	 * <code>Wire</code> object's filter attribute (named
+	 * <code>wirevalue.current</code>) representing the current value.
+	 */
+	public final static String	WIREVALUE_CURRENT				= "wirevalue.current";
+	/**
+	 * <code>Wire</code> object's filter attribute (named
+	 * <code>wirevalue.previous</code>) representing the previous value.
+	 */
+	public final static String	WIREVALUE_PREVIOUS				= "wirevalue.previous";
+	/**
+	 * <code>Wire</code> object's filter attribute (named
+	 * <code>wirevalue.delta.absolute</code>) representing the absolute delta.
+	 * The absolute (always positive) difference between the last update and the
+	 * current value (only when numeric). This attribute must not be used when
+	 * the values are not numeric.
+	 */
+	public final static String	WIREVALUE_DELTA_ABSOLUTE		= "wirevalue.delta.absolute";
+	/**
+	 * <code>Wire</code> object's filter attribute (named
+	 * <code>wirevalue.delta.relative</code>) representing the relative delta.
+	 * The relative difference is |<code>previous</code>-<code>current</code> |/|
+	 * <code>current</code>| (only when numeric). This attribute must not be used
+	 * when the values are not numeric.
+	 */
+	public final static String	WIREVALUE_DELTA_RELATIVE		= "wirevalue.delta.relative";
+	/**
+	 * <code>Wire</code> object's filter attribute (named
+	 * <code>wirevalue.elapsed</code>) representing the elapsed time, in ms,
+	 * between this filter evaluation and the last update of the
+	 * <code>Consumer</code> service.
+	 */
+	public final static String	WIREVALUE_ELAPSED				= "wirevalue.elapsed";
+	/* Service registration property key names. */
+	/**
+	 * Service Registration property (named <code>wireadmin.producer.filters</code>).
+	 * A <code>Producer</code> service registered with this property indicates to
+	 * the Wire Admin service that the Producer service implements at least the
+	 * filtering as described for the {@link #WIREADMIN_FILTER}property. If the
+	 * Producer service is not registered with this property, the <code>Wire</code>
+	 * object must perform the basic filtering as described in
+	 * {@link #WIREADMIN_FILTER}.
+	 * 
+	 * <p>
+	 * The type of the property value is not relevant. Only its presence is
+	 * relevant.
+	 */
+	public final static String	WIREADMIN_PRODUCER_FILTERS		= "wireadmin.producer.filters";
+	/**
+	 * Service Registration property (named <code>wireadmin.consumer.flavors</code>)
+	 * specifying the list of data types understood by this Consumer service.
+	 * 
+	 * <p>
+	 * The Consumer service object must be registered with this service
+	 * property. The list must be in the order of preference with the first type
+	 * being the most preferred. The value of the property must be of type
+	 * <code>Class[]</code>.
+	 */
+	public final static String	WIREADMIN_CONSUMER_FLAVORS		= "wireadmin.consumer.flavors";
+	/**
+	 * Service Registration property (named <code>wireadmin.producer.flavors</code>)
+	 * specifying the list of data types available from this Producer service.
+	 * 
+	 * <p>
+	 * The Producer service object should be registered with this service
+	 * property.
+	 * 
+	 * <p>
+	 * The value of the property must be of type <code>Class[]</code>.
+	 */
+	public final static String	WIREADMIN_PRODUCER_FLAVORS		= "wireadmin.producer.flavors";
+	/**
+	 * Service Registration property (named <code>wireadmin.events</code>)
+	 * specifying the <code>WireAdminEvent</code> type of interest to a Wire Admin
+	 * Listener service. The value of the property is a bitwise OR of all the
+	 * <code>WireAdminEvent</code> types the Wire Admin Listener service wishes to
+	 * receive and must be of type <code>Integer</code>.
+	 * 
+	 * @see WireAdminEvent
+	 */
+	public final static String	WIREADMIN_EVENTS				= "wireadmin.events";
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WirePermission.java b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WirePermission.java
new file mode 100644
index 0000000..671a9a3
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/WirePermission.java
@@ -0,0 +1,462 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.wireadmin/src/org/osgi/service/wireadmin/WirePermission.java,v 1.11 2006/03/14 01:20:55 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). 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.wireadmin;
+
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.security.Permission;
+import java.security.BasicPermission;
+import java.security.PermissionCollection;
+
+/**
+ * Permission for the scope of a <code>Wire</code> object. When a
+ * <code>Envelope</code> object is used for communication with the <code>poll</code>
+ * or <code>update</code> method, and the scope is set, then the <code>Wire</code>
+ * object must verify that the Consumer service has
+ * <code>WirePermission[name,CONSUME]</code> and the Producer service has
+ * <code>WirePermission[name,PRODUCE]</code> for all names in the scope.
+ * <p>
+ * The names are compared with the normal rules for permission names. This means
+ * that they may end with a "*" to indicate wildcards. E.g. Door.* indicates all
+ * scope names starting with the string "Door". The last period is required due
+ * to the implementations of the <code>BasicPermission</code> class.
+ * 
+ * @version $Revision: 1.11 $
+ */
+final public class WirePermission extends BasicPermission {
+    static final long serialVersionUID = -5583709391516569321L;
+	/**
+	 * The action string for the <code>PRODUCE</code> action: value is "produce".
+	 */
+	public static final String	PRODUCE			= "produce";
+	/**
+	 * The action string for the <code>CONSUME</code> action: value is "consume".
+	 */
+	public static final String	CONSUME			= "consume";
+	private final static int	ACTION_PRODUCE	= 0x00000001;
+	private final static int	ACTION_CONSUME	= 0x00000002;
+	private final static int	ACTION_ALL		= ACTION_PRODUCE
+														| ACTION_CONSUME;
+	private final static int	ACTION_NONE		= 0;
+	/**
+	 * The actions mask.
+	 */
+	private transient int		action_mask		= ACTION_NONE;
+	/**
+	 * The actions in canonical form.
+	 * 
+	 * @serial
+	 */
+	private String				actions			= null;
+
+	/**
+	 * Create a new WirePermission with the given name (may be wildcard) and
+	 * actions.
+	 * @param name Wire name.
+	 * @param actions <code>produce</code>, <code>consume</code>
+	 *        (canonical order).
+	 */
+	public WirePermission(String name, String actions) {
+		this(name, getMask(actions));
+	}
+
+	/**
+	 * Package private constructor used by WirePermissionCollection.
+	 * 
+	 * @param name class name
+	 * @param mask action mask
+	 */
+	WirePermission(String name, int mask) {
+		super(name);
+		init(mask);
+	}
+
+	/**
+	 * Called by constructors and when deserialized.
+	 * 
+	 * @param mask action mask
+	 */
+	private void init(int mask) {
+		if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
+			throw new IllegalArgumentException("invalid action string");
+		}
+		action_mask = mask;
+	}
+
+	/**
+	 * Parse action string into action mask.
+	 * 
+	 * @param actions Action string.
+	 * @return action mask.
+	 */
+	private static int getMask(String actions) {
+		boolean seencomma = false;
+		int mask = ACTION_NONE;
+		if (actions == null) {
+			return mask;
+		}
+		char[] a = actions.toCharArray();
+		int i = a.length - 1;
+		if (i < 0)
+			return mask;
+		while (i != -1) {
+			char c;
+			// skip whitespace
+			while ((i != -1)
+					&& ((c = a[i]) == ' ' || c == '\r' || c == '\n'
+							|| c == '\f' || c == '\t'))
+				i--;
+			// check for the known strings
+			int matchlen;
+			if (i >= 6 && (a[i - 6] == 'p' || a[i - 6] == 'P')
+					&& (a[i - 5] == 'r' || a[i - 5] == 'R')
+					&& (a[i - 4] == 'o' || a[i - 4] == 'O')
+					&& (a[i - 3] == 'd' || a[i - 3] == 'D')
+					&& (a[i - 2] == 'u' || a[i - 2] == 'U')
+					&& (a[i - 1] == 'c' || a[i - 1] == 'C')
+					&& (a[i] == 'e' || a[i] == 'E')) {
+				matchlen = 7;
+				mask |= ACTION_PRODUCE;
+			}
+			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] == 's' || a[i - 3] == 'S')
+						&& (a[i - 2] == 'u' || a[i - 2] == 'U')
+						&& (a[i - 1] == 'm' || a[i - 1] == 'M')
+						&& (a[i] == 'e' || a[i] == 'E')) {
+					matchlen = 7;
+					mask |= ACTION_CONSUME;
+				}
+				else {
+					// parse error
+					throw new IllegalArgumentException("invalid permission: "
+							+ actions);
+				}
+			// make sure we didn't just match the tail of a word
+			// like "ackbarfregister". Also, skip to the comma.
+			seencomma = false;
+			while (i >= matchlen && !seencomma) {
+				switch (a[i - matchlen]) {
+					case ',' :
+						seencomma = true;
+					/* FALLTHROUGH */
+					case ' ' :
+					case '\r' :
+					case '\n' :
+					case '\f' :
+					case '\t' :
+						break;
+					default :
+						throw new IllegalArgumentException(
+								"invalid permission: " + actions);
+				}
+				i--;
+			}
+			// point i at the location of the comma minus one (or -1).
+			i -= matchlen;
+		}
+		if (seencomma) {
+			throw new IllegalArgumentException("invalid permission: " + actions);
+		}
+		return mask;
+	}
+
+	/**
+	 * Checks if this <code>WirePermission</code> object <code>implies</code> the
+	 * specified permission.
+	 * <P>
+	 * More specifically, this method returns <code>true</code> if:
+	 * <p>
+	 * <ul>
+	 * <li><i>p </i> is an instanceof the <code>WirePermission</code> class,
+	 * <li><i>p </i>'s actions are a proper subset of this object's actions,
+	 * and
+	 * <li><i>p </i>'s name is implied by this object's name. For example,
+	 * <code>java.*</code> implies <code>java.home</code>.
+	 * </ul>
+	 * 
+	 * @param p The permission to check against.
+	 * 
+	 * @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 WirePermission) {
+			WirePermission target = (WirePermission) p;
+			return ((action_mask & target.action_mask) == target.action_mask)
+					&& super.implies(p);
+		}
+		return false;
+	}
+
+	/**
+	 * Returns the canonical string representation of the actions. Always
+	 * returns present actions in the following order: <code>produce</code>,
+	 * <code>consume</code>.
+	 * 
+	 * @return The canonical string representation of the actions.
+	 */
+	public String getActions() {
+		if (actions == null) {
+			StringBuffer sb = new StringBuffer();
+			boolean comma = false;
+			if ((action_mask & ACTION_PRODUCE) == ACTION_PRODUCE) {
+				sb.append(PRODUCE);
+				comma = true;
+			}
+			if ((action_mask & ACTION_CONSUME) == ACTION_CONSUME) {
+				if (comma)
+					sb.append(',');
+				sb.append(CONSUME);
+			}
+			actions = sb.toString();
+		}
+		return actions;
+	}
+
+	/**
+	 * Returns a new <code>PermissionCollection</code> object for storing
+	 * <code>WirePermission</code> objects.
+	 * 
+	 * @return A new <code>PermissionCollection</code> object suitable for storing
+	 *         <code>WirePermission</code> objects.
+	 */
+	public PermissionCollection newPermissionCollection() {
+		return new WirePermissionCollection();
+	}
+
+	/**
+	 * Determines the equalty of two <code>WirePermission</code> objects.
+	 * 
+	 * Checks that specified object has the same name and actions as this
+	 * <code>WirePermission</code> object.
+	 * 
+	 * @param obj The object to test for equality.
+	 * @return true if <code>obj</code> is a <code>WirePermission</code>, and has
+	 *         the same name and actions as this <code>WirePermission</code>
+	 *         object; <code>false</code> otherwise.
+	 */
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+		if (!(obj instanceof WirePermission)) {
+			return false;
+		}
+		WirePermission p = (WirePermission) obj;
+		return (action_mask == p.action_mask) && getName().equals(p.getName());
+	}
+
+	/**
+	 * Returns the hash code value for this object.
+	 * 
+	 * @return Hash code value for this object.
+	 */
+	public int hashCode() {
+		return getName().hashCode() ^ getActions().hashCode();
+	}
+
+	/**
+	 * Returns the current action mask. Used by the WirePermissionCollection
+	 * object.
+	 * 
+	 * @return The actions mask.
+	 */
+	int getMask() {
+		return action_mask;
+	}
+
+	/**
+	 * Returns a string describing this <code>WirePermission</code>. The
+	 * convention is to specify the class name, the permission name, and the
+	 * actions in the following format:
+	 * '(org.osgi.service.wireadmin.WirePermission &quot;name&quot;
+	 * &quot;actions&quot;)'.
+	 * 
+	 * @return information about this <code>Permission</code> object.
+	 */
+	public String toString() {
+		StringBuffer sb = new StringBuffer();
+		sb.append('(');
+		sb.append(getClass().getName());
+		sb.append(" \"");
+		sb.append(getName());
+		sb.append("\" \"");
+		sb.append(getActions());
+		sb.append("\")");
+		return sb.toString();
+	}
+
+	/**
+	 * WriteObject is called to save the state of the ServicePermission to a
+	 * stream. The actions are serialized, and the superclass takes care of the
+	 * name.
+	 */
+	private synchronized void writeObject(java.io.ObjectOutputStream s)
+			throws IOException {
+		// Write out the actions. The superclass takes care of the name
+		// call getActions to make sure actions field is initialized
+		if (actions == null)
+			getActions();
+		s.defaultWriteObject();
+	}
+
+	/**
+	 * readObject is called to restore the state of the ServicePermission from a
+	 * stream.
+	 */
+	private synchronized void readObject(java.io.ObjectInputStream s)
+			throws IOException, ClassNotFoundException {
+		// Read in the action, then initialize the rest
+		s.defaultReadObject();
+		init(getMask(actions));
+	}
+}
+/**
+ * A <code>WirePermissionCollection</code> stores a set of <code>WirePermission</code>
+ * permissions.
+ */
+
+final class WirePermissionCollection extends PermissionCollection {
+    static final long serialVersionUID = 2617521094909826016L;
+	/**
+	 * Table of permissions.
+	 * 
+	 * @serial
+	 */
+	private Hashtable	permissions;
+	/**
+	 * Boolean saying if "*" is in the collection.
+	 * 
+	 * @serial
+	 */
+	private boolean		all_allowed;
+
+	/**
+	 * Creates an empty WirePermissionCollection object.
+	 *  
+	 */
+	public WirePermissionCollection() {
+		permissions = new Hashtable();
+		all_allowed = false;
+	}
+
+	/**
+	 * Adds a permission to this PermissionCollection.
+	 * 
+	 * @param permission The Permission object to add.
+	 * 
+	 * @throws IllegalArgumentException If the permission is not a
+	 *            WirePermission object.
+	 * 
+	 * @throws SecurityException If this PermissionCollection has been marked
+	 *            read-only.
+	 */
+	public void add(Permission permission) {
+		if (!(permission instanceof WirePermission))
+			throw new IllegalArgumentException("invalid permission: "
+					+ permission);
+		if (isReadOnly())
+			throw new SecurityException("attempt to add a Permission to a "
+					+ "readonly PermissionCollection");
+		WirePermission p = (WirePermission) permission;
+		String name = p.getName();
+		WirePermission existing = (WirePermission) permissions.get(name);
+		if (existing != null) {
+			int oldMask = existing.getMask();
+			int newMask = p.getMask();
+			if (oldMask != newMask) {
+				permissions.put(name, new WirePermission(name, oldMask
+						| newMask));
+			}
+		}
+		else {
+			permissions.put(name, permission);
+		}
+		if (!all_allowed) {
+			if (name.equals("*"))
+				all_allowed = true;
+		}
+	}
+
+	/**
+	 * Determines if a set of permissions implies the permissions expressed in
+	 * <code>permission</code>.
+	 * 
+	 * @param permission The Permission object to compare.
+	 * 
+	 * @return <code>true</code> if <code>permission</code> is a proper subset of a
+	 *         permission in the set; <code>false</code> otherwise.
+	 */
+	public boolean implies(Permission permission) {
+		if (!(permission instanceof WirePermission))
+			return false;
+		WirePermission p = (WirePermission) permission;
+		WirePermission x;
+		int desired = p.getMask();
+		int effective = 0;
+		// short circuit if the "*" Permission was added
+		if (all_allowed) {
+			x = (WirePermission) permissions.get("*");
+			if (x != null) {
+				effective |= x.getMask();
+				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 = p.getName();
+		x = (WirePermission) 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 = (WirePermission) 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;
+	}
+
+	/**
+	 * Returns an enumeration of all the Permission objects in the container.
+	 * 
+	 * @return Enumeration of all the Permission objects.
+	 */
+	public Enumeration elements() {
+		return permissions.elements();
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/package.html b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/package.html
new file mode 100644
index 0000000..083087c
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/package.html
@@ -0,0 +1,11 @@
+<!-- $Header: /cvshome/build/org.osgi.service.wireadmin/src/org/osgi/service/wireadmin/package.html,v 1.2 2004/12/01 19:01:21 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Wire Admin service Package. Specification 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.wireadmin; version=1.0
+</pre>
+</BODY>
+
diff --git a/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/service/wireadmin/packageinfo
@@ -0,0 +1 @@
+version 1.0
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Measurement.java b/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Measurement.java
new file mode 100644
index 0000000..5870fdf
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Measurement.java
@@ -0,0 +1,480 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/Measurement.java,v 1.12 2006/03/14 01:19:37 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.osgi.util.measurement;
+
+
+/**
+ * Represents a value with an error, a unit and a time-stamp.
+ * 
+ * <p>
+ * A <code>Measurement</code> object is used for maintaining the tuple of value,
+ * error, unit and time-stamp. The value and error are represented as doubles
+ * and the time is measured in milliseconds since midnight, January 1, 1970 UTC.
+ * 
+ * <p>
+ * Mathematic methods are provided that correctly calculate taking the error
+ * into account. A runtime error will occur when two measurements are used in an
+ * incompatible way. E.g., when a speed (m/s) is added to a distance (m). The
+ * measurement class will correctly track changes in unit during multiplication
+ * and division, always coercing the result to the most simple form. See
+ * {@link Unit}for more information on the supported units.
+ * 
+ * <p>
+ * Errors in the measurement class are absolute errors. Measurement errors
+ * should use the P95 rule. Actual values must fall in the range value +/- error
+ * 95% or more of the time.
+ * 
+ * <p>
+ * A <code>Measurement</code> object is immutable in order to be easily shared.
+ * 
+ * <p>
+ * Note: This class has a natural ordering that is inconsistent with equals. See
+ * {@link #compareTo}.
+ * 
+ * @version $Revision: 1.12 $
+ */
+public class Measurement implements Comparable {
+	/* package private so it can be accessed by Unit */
+	final double	value;
+	final double	error;
+	final long		time;
+	final Unit		unit;
+	private transient String	name;
+
+	/**
+	 * Create a new <code>Measurement</code> object.
+	 * 
+	 * @param value The value of the <code>Measurement</code>.
+	 * @param error The error of the <code>Measurement</code>.
+	 * @param unit The <code>Unit</code> object in which the value is measured. If
+	 *        this argument is <code>null</code>, then the unit will be set to
+	 *        {@link Unit#unity}.
+	 * @param time The time measured in milliseconds since midnight, January 1,
+	 *        1970 UTC.
+	 */
+	public Measurement(double value, double error, Unit unit, long time) {
+		this.value = value;
+		this.error = Math.abs(error);
+		this.unit = (unit != null) ? unit : Unit.unity;
+		this.time = time;
+	}
+
+	/**
+	 * Create a new <code>Measurement</code> object with a time of zero.
+	 * 
+	 * @param value The value of the <code>Measurement</code>.
+	 * @param error The error of the <code>Measurement</code>.
+	 * @param unit The <code>Unit</code> object in which the value is measured. If
+	 *        this argument is <code>null</code>, then the unit will be set to
+	 *        {@link Unit#unity}.
+	 */
+	public Measurement(double value, double error, Unit unit) {
+		this(value, error, unit, 0l);
+	}
+
+	/**
+	 * Create a new <code>Measurement</code> object with an error of 0.0 and a
+	 * time of zero.
+	 * 
+	 * @param value The value of the <code>Measurement</code>.
+	 * @param unit The <code>Unit</code> in which the value is measured. If this
+	 *        argument is <code>null</code>, then the unit will be set to
+	 *        {@link Unit#unity}.
+	 */
+	public Measurement(double value, Unit unit) {
+		this(value, 0.0d, unit, 0l);
+	}
+
+	/**
+	 * Create a new <code>Measurement</code> object with an error of 0.0, a unit
+	 * of {@link Unit#unity}and a time of zero.
+	 * 
+	 * @param value The value of the <code>Measurement</code>.
+	 */
+	public Measurement(double value) {
+		this(value, 0.0d, null, 0l);
+	}
+
+	/**
+	 * Returns the value of this <code>Measurement</code> object.
+	 * 
+	 * @return The value of this <code>Measurement</code> object as a double.
+	 */
+	public final double getValue() {
+		return value;
+	}
+
+	/**
+	 * Returns the error of this <code>Measurement</code> object. The error is
+	 * always a positive value.
+	 * 
+	 * @return The error of this <code>Measurement</code> as a double.
+	 */
+	public final double getError() {
+		return error;
+	}
+
+	/**
+	 * Returns the <code>Unit</code> object of this <code>Measurement</code> object.
+	 * 
+	 * @return The <code>Unit</code> object of this <code>Measurement</code> object.
+	 * 
+	 * @see Unit
+	 */
+	public final Unit getUnit() {
+		return unit;
+	}
+
+	/**
+	 * Returns the time at which this <code>Measurement</code> object was taken.
+	 * The time is measured in milliseconds since midnight, January 1, 1970 UTC,
+	 * or zero when not defined.
+	 * 
+	 * @return The time at which this <code>Measurement</code> object was taken or
+	 *         zero.
+	 */
+	public final long getTime() {
+		return time;
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the product of this
+	 * object multiplied by the specified object.
+	 * 
+	 * @param m The <code>Measurement</code> object that will be multiplied with
+	 *        this object.
+	 * @return A new <code>Measurement</code> that is the product of this object
+	 *         multiplied by the specified object. The error and unit of the new
+	 *         object are computed. The time of the new object is set to the
+	 *         time of this object.
+	 * @throws ArithmeticException If the <code>Unit</code> objects of this object
+	 *         and the specified object cannot be multiplied.
+	 * @see Unit
+	 */
+	public Measurement mul(Measurement m) {
+		double mvalue = m.value;
+		return new Measurement(value * mvalue, Math.abs(value) * m.error
+				+ error * Math.abs(mvalue), unit.mul(m.unit), time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the product of this
+	 * object multiplied by the specified value.
+	 * 
+	 * @param d The value that will be multiplied with this object.
+	 * @param u The <code>Unit</code> of the specified value.
+	 * @return A new <code>Measurement</code> object that is the product of this
+	 *         object multiplied by the specified value. The error and unit of
+	 *         the new object are computed. The time of the new object is set to
+	 *         the time of this object.
+	 * @throws ArithmeticException If the units of this object and the specified
+	 *         value cannot be multiplied.
+	 * @see Unit
+	 */
+	public Measurement mul(double d, Unit u) {
+		return new Measurement(value * d, error * Math.abs(d), unit.mul(u),
+				time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the product of this
+	 * object multiplied by the specified value.
+	 * 
+	 * @param d The value that will be multiplied with this object.
+	 * @return A new <code>Measurement</code> object that is the product of this
+	 *         object multiplied by the specified value. The error of the new
+	 *         object is computed. The unit and time of the new object is set to
+	 *         the unit and time of this object.
+	 */
+	public Measurement mul(double d) {
+		return new Measurement(value * d, error * Math.abs(d), unit, time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the quotient of this
+	 * object divided by the specified object.
+	 * 
+	 * @param m The <code>Measurement</code> object that will be the divisor of
+	 *        this object.
+	 * @return A new <code>Measurement</code> object that is the quotient of this
+	 *         object divided by the specified object. The error and unit of the
+	 *         new object are computed. The time of the new object is set to the
+	 *         time of this object.
+	 * @throws ArithmeticException If the <code>Unit</code> objects of this object
+	 *         and the specified object cannot be divided.
+	 * @see Unit
+	 */
+	public Measurement div(Measurement m) {
+		double mvalue = m.value;
+		return new Measurement(value / mvalue,
+				(Math.abs(value) * m.error + error * Math.abs(mvalue))
+						/ (mvalue * mvalue), unit.div(m.unit), time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the quotient of this
+	 * object divided by the specified value.
+	 * 
+	 * @param d The value that will be the divisor of this object.
+	 * @param u The <code>Unit</code> object of the specified value.
+	 * @return A new <code>Measurement</code> that is the quotient of this object
+	 *         divided by the specified value. The error and unit of the new
+	 *         object are computed. The time of the new object is set to the
+	 *         time of this object.
+	 * @throws ArithmeticException If the <code>Unit</code> objects of this object
+	 *         and the specified object cannot be divided.
+	 * @see Unit
+	 */
+	public Measurement div(double d, Unit u) {
+		return new Measurement(value / d, error / Math.abs(d), unit.div(u),
+				time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the quotient of this
+	 * object divided by the specified value.
+	 * 
+	 * @param d The value that will be the divisor of this object.
+	 * @return A new <code>Measurement</code> object that is the quotient of this
+	 *         object divided by the specified value. The error of the new
+	 *         object is computed. The unit and time of the new object is set to
+	 *         the <code>Unit</code> and time of this object.
+	 */
+	public Measurement div(double d) {
+		return new Measurement(value / d, error / Math.abs(d), unit, time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the sum of this
+	 * object added to the specified object.
+	 * 
+	 * The error and unit of the new object are computed. The time of the new
+	 * object is set to the time of this object.
+	 * 
+	 * @param m The <code>Measurement</code> object that will be added with this
+	 *        object.
+	 * @return A new <code>Measurement</code> object that is the sum of this and
+	 *         m.
+	 * @see Unit
+	 * @throws ArithmeticException If the <code>Unit</code> objects of this object
+	 *         and the specified object cannot be added.
+	 */
+	public Measurement add(Measurement m) {
+		return new Measurement(value + m.value, error + m.error, unit
+				.add(m.unit), time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the sum of this
+	 * object added to the specified value.
+	 * 
+	 * @param d The value that will be added with this object.
+	 * @param u The <code>Unit</code> object of the specified value.
+	 * @return A new <code>Measurement</code> object that is the sum of this
+	 *         object added to the specified value. The unit of the new object
+	 *         is computed. The error and time of the new object is set to the
+	 *         error and time of this object.
+	 * @throws ArithmeticException If the <code>Unit</code> objects of this object
+	 *         and the specified value cannot be added.
+	 * @see Unit
+	 */
+	public Measurement add(double d, Unit u) {
+		return new Measurement(value + d, error, unit.add(u), time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the sum of this
+	 * object added to the specified value.
+	 * 
+	 * @param d The value that will be added with this object.
+	 * @return A new <code>Measurement</code> object that is the sum of this
+	 *         object added to the specified value. The error, unit, and time of
+	 *         the new object is set to the error, <code>Unit</code> and time of
+	 *         this object.
+	 */
+	public Measurement add(double d) {
+		return new Measurement(value + d, error, unit, time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the subtraction of
+	 * the specified object from this object.
+	 * 
+	 * @param m The <code>Measurement</code> object that will be subtracted from
+	 *        this object.
+	 * @return A new <code>Measurement</code> object that is the subtraction of
+	 *         the specified object from this object. The error and unit of the
+	 *         new object are computed. The time of the new object is set to the
+	 *         time of this object.
+	 * @throws ArithmeticException If the <code>Unit</code> objects of this object
+	 *         and the specified object cannot be subtracted.
+	 * @see Unit
+	 */
+	public Measurement sub(Measurement m) {
+		return new Measurement(value - m.value, error + m.error, unit
+				.sub(m.unit), time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the subtraction of
+	 * the specified value from this object.
+	 * 
+	 * @param d The value that will be subtracted from this object.
+	 * @param u The <code>Unit</code> object of the specified value.
+	 * @return A new <code>Measurement</code> object that is the subtraction of
+	 *         the specified value from this object. The unit of the new object
+	 *         is computed. The error and time of the new object is set to the
+	 *         error and time of this object.
+	 * @throws ArithmeticException If the <code>Unit</code> objects of this object
+	 *         and the specified object cannot be subtracted.
+	 * @see Unit
+	 */
+	public Measurement sub(double d, Unit u) {
+		return new Measurement(value - d, error, unit.sub(u), time);
+	}
+
+	/**
+	 * Returns a new <code>Measurement</code> object that is the subtraction of
+	 * the specified value from this object.
+	 * 
+	 * @param d The value that will be subtracted from this object.
+	 * @return A new <code>Measurement</code> object that is the subtraction of
+	 *         the specified value from this object. The error, unit and time of
+	 *         the new object is set to the error, <code>Unit</code> object and
+	 *         time of this object.
+	 */
+	public Measurement sub(double d) {
+		return new Measurement(value - d, error, unit, time);
+	}
+
+	/**
+	 * Returns a <code>String</code> object representing this <code>Measurement</code>
+	 * object.
+	 * 
+	 * @return a <code>String</code> object representing this <code>Measurement</code>
+	 *         object.
+	 */
+	public String toString() {
+		if (name == null) {
+			StringBuffer sb = new StringBuffer();
+			sb.append(value);
+			if (error != 0.0d) {
+				sb.append(" +/- ");
+				sb.append(error);
+			}
+			String u = unit.toString();
+			if (u.length() > 0) {
+				sb.append(" ");
+				sb.append(u);
+			}
+			name = sb.toString();
+		}
+		return name;
+	}
+
+	/**
+	 * Compares this object with the specified object for order. Returns a
+	 * negative integer, zero, or a positive integer if this object is less
+	 * than, equal to, or greater than the specified object.
+	 * 
+	 * <p>
+	 * Note: This class has a natural ordering that is inconsistent with equals.
+	 * For this method, another <code>Measurement</code> object is considered
+	 * equal if there is some <code>x</code> such that
+	 * 
+	 * <pre>
+	 * getValue() - getError() &lt;= x &lt;= getValue() + getError()
+	 * </pre>
+	 * 
+	 * for both <code>Measurement</code> objects being compared.
+	 * 
+	 * @param obj The object to be compared.
+	 * @return A negative integer, zero, or a positive integer if this object is
+	 *         less than, equal to, or greater than the specified object.
+	 * 
+	 * @throws ClassCastException If the specified object is not of type
+	 *         <code>Measurement</code>.
+	 * @throws ArithmeticException If the unit of the specified
+	 *         <code>Measurement</code> object is not equal to the <code>Unit</code>
+	 *         object of this object.
+	 */
+	public int compareTo(Object obj) {
+		if (this == obj) {
+			return 0;
+		}
+		Measurement that = (Measurement) obj;
+		if (!unit.equals(that.unit)) {
+			throw new ArithmeticException("Cannot compare " + this + " and "
+					+ that);
+		}
+		if (value == that.value) {
+			return 0;
+		}
+		if (value < that.value) {
+			if ((value + error) >= (that.value - that.error)) {
+				return 0;
+			}
+			else {
+				return -1;
+			}
+		}
+		else {
+			if ((value - error) <= (that.value + that.error)) {
+				return 0;
+			}
+			else {
+				return 1;
+			}
+		}
+	}
+
+	/**
+	 * Returns a hash code value for this object.
+	 * 
+	 * @return A hash code value for this object.
+	 */
+	public int hashCode() {
+		long bits = Double.doubleToLongBits(value + error);
+		return ((int) (bits ^ (bits >>> 32))) ^ unit.hashCode();
+	}
+
+	/**
+	 * Returns whether the specified object is equal to this object. Two
+	 * <code>Measurement</code> objects are equal if they have same value, error
+	 * and <code>Unit</code>.
+	 * 
+	 * <p>
+	 * Note: This class has a natural ordering that is inconsistent with equals.
+	 * See {@link #compareTo}.
+	 * 
+	 * @param obj The object to compare with this object.
+	 * @return <code>true</code> if this object is equal to the specified object;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean equals(Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (!(obj instanceof Measurement)) {
+			return false;
+		}
+		Measurement that = (Measurement) obj;
+		return (value == that.value) && (error == that.error)
+				&& unit.equals(that.unit);
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java b/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java
new file mode 100644
index 0000000..df8385d
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java
@@ -0,0 +1,145 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/State.java,v 1.7 2006/03/14 01:19:37 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.osgi.util.measurement;
+
+/**
+ * Groups a state name, value and timestamp.
+ * 
+ * <p>
+ * The state itself is represented as an integer and the time is measured in
+ * milliseconds since midnight, January 1, 1970 UTC.
+ * 
+ * <p>
+ * A <code>State</code> object is immutable so that it may be easily shared.
+ * 
+ * @version $Revision: 1.7 $
+ */
+public class State {
+	final int		value;
+	final long		time;
+	final String	name;
+
+	/**
+	 * Create a new <code>State</code> object.
+	 * 
+	 * @param value The value of the state.
+	 * @param name The name of the state.
+	 * @param time The time measured in milliseconds since midnight, January 1,
+	 *        1970 UTC.
+	 */
+	public State(int value, String name, long time) {
+		this.value = value;
+		this.name = name;
+		this.time = time;
+	}
+
+	/**
+	 * Create a new <code>State</code> object with a time of 0.
+	 * 
+	 * @param value The value of the state.
+	 * @param name The name of the state.
+	 */
+	public State(int value, String name) {
+		this(value, name, 0);
+	}
+
+	/**
+	 * Returns the value of this <code>State</code>.
+	 * 
+	 * @return The value of this <code>State</code> object.
+	 */
+	public final int getValue() {
+		return value;
+	}
+
+	/**
+	 * Returns the time with which this <code>State</code> was created.
+	 * 
+	 * @return The time with which this <code>State</code> was created. The time
+	 *         is measured in milliseconds since midnight, January 1, 1970 UTC.
+	 */
+	public final long getTime() {
+		return time;
+	}
+
+	/**
+	 * Returns the name of this <code>State</code>.
+	 * 
+	 * @return The name of this <code>State</code> object.
+	 */
+	public final String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns a <code>String</code> object representing this object.
+	 * 
+	 * @return a <code>String</code> object representing this object.
+	 */
+	public String toString() {
+		StringBuffer sb = new StringBuffer();
+		sb.append(value);
+		if (name != null) {
+			sb.append(" \"");
+			sb.append(name);
+			sb.append("\"");
+		}
+		return (sb.toString());
+	}
+
+	/**
+	 * Returns a hash code value for this object.
+	 * 
+	 * @return A hash code value for this object.
+	 */
+	public int hashCode() {
+		int hash = value;
+		if (name != null) {
+			hash ^= name.hashCode();
+		}
+		return hash;
+	}
+
+	/**
+	 * Return whether the specified object is equal to this object. Two
+	 * <code>State</code> objects are equal if they have same value and name.
+	 * 
+	 * @param obj The object to compare with this object.
+	 * @return <code>true</code> if this object is equal to the specified object;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean equals(Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (!(obj instanceof State)) {
+			return false;
+		}
+		State that = (State) obj;
+		if (value != that.value) {
+			return false;
+		}
+		if (name == that.name) {
+			return true;
+		}
+		if (name == null) {
+			return false;
+		}
+		return name.equals(that.name);
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java b/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java
new file mode 100644
index 0000000..b744e21
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java
@@ -0,0 +1,525 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/Unit.java,v 1.14 2006/03/14 01:19:37 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.osgi.util.measurement;
+
+import java.util.Hashtable;
+
+/**
+ * A unit system for measurements.
+ * 
+ * This class contains definitions of the most common SI units.
+ * <p>
+ * 
+ * <p>
+ * This class only support exponents for the base SI units in the range -64 to
+ * +63. Any operation which produces an exponent outside of this range will
+ * result in a <code>Unit</code> object with undefined exponents.
+ * 
+ * @version $Revision: 1.14 $
+ */
+/*
+ * This local class maintains the information about units. It can calculate new
+ * units when two values are multiplied, divided, added or subtracted. <p> The
+ * unit works with the 7 basic SI types + rad + up to 2^6 custom types. For each
+ * type, the unit keeps a bit mask with the exponents of the basic types. Eg.
+ * m/s is m = 1, s = -1. Multiplying one unit with another means that the bit
+ * masks are added, dividing means that the bit masks are subtracted. <p> This
+ * class can handle any reasonable combination of SI units. However, it will
+ * always try to coerce results back into the basic set. E.g. when you do V*A
+ * you should get W and not m2.kg/s3 . Only when the existing types do not match
+ * does the unit fallback to the expanded form. <p> This class uses offset
+ * arithmetic. This means that the exponents are stored in an long. The special
+ * field is used for units that should not be arithmetically divided or
+ * multiplied, like longitude and lattitude. These special units can however, be
+ * divided and multiplied by the basic 7 constants of the SI, e.g. deg/s.
+ */
+public class Unit {
+	private final static long	UNITY		= createType(0, 0, 0, 0, 0, 0, 0,
+													0, 0);
+	private final static long	ZERO		= 0x40L;
+	private final static long	MASK		= 0x7fL;
+	private final static int	m_SHIFT		= 0;
+	private final static int	s_SHIFT		= 7;
+	private final static int	kg_SHIFT	= 14;
+	private final static int	K_SHIFT		= 21;
+	private final static int	A_SHIFT		= 28;
+	private final static int	mol_SHIFT	= 35;
+	private final static int	cd_SHIFT	= 42;
+	private final static int	rad_SHIFT	= 49;
+	private final static int	x_SHIFT		= 56;
+	private final static long	x_MASK		= MASK << x_SHIFT;
+	/** No Unit (Unity) */
+	public final static Unit	unity		= new Unit("", UNITY);					// Unity
+	/* SI Base Units */
+	/** The length unit meter (m) */
+	public final static Unit	m			= new Unit("m", createType(0, 0, 0,
+													0, 0, 0, 0, 0, 1));			// Distance
+	// meter
+	/** The time unit second (s) */
+	public final static Unit	s			= new Unit("s", createType(0, 0, 0,
+													0, 0, 0, 0, 1, 0));			// Time
+	// Seconds
+	// s
+	/** The mass unit kilogram (kg) */
+	public final static Unit	kg			= new Unit("kg", createType(0, 0,
+													0, 0, 0, 0, 1, 0, 0));			// Mass
+	// kilogram
+	// kg
+	/** The temperature unit kelvin (K) */
+	public final static Unit	K			= new Unit("K", createType(0, 0, 0,
+													0, 0, 1, 0, 0, 0));			// Temperature
+	// kelvin
+	// K
+	/** The electric current unit ampere (A) */
+	public final static Unit	A			= new Unit("A", createType(0, 0, 0,
+													0, 1, 0, 0, 0, 0));			// Current
+	// ampere
+	// A
+	/** The amount of substance unit mole (mol) */
+	public final static Unit	mol			= new Unit("mol", createType(0, 0,
+													0, 1, 0, 0, 0, 0, 0));			// Substance
+	// mole
+	// mol
+	/** The luminous intensity unit candela (cd) */
+	public final static Unit	cd			= new Unit("cd", createType(0, 0,
+													1, 0, 0, 0, 0, 0, 0));			// Light
+	// candela
+	// cd
+	/* SI Derived Units */
+	/** The speed unit meter per second (m/s) */
+	public final static Unit	m_s			= new Unit("m/s", createType(0, 0,
+													0, 0, 0, 0, 0, -1, 1));		// Speed
+	// m/s
+	/** The acceleration unit meter per second squared (m/s <sup>2 </sup>) */
+	public final static Unit	m_s2		= new Unit("m/s2", createType(0, 0,
+													0, 0, 0, 0, 0, -2, 1));		// Acceleration
+	// m/s^2
+	/** The area unit square meter(m <sup>2 </sup>) */
+	public final static Unit	m2			= new Unit("m2", createType(0, 0,
+													0, 0, 0, 0, 0, 0, 2));			// Surface
+	// m^2
+	/** The volume unit cubic meter (m <sup>3 </sup>) */
+	public final static Unit	m3			= new Unit("m3", createType(0, 0,
+													0, 0, 0, 0, 0, 0, 3));			// Volume
+	// m^3
+	/**
+	 * The frequency unit hertz (Hz).
+	 * <p>
+	 * hertz is expressed in SI units as 1/s
+	 */
+	public final static Unit	Hz			= new Unit("Hz", createType(0, 0,
+													0, 0, 0, 0, 0, -1, 0));		// Frequency
+	// 1/s
+	/**
+	 * The force unit newton (N).
+	 * <p>
+	 * N is expressed in SI units as m&#183;kg/s <sup>2 </sup>
+	 */
+	public final static Unit	N			= new Unit("N", createType(0, 0, 0,
+													0, 0, 0, 1, -2, 1));			// Force
+	// newton
+	// (m*kg)/s^2
+	/**
+	 * The pressure unit pascal (Pa).
+	 * <p>
+	 * Pa is equal to N/m <sup>2 </sup> or is expressed in SI units as
+	 * kg/m&#183;s <sup>2 </sup>
+	 */
+	public final static Unit	Pa			= new Unit("Pa", createType(0, 0,
+													0, 0, 0, 0, 1, -2, -1));		// Pressure
+	// pascal
+	// kg/(m*s^2)
+	/**
+	 * The energy unit joule (J).
+	 * <p>
+	 * joule is equal to N&#183;m or is expressed in SI units as m <sup>2
+	 * </sup>&#183;kg/s <sup>2
+	 */
+	public final static Unit	J			= new Unit("J", createType(0, 0, 0,
+													0, 0, 0, 1, -2, 2));			// Energy
+	// joule
+	// (m^2*kg)/s^2
+	/**
+	 * The power unit watt (W).
+	 * <p>
+	 * watt is equal to J/s or is expressed in SI units as m <sup>2
+	 * </sup>&#183;kg/s <sup>3 </sup>
+	 */
+	public final static Unit	W			= new Unit("W", createType(0, 0, 0,
+													0, 0, 0, 1, -3, 2));			// Power
+	// watt
+	// (m^2*kg)/s^3
+	/**
+	 * The electric charge unit coulomb (C).
+	 * <p>
+	 * coulomb is expressed in SI units as s&#183;A
+	 */
+	public final static Unit	C			= new Unit("C", createType(0, 0, 0,
+													0, 1, 0, 0, 1, 0));			// Charge
+	// coulumb
+	// s*A
+	/**
+	 * The electric potential difference unit volt (V).
+	 * <p>
+	 * volt is equal to W/A or is expressed in SI units as m <sup>2
+	 * </sup>&#183;kg/s <sup>3 </sup>&#183;A
+	 */
+	public final static Unit	V			= new Unit("V", createType(0, 0, 0,
+													0, -1, 0, 1, -3, 2));			// El.
+	// Potent.
+	// volt
+	// (m^2*kg)/(s^3*A)
+	/**
+	 * The capacitance unit farad (F).
+	 * <p>
+	 * farad is equal to C/V or is expressed in SI units as s <sup>4
+	 * </sup>&#183;A <sup>2 </sup>/m <sup>2 </sup>&#183;kg
+	 */
+	public final static Unit	F			= new Unit("F", createType(0, 0, 0,
+													0, 2, 0, -1, 4, -2));			// Capacitance
+	// farad
+	// (s^4*A^2)/(m^2*kg)
+	/**
+	 * The electric resistance unit ohm.
+	 * <p>
+	 * ohm is equal to V/A or is expressed in SI units as m <sup>2
+	 * </sup>&#183;kg/s <sup>3 </sup>&#183;A <sup>2 </sup>
+	 */
+	public final static Unit	Ohm			= new Unit("Ohm", createType(0, 0,
+													0, 0, -2, 0, 1, -3, 2));		// Resistance
+	// ohm
+	// (m^2*kg)/(s^3*A^2)
+	/**
+	 * The electric conductance unit siemens (S).
+	 * <p>
+	 * siemens is equal to A/V or is expressed in SI units as s <sup>3
+	 * </sup>&#183;A <sup>2 </sup>/m <sup>2 </sup>&#183;kg
+	 */
+	public final static Unit	S			= new Unit("S", createType(0, 0, 0,
+													0, 2, 0, -1, 3, -2));			// Conductance
+	// siemens
+	// (s^3*A^2)/(m^2*kg)
+	/**
+	 * The magnetic flux unit weber (Wb).
+	 * <p>
+	 * weber is equal to V&#183;s or is expressed in SI units as m <sup>2
+	 * </sup>&#183;kg/s <sup>2 </sup>&#183;A
+	 */
+	public final static Unit	Wb			= new Unit("Wb", createType(0, 0,
+													0, 0, -1, 0, 1, -2, 2));		// Magn.
+	// Flux
+	// weber
+	// (m^2*kg)/(s^2*A)
+	/**
+	 * The magnetic flux density unit tesla (T).
+	 * <p>
+	 * tesla is equal to Wb/m <sup>2 </sup> or is expressed in SI units as kg/s
+	 * <sup>2 </sup>&#183;A
+	 */
+	public final static Unit	T			= new Unit("T", createType(0, 0, 0,
+													0, -1, 0, 1, -2, 0));			// Magn.
+	// Flux
+	// Dens.
+	// tesla
+	// kg/(s^2*A)
+	/**
+	 * The illuminance unit lux (lx).
+	 * <p>
+	 * lux is expressed in SI units as cd/m <sup>2 </sup>
+	 */
+	public final static Unit	lx			= new Unit("lx", createType(0, 0,
+													1, 0, 0, 0, 0, 0, -2));		// Illuminace
+	// lux
+	// cd/m^2
+	/**
+	 * The absorbed dose unit gray (Gy).
+	 * <p>
+	 * Gy is equal to J/kg or is expressed in SI units as m <sup>2 </sup>/s
+	 * <sup>2 </sup>
+	 */
+	public final static Unit	Gy			= new Unit("Gy", createType(0, 0,
+													0, 0, 0, 0, 0, -2, 2));		// Absorbed
+	// dose
+	// gray
+	// m^2/s^2
+	/**
+	 * The catalytic activity unit katal (kat).
+	 * <p>
+	 * katal is expressed in SI units as mol/s
+	 */
+	public final static Unit	kat			= new Unit("kat", createType(0, 0,
+													0, 1, 0, 0, 0, -1, 0));		// Catalytic
+	// Act.
+	// katal
+	// mol/s
+	/** The angle unit radians (rad) */
+	public final static Unit	rad			= new Unit("rad", createType(0, 1,
+													0, 0, 0, 0, 0, 0, 0));			// Angle
+	// radians
+	// rad
+	/**
+	 * An array containing all units defined. The first seven items must be m,
+	 * s, kg, K, A, mol, cd, rad in this order!
+	 */
+	private final static Unit[]	allUnits	= new Unit[] {m, s, kg, K, A, mol,
+			cd, rad, m_s, m_s2, m2, m3, Hz, N, Pa, J, W, C, V, F, Ohm, S, Wb,
+			T, lx, Gy, kat, unity			};
+	private static Hashtable	base;
+	private String				name;
+	private long				type;
+
+	/**
+	 * Creates a new <code>Unit</code> instance.
+	 * 
+	 * @param name the name of the <code>Unit</code>
+	 * @param type the type of the <code>Unit</code>
+	 */
+	private Unit(String name, long type) {
+		this.name = name;
+		this.type = type;
+		//System.out.println( name + " " + Long.toHexString( type ) );
+	}
+
+	/**
+	 * Create a type field from the base SI unit exponent values.
+	 *  
+	 */
+	private static long createType(int x, int rad, int cd, int mol, int A,
+			int K, int kg, int s, int m) {
+		return (((ZERO + m) & MASK) << m_SHIFT)
+				| (((ZERO + s) & MASK) << s_SHIFT)
+				| (((ZERO + kg) & MASK) << kg_SHIFT)
+				| (((ZERO + K) & MASK) << K_SHIFT)
+				| (((ZERO + A) & MASK) << A_SHIFT)
+				| (((ZERO + mol) & MASK) << mol_SHIFT)
+				| (((ZERO + cd) & MASK) << cd_SHIFT)
+				| (((ZERO + rad) & MASK) << rad_SHIFT)
+				| (((long) x) << x_SHIFT);
+	}
+
+	/**
+	 * Checks whether this <code>Unit</code> object is equal to the specified
+	 * <code>Unit</code> object. The <code>Unit</code> objects are considered equal
+	 * if their exponents are equal.
+	 * 
+	 * @param obj the <code>Unit</code> object that should be checked for equality
+	 * 
+	 * @return true if the specified <code>Unit</code> object is equal to this
+	 *         <code>Unit</code> object.
+	 */
+	public boolean equals(Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (!(obj instanceof Unit)) {
+			return false;
+		}
+		return ((Unit) obj).type == type;
+	}
+
+	/**
+	 * Returns the hash code for this object.
+	 * 
+	 * @return This object's hash code.
+	 */
+	public int hashCode() {
+		return (int) ((type >>> 32) ^ type);
+	}
+
+	/**
+	 * Returns a new <code>Unit</code> that is the multiplication of this
+	 * <code>Unit</code> and the <code>Unit</code> specified
+	 * 
+	 * @param that the <code>Unit</code> that will be multiplied with this
+	 *        <code>Unit</code>
+	 * 
+	 * @return a new <code>Unit</code> that is the multiplication of this
+	 *         <code>Unit</code> and the <code>Unit</code> specified
+	 * 
+	 * @throws RuntimeException if both <code>Unit</code> s are special
+	 * 
+	 * @see Unit#isSpecial
+	 */
+	Unit mul(Unit that) {
+		if (this.isSpecial() && that.isSpecial()) {
+			throw new ArithmeticException("Cannot multiply " + this + " with "
+					+ that);
+		}
+		return find(this.type - UNITY + that.type);
+	}
+
+	/**
+	 * Returns a new <code>Unit</code> that is the division of this <code>Unit</code>
+	 * and the <code>Unit</code> specified
+	 * 
+	 * @param that the <code>Unit</code> that this <code>Unit</code> will be divided
+	 *        with
+	 * @return a new <code>Unit</code> that is the division of this <code>Unit</code>
+	 *         and the <code>Unit</code> specified
+	 * 
+	 * @throws RuntimeException if both <code>Unit</code> s are special
+	 * 
+	 * @see Unit#isSpecial
+	 */
+	Unit div(Unit that) {
+		if (this.isSpecial() && that.isSpecial()) {
+			if (this.type == that.type) {
+				return Unit.unity;
+			}
+			throw new ArithmeticException("Cannot divide " + this + " by "
+					+ that);
+		}
+		return find(this.type - that.type + UNITY);
+	}
+
+	/**
+	 * Returns a new <code>Unit</code> that is the addition of this <code>Unit</code>
+	 * and the <code>Unit</code> specified.
+	 * 
+	 * @param that the <code>Unit</code> that should be added to this
+	 *        <code>Unit</code>
+	 * 
+	 * @return a new <code>Unit</code> that is the addition of this <code>Unit</code>
+	 *         and the <code>Unit</code> specified.
+	 * 
+	 * @throws RuntimeException if the two <code>Unit</code> s are not the same
+	 */
+	Unit add(Unit that) {
+		if (!this.equals(that)) {
+			throw new ArithmeticException("Cannot add " + this + " to " + that);
+		}
+		return this;
+	}
+
+	/**
+	 * Returns a new <code>Unit</code> that is the subtraction between this
+	 * <code>Unit</code> and the <code>Unit</code> specified.
+	 * 
+	 * @param that the <code>Unit</code> that will be subtracted from this
+	 *        <code>Unit</code>
+	 * @return a new <code>Unit</code> that is the subtraction between this
+	 *         <code>Unit</code> and the <code>Unit</code> specified.
+	 * 
+	 * @throws RuntimeException if the <code>Unit</code> specified is not the same
+	 *         as this <code>Unit</code>
+	 */
+	Unit sub(Unit that) {
+		if (!this.equals(that)) {
+			throw new ArithmeticException("Cannot subtract " + that + " from "
+					+ this);
+		}
+		return this;
+	}
+
+	/**
+	 * Finds a <code>Unit</code> based on a type. If the <code>Unit</code> is not
+	 * found, it will be created and added to the list of all units under a null
+	 * name.
+	 * 
+	 * @param type the type of the <code>Unit</code> to find
+	 * 
+	 * @return the <code>Unit</code>
+	 */
+	static Unit find(long type) {
+		if (base == null) {
+			synchronized (Unit.class) {
+				if (base == null) {
+					int size = allUnits.length;
+					base = new Hashtable(size << 1);
+					for (int i = 0; i < size; i++) {
+						base.put(allUnits[i], allUnits[i]);
+					}
+				}
+			}
+		}
+		Unit unit = new Unit(null, type);
+		Unit out = (Unit) base.get(unit);
+		if (out == null) {
+			base.put(unit, unit);
+			out = unit;
+		}
+		return out;
+	}
+
+	/**
+	 * Returns a <code>String</code> object representing the <code>Unit</code>
+	 * 
+	 * @return A <code>String</code> object representing the <code>Unit</code>
+	 */
+	public String toString() {
+		if (name == null) {
+			int m = (int) (((type >> m_SHIFT) & MASK) - ZERO);
+			int s = (int) (((type >> s_SHIFT) & MASK) - ZERO);
+			int kg = (int) (((type >> kg_SHIFT) & MASK) - ZERO);
+			int K = (int) (((type >> K_SHIFT) & MASK) - ZERO);
+			int A = (int) (((type >> A_SHIFT) & MASK) - ZERO);
+			int mol = (int) (((type >> mol_SHIFT) & MASK) - ZERO);
+			int cd = (int) (((type >> cd_SHIFT) & MASK) - ZERO);
+			int rad = (int) (((type >> rad_SHIFT) & MASK) - ZERO);
+			StringBuffer numerator = new StringBuffer();
+			StringBuffer denominator = new StringBuffer();
+			addSIname(m, "m", numerator, denominator);
+			addSIname(s, "s", numerator, denominator);
+			addSIname(kg, "kg", numerator, denominator);
+			addSIname(K, "K", numerator, denominator);
+			addSIname(A, "A", numerator, denominator);
+			addSIname(mol, "mol", numerator, denominator);
+			addSIname(cd, "cd", numerator, denominator);
+			addSIname(rad, "rad", numerator, denominator);
+			if (denominator.length() > 0) {
+				if (numerator.length() == 0) {
+					numerator.append("1");
+				}
+				numerator.append("/");
+				numerator.append((Object) denominator); /*
+														 * we use (Object) to
+														 * avoid using new 1.4
+														 * method
+														 * append(StringBuffer)
+														 */
+			}
+			name = numerator.toString();
+		}
+		return name;
+	}
+
+	private void addSIname(int si, String name, StringBuffer numerator,
+			StringBuffer denominator) {
+		if (si != 0) {
+			StringBuffer sb = (si > 0) ? numerator : denominator;
+			if (sb.length() > 0) {
+				sb.append("*");
+			}
+			sb.append(name);
+			int power = Math.abs(si);
+			if (power > 1) {
+				sb.append("^");
+				sb.append(power);
+			}
+		}
+	}
+
+	/**
+	 * Checks whether the unit has a special type, i.e. not a SI unit.
+	 * 
+	 * @return true if the type is special, otherwise false.
+	 */
+	private boolean isSpecial() {
+		return (type & x_MASK) != 0;
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html b/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html
new file mode 100644
index 0000000..b3b7f3f
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/package.html,v 1.4 2005/05/27 01:25:29 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Measurement Package. Specification 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.util.measurement; version=1.0
+</pre>
+</BODY>
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo
new file mode 100644
index 0000000..a4f1546
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo
@@ -0,0 +1 @@
+version 1.0
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java b/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java
new file mode 100644
index 0000000..1190cf5
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java
@@ -0,0 +1,236 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.position/src/org/osgi/util/position/Position.java,v 1.7 2006/03/14 01:20:44 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2002, 2005). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.osgi.util.position;
+
+import org.osgi.util.measurement.*;
+
+/**
+ * Position represents a geographic location, based on the WGS84 System (World
+ * Geodetic System 1984).
+ * <p>
+ * The <code>org.osgi.util.measurement.Measurement</code> class is used to
+ * represent the values that make up a position.
+ * <p>
+ * <p>
+ * A given position object may lack any of it's components, i.e. the altitude
+ * may not be known. Such missing values will be represented by null.
+ * <p>
+ * Position does not override the implementation of either equals() or
+ * hashCode() because it is not clear how missing values should be handled. It
+ * is up to the user of a position to determine how best to compare two position
+ * objects. A <code>Position</code> object is immutable.
+ */
+public class Position {
+	private Measurement	altitude;
+	private Measurement	longitude;
+	private Measurement	latitude;
+	private Measurement	speed;
+	private Measurement	track;
+
+	/**
+	 * Contructs a <code>Position</code> object with the given values.
+	 * 
+	 * @param lat a <code>Measurement</code> object specifying the latitude in
+	 *        radians, or null
+	 * @param lon a <code>Measurement</code> object specifying the longitude in
+	 *        radians, or null
+	 * @param alt a <code>Measurement</code> object specifying the altitude in
+	 *        meters, or null
+	 * @param speed a <code>Measurement</code> object specifying the speed in
+	 *        meters per second, or null
+	 * @param track a <code>Measurement</code> object specifying the track in
+	 *        radians, or null
+	 */
+	public Position(Measurement lat, Measurement lon, Measurement alt,
+			Measurement speed, Measurement track) {
+		if (lat != null) {
+			if (!Unit.rad.equals(lat.getUnit())) {
+				throw new IllegalArgumentException("Invalid Latitude");
+			}
+			this.latitude = lat;
+		}
+		if (lon != null) {
+			if (!Unit.rad.equals(lon.getUnit())) {
+				throw new IllegalArgumentException("Invalid Longitude");
+			}
+			this.longitude = lon;
+		}
+		normalizeLatLon();
+		if (alt != null) {
+			if (!Unit.m.equals(alt.getUnit())) {
+				throw new IllegalArgumentException("Invalid Altitude");
+			}
+			this.altitude = alt;
+		}
+		if (speed != null) {
+			if (!Unit.m_s.equals(speed.getUnit())) {
+				throw new IllegalArgumentException("Invalid Speed");
+			}
+			this.speed = speed;
+		}
+		if (track != null) {
+			if (!Unit.rad.equals(track.getUnit())) {
+				throw new IllegalArgumentException("Invalid Track");
+			}
+			this.track = normalizeTrack(track);
+		}
+	}
+
+	/**
+	 * Returns the altitude of this position in meters.
+	 * 
+	 * @return a <code>Measurement</code> object in <code>Unit.m</code> representing
+	 *         the altitude in meters above the ellipsoid <code>null</code> if the
+	 *         altitude is not known.
+	 */
+	public Measurement getAltitude() {
+		return altitude;
+	}
+
+	/**
+	 * Returns the longitude of this position in radians.
+	 * 
+	 * @return a <code>Measurement</code> object in <code>Unit.rad</code>
+	 *         representing the longitude, or <code>null</code> if the longitude
+	 *         is not known.
+	 */
+	public Measurement getLongitude() {
+		return longitude;
+	}
+
+	/**
+	 * Returns the latitude of this position in radians.
+	 * 
+	 * @return a <code>Measurement</code> object in <code>Unit.rad</code>
+	 *         representing the latitude, or <code>null</code> if the latitude is
+	 *         not known..
+	 */
+	public Measurement getLatitude() {
+		return latitude;
+	}
+
+	/**
+	 * Returns the ground speed of this position in meters per second.
+	 * 
+	 * @return a <code>Measurement</code> object in <code>Unit.m_s</code>
+	 *         representing the speed, or <code>null</code> if the speed is not
+	 *         known..
+	 */
+	public Measurement getSpeed() {
+		return speed;
+	}
+
+	/**
+	 * Returns the track of this position in radians as a compass heading. The
+	 * track is the extrapolation of previous previously measured positions to a
+	 * future position.
+	 * 
+	 * @return a <code>Measurement</code> object in <code>Unit.rad</code>
+	 *         representing the track, or <code>null</code> if the track is not
+	 *         known..
+	 */
+	public Measurement getTrack() {
+		return track;
+	}
+
+	private static final double	LON_RANGE	= Math.PI;
+	private static final double	LAT_RANGE	= Math.PI / 2.0D;
+
+	/**
+	 * Verify the longitude and latitude parameters so they fit the normal
+	 * coordinate system. A latitude is between -90 (south) and +90 (north). A A
+	 * longitude is between -180 (Western hemisphere) and +180 (eastern
+	 * hemisphere). This method first normalizes the latitude and longitude
+	 * between +/- 180. If the |latitude| > 90, then the longitude is added 180
+	 * and the latitude is normalized to fit +/-90. (Example are with degrees
+	 * though radians are used) <br>
+	 * No normalization takes place when either lon or lat is null.
+	 */
+	private void normalizeLatLon() {
+		if (longitude == null || latitude == null)
+			return;
+		double dlon = longitude.getValue();
+		double dlat = latitude.getValue();
+		if (dlon >= -LON_RANGE && dlon < LON_RANGE && dlat >= -LAT_RANGE
+				&& dlat <= LAT_RANGE)
+			return;
+		dlon = normalize(dlon, LON_RANGE);
+		dlat = normalize(dlat, LAT_RANGE * 2.0D); // First over 180 degree
+		// Check if we have to move to other side of the earth
+		if (dlat > LAT_RANGE || dlat < -LAT_RANGE) {
+			dlon = normalize(dlon - LON_RANGE, LON_RANGE);
+			dlat = normalize((LAT_RANGE * 2.0D) - dlat, LAT_RANGE);
+		}
+		longitude = new Measurement(dlon, longitude.getError(), longitude
+				.getUnit(), longitude.getTime());
+		latitude = new Measurement(dlat, latitude.getError(), latitude
+				.getUnit(), latitude.getTime());
+	}
+
+	/**
+	 * This function normalizes the a value according to a range. This is not
+	 * simple modulo (as I thought when I started), but requires some special
+	 * handling. For positive numbers we subtract 2*range from the number so
+	 * that end up between -/+ range. For negative numbers we add this value.
+	 * For example, if the value is 270 and the range is +/- 180. Then sign=1 so
+	 * the (int) factor becomes 270+180/360 = 1. This means that 270-360=-90 is
+	 * the result. (degrees are only used to make it easier to understand, this
+	 * function is agnostic for radians/degrees). The result will be in
+	 * [range,range&gt; The algorithm is not very fast, but it handling the
+	 * [&gt; ranges made it very messy using integer arithmetic, and this is
+	 * very readable. Note that it is highly unlikely that this method is called
+	 * in normal situations. Normally input values to position are already
+	 * normalized because they come from a GPS. And this is much more readable.
+	 * 
+	 * @param value The value that needs adjusting
+	 * @param range -range = < value < range
+	 */
+	private double normalize(double value, double range) {
+		double twiceRange = 2.0D * range;
+		while (value >= range) {
+			value -= twiceRange;
+		}
+		while (value < -range) {
+			value += twiceRange;
+		}
+		return value;
+	}
+
+	private static final double	TRACK_RANGE	= Math.PI * 2.0D;
+
+	/**
+	 * Normalize track to be a value such that: 0 <= value < +2PI. This
+	 * corresponds to 0 deg to +360 deg. 0 is North 0.5*PI is East PI is South
+	 * 1.5*PI is West
+	 * 
+	 * @param track Value to be normalized
+	 * @return Normalized value
+	 */
+	private Measurement normalizeTrack(Measurement track) {
+		double value = track.getValue();
+		if ((0.0D <= value) && (value < TRACK_RANGE)) {
+			return track; /* value is already normalized */
+		}
+		value %= TRACK_RANGE;
+		if (value < 0.0D) {
+			value += TRACK_RANGE;
+		}
+		return new Measurement(value, track.getError(), track.getUnit(), track
+				.getTime());
+	}
+}
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html b/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html
new file mode 100644
index 0000000..c73c3d4
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.util.position/src/org/osgi/util/position/package.html,v 1.2 2004/12/01 19:00:53 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Position Package. Specification 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.util.position; version=1.0
+</pre>
+</BODY>
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo
new file mode 100644
index 0000000..a4f1546
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo
@@ -0,0 +1 @@
+version 1.0
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTracker.java b/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTracker.java
new file mode 100644
index 0000000..8ded728
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTracker.java
@@ -0,0 +1,1139 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.tracker/src/org/osgi/util/tracker/ServiceTracker.java,v 1.18 2006/03/14 01:20:01 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2000, 2005). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.util.tracker;
+
+import java.util.*;
+
+import org.osgi.framework.*;
+
+/**
+ * The <code>ServiceTracker</code> class simplifies using services from the
+ * Framework's service registry.
+ * <p>
+ * A <code>ServiceTracker</code> object is constructed with search criteria
+ * and a <code>ServiceTrackerCustomizer</code> object. A
+ * <code>ServiceTracker</code> object can use the
+ * <code>ServiceTrackerCustomizer</code> object to customize the service
+ * objects to be tracked. The <code>ServiceTracker</code> object can then be
+ * opened to begin tracking all services in the Framework's service registry
+ * that match the specified search criteria. The <code>ServiceTracker</code>
+ * object correctly handles all of the details of listening to
+ * <code>ServiceEvent</code> objects and getting and ungetting services.
+ * <p>
+ * The <code>getServiceReferences</code> method can be called to get
+ * references to the services being tracked. The <code>getService</code> and
+ * <code>getServices</code> methods can be called to get the service objects
+ * for the tracked service.
+ * 
+ * @version $Revision: 1.18 $
+ */
+public class ServiceTracker implements ServiceTrackerCustomizer {
+	/* set this to true to compile in debug messages */
+	static final boolean				DEBUG			= false;
+	/**
+	 * Bundle context this <code>ServiceTracker</code> object is tracking
+	 * against.
+	 */
+	protected final BundleContext		context;
+	/**
+	 * Filter specifying search criteria for the services to track.
+	 * 
+	 * @since 1.1
+	 */
+	protected final Filter				filter;
+	/**
+	 * <code>ServiceTrackerCustomizer</code> object for this tracker.
+	 */
+	final ServiceTrackerCustomizer		customizer;
+	/**
+	 * Filter string for use when adding the ServiceListener. If this field is
+	 * set, then certain optimizations can be taken since we don't have a user
+	 * supplied filter.
+	 */
+	final String						listenerFilter;
+	/**
+	 * Class name to be tracked. If this field is set, then we are tracking by
+	 * class name.
+	 */
+	private final String				trackClass;
+	/**
+	 * Reference to be tracked. If this field is set, then we are tracking a
+	 * single ServiceReference.
+	 */
+	private final ServiceReference		trackReference;
+	/**
+	 * Tracked services: <code>ServiceReference</code> object -> customized
+	 * Object and <code>ServiceListener</code> object
+	 */
+	private Tracked						tracked;
+	/**
+	 * Modification count. This field is initialized to zero by open, set to -1
+	 * by close and incremented by modified.
+	 * 
+	 * This field is volatile since it is accessed by multiple threads.
+	 */
+	private volatile int				trackingCount	= -1;
+	/**
+	 * Cached ServiceReference for getServiceReference.
+	 * 
+	 * This field is volatile since it is accessed by multiple threads.
+	 */
+	private volatile ServiceReference	cachedReference;
+	/**
+	 * Cached service object for getService.
+	 * 
+	 * This field is volatile since it is accessed by multiple threads.
+	 */
+	private volatile Object				cachedService;
+
+	/**
+	 * Create a <code>ServiceTracker</code> object on the specified
+	 * <code>ServiceReference</code> object.
+	 * 
+	 * <p>
+	 * The service referenced by the specified <code>ServiceReference</code>
+	 * object will be tracked by this <code>ServiceTracker</code> object.
+	 * 
+	 * @param context <code>BundleContext</code> object against which the
+	 *        tracking is done.
+	 * @param reference <code>ServiceReference</code> object for the service
+	 *        to be tracked.
+	 * @param customizer The customizer object to call when services are added,
+	 *        modified, or removed in this <code>ServiceTracker</code> object.
+	 *        If customizer is <code>null</code>, then this
+	 *        <code>ServiceTracker</code> object will be used as the
+	 *        <code>ServiceTrackerCustomizer</code> object and the
+	 *        <code>ServiceTracker</code> object will call the
+	 *        <code>ServiceTrackerCustomizer</code> methods on itself.
+	 */
+	public ServiceTracker(BundleContext context, ServiceReference reference,
+			ServiceTrackerCustomizer customizer) {
+		this.context = context;
+		this.trackReference = reference;
+		this.trackClass = null;
+		this.customizer = (customizer == null) ? this : customizer;
+		this.listenerFilter = "(" + Constants.SERVICE_ID + "=" + reference.getProperty(Constants.SERVICE_ID).toString() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		try {
+			this.filter = context.createFilter(listenerFilter);
+		}
+		catch (InvalidSyntaxException e) { // we could only get this exception
+			// if the ServiceReference was
+			// invalid
+			throw new IllegalArgumentException(
+					"unexpected InvalidSyntaxException: " + e.getMessage()); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Create a <code>ServiceTracker</code> object on the specified class
+	 * name.
+	 * 
+	 * <p>
+	 * Services registered under the specified class name will be tracked by
+	 * this <code>ServiceTracker</code> object.
+	 * 
+	 * @param context <code>BundleContext</code> object against which the
+	 *        tracking is done.
+	 * @param clazz Class name of the services to be tracked.
+	 * @param customizer The customizer object to call when services are added,
+	 *        modified, or removed in this <code>ServiceTracker</code> object.
+	 *        If customizer is <code>null</code>, then this
+	 *        <code>ServiceTracker</code> object will be used as the
+	 *        <code>ServiceTrackerCustomizer</code> object and the
+	 *        <code>ServiceTracker</code> object will call the
+	 *        <code>ServiceTrackerCustomizer</code> methods on itself.
+	 */
+	public ServiceTracker(BundleContext context, String clazz,
+			ServiceTrackerCustomizer customizer) {
+		this.context = context;
+		this.trackReference = null;
+		this.trackClass = clazz;
+		this.customizer = (customizer == null) ? this : customizer;
+		this.listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz.toString() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		try {
+			this.filter = context.createFilter(listenerFilter);
+		}
+		catch (InvalidSyntaxException e) { // we could only get this exception
+			// if the clazz argument was
+			// malformed
+			throw new IllegalArgumentException(
+					"unexpected InvalidSyntaxException: " + e.getMessage()); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Create a <code>ServiceTracker</code> object on the specified
+	 * <code>Filter</code> object.
+	 * 
+	 * <p>
+	 * Services which match the specified <code>Filter</code> object will be
+	 * tracked by this <code>ServiceTracker</code> object.
+	 * 
+	 * @param context <code>BundleContext</code> object against which the
+	 *        tracking is done.
+	 * @param filter <code>Filter</code> object to select the services to be
+	 *        tracked.
+	 * @param customizer The customizer object to call when services are added,
+	 *        modified, or removed in this <code>ServiceTracker</code> object.
+	 *        If customizer is null, then this <code>ServiceTracker</code>
+	 *        object will be used as the <code>ServiceTrackerCustomizer</code>
+	 *        object and the <code>ServiceTracker</code> object will call the
+	 *        <code>ServiceTrackerCustomizer</code> methods on itself.
+	 * @since 1.1
+	 */
+	public ServiceTracker(BundleContext context, Filter filter,
+			ServiceTrackerCustomizer customizer) {
+		this.context = context;
+		this.trackReference = null;
+		this.trackClass = null;
+		this.listenerFilter = null;
+		this.filter = filter;
+		this.customizer = (customizer == null) ? this : customizer;
+		if ((context == null) || (filter == null)) { // we throw a NPE here
+			// to
+			// be consistent with the
+			// other constructors
+			throw new NullPointerException();
+		}
+	}
+
+	/**
+	 * Open this <code>ServiceTracker</code> object and begin tracking
+	 * services.
+	 * 
+	 * <p>
+	 * This method calls <code>open(false)</code>.
+	 * 
+	 * @throws java.lang.IllegalStateException if the <code>BundleContext</code>
+	 *         object with which this <code>ServiceTracker</code> object was
+	 *         created is no longer valid.
+	 * @see #open(boolean)
+	 */
+	public void open() {
+		open(false);
+	}
+
+	/**
+	 * Open this <code>ServiceTracker</code> object and begin tracking
+	 * services.
+	 * 
+	 * <p>
+	 * Services which match the search criteria specified when this
+	 * <code>ServiceTracker</code> object was created are now tracked by this
+	 * <code>ServiceTracker</code> object.
+	 * 
+	 * @param trackAllServices If <code>true</code>, then this
+	 *        <code>ServiceTracker</code> will track all matching services
+	 *        regardless of class loader accessibility. If <code>false</code>,
+	 *        then this <code>ServiceTracker</code> will only track matching
+	 *        services which are class loader accessibile to the bundle whose
+	 *        <code>BundleContext</code> is used by this
+	 *        <code>ServiceTracker</code>.
+	 * @throws java.lang.IllegalStateException if the <code>BundleContext</code>
+	 *         object with which this <code>ServiceTracker</code> object was
+	 *         created is no longer valid.
+	 * @since 1.3
+	 */
+	public synchronized void open(boolean trackAllServices) {
+		if (tracked != null) {
+			return;
+		}
+		if (DEBUG) {
+			System.out.println("ServiceTracker.open: " + filter); //$NON-NLS-1$
+		}
+		tracked = trackAllServices ? new AllTracked() : new Tracked();
+		trackingCount = 0;
+		synchronized (tracked) {
+			try {
+				context.addServiceListener(tracked, listenerFilter);
+				ServiceReference[] references;
+				if (listenerFilter == null) { // user supplied filter
+					references = getInitialReferences(trackAllServices, null,
+							filter.toString());
+				}
+				else { // constructor supplied filter
+					if (trackClass == null) {
+						references = new ServiceReference[] {trackReference};
+					}
+					else {
+						references = getInitialReferences(trackAllServices,
+								trackClass, null);
+					}
+				}
+
+				tracked.setInitialServices(references); // set tracked with
+				// the initial
+				// references
+			}
+			catch (InvalidSyntaxException e) {
+				throw new RuntimeException(
+						"unexpected InvalidSyntaxException: " + e.getMessage()); //$NON-NLS-1$
+			}
+		}
+		/* Call tracked outside of synchronized region */
+		tracked.trackInitialServices(); // process the initial references
+	}
+
+	/**
+	 * Returns the list of initial <code>ServiceReference</code> objects that
+	 * will be tracked by this <code>ServiceTracker</code> object.
+	 * 
+	 * @param trackAllServices If true, use getAllServiceReferences.
+	 * @param trackClass the class name with which the service was registered,
+	 *        or null for all services.
+	 * @param filterString the filter criteria or null for all services.
+	 * @return the list of initial <code>ServiceReference</code> objects.
+	 * @throws InvalidSyntaxException if the filter uses an invalid syntax.
+	 */
+	private ServiceReference[] getInitialReferences(boolean trackAllServices,
+			String trackClass, String filterString)
+			throws InvalidSyntaxException {
+		if (trackAllServices) {
+			return context.getAllServiceReferences(trackClass, filterString);
+		}
+		else {
+			return context.getServiceReferences(trackClass, filterString);
+		}
+	}
+
+	/**
+	 * Close this <code>ServiceTracker</code> object.
+	 * 
+	 * <p>
+	 * This method should be called when this <code>ServiceTracker</code>
+	 * object should end the tracking of services.
+	 */
+	public synchronized void close() {
+		if (tracked == null) {
+			return;
+		}
+		if (DEBUG) {
+			System.out.println("ServiceTracker.close: " + filter); //$NON-NLS-1$
+		}
+		tracked.close();
+		ServiceReference[] references = getServiceReferences();
+		Tracked outgoing = tracked;
+		tracked = null;
+		try {
+			context.removeServiceListener(outgoing);
+		}
+		catch (IllegalStateException e) {
+			/* In case the context was stopped. */
+		}
+		if (references != null) {
+			for (int i = 0; i < references.length; i++) {
+				outgoing.untrack(references[i]);
+			}
+		}
+		trackingCount = -1;
+		if (DEBUG) {
+			if ((cachedReference == null) && (cachedService == null)) {
+				System.out
+						.println("ServiceTracker.close[cached cleared]: " + filter); //$NON-NLS-1$
+			}
+		}
+	}
+
+	/**
+	 * Default implementation of the
+	 * <code>ServiceTrackerCustomizer.addingService</code> method.
+	 * 
+	 * <p>
+	 * This method is only called when this <code>ServiceTracker</code> object
+	 * has been constructed with a <code>null ServiceTrackerCustomizer</code>
+	 * argument.
+	 * 
+	 * The default implementation returns the result of calling
+	 * <code>getService</code>, on the <code>BundleContext</code> object
+	 * with which this <code>ServiceTracker</code> object was created, passing
+	 * the specified <code>ServiceReference</code> object.
+	 * <p>
+	 * This method can be overridden in a subclass to customize the service
+	 * object to be tracked for the service being added. In that case, take care
+	 * not to rely on the default implementation of removedService that will
+	 * unget the service.
+	 * 
+	 * @param reference Reference to service being added to this
+	 *        <code>ServiceTracker</code> object.
+	 * @return The service object to be tracked for the service added to this
+	 *         <code>ServiceTracker</code> object.
+	 * @see ServiceTrackerCustomizer
+	 */
+	public Object addingService(ServiceReference reference) {
+		return context.getService(reference);
+	}
+
+	/**
+	 * Default implementation of the
+	 * <code>ServiceTrackerCustomizer.modifiedService</code> method.
+	 * 
+	 * <p>
+	 * This method is only called when this <code>ServiceTracker</code> object
+	 * has been constructed with a <code>null ServiceTrackerCustomizer</code>
+	 * argument.
+	 * 
+	 * The default implementation does nothing.
+	 * 
+	 * @param reference Reference to modified service.
+	 * @param service The service object for the modified service.
+	 * @see ServiceTrackerCustomizer
+	 */
+	public void modifiedService(ServiceReference reference, Object service) {
+	}
+
+	/**
+	 * Default implementation of the
+	 * <code>ServiceTrackerCustomizer.removedService</code> method.
+	 * 
+	 * <p>
+	 * This method is only called when this <code>ServiceTracker</code> object
+	 * has been constructed with a <code>null ServiceTrackerCustomizer</code>
+	 * argument.
+	 * 
+	 * The default implementation calls <code>ungetService</code>, on the
+	 * <code>BundleContext</code> object with which this
+	 * <code>ServiceTracker</code> object was created, passing the specified
+	 * <code>ServiceReference</code> object.
+	 * <p>
+	 * This method can be overridden in a subclass. If the default
+	 * implementation of <code>addingService</code> method was used, this
+	 * method must unget the service.
+	 * 
+	 * @param reference Reference to removed service.
+	 * @param service The service object for the removed service.
+	 * @see ServiceTrackerCustomizer
+	 */
+	public void removedService(ServiceReference reference, Object service) {
+		context.ungetService(reference);
+	}
+
+	/**
+	 * Wait for at least one service to be tracked by this
+	 * <code>ServiceTracker</code> object.
+	 * <p>
+	 * It is strongly recommended that <code>waitForService</code> is not used
+	 * during the calling of the <code>BundleActivator</code> methods.
+	 * <code>BundleActivator</code> methods are expected to complete in a
+	 * short period of time.
+	 * 
+	 * @param timeout time interval in milliseconds to wait. If zero, the method
+	 *        will wait indefinately.
+	 * @return Returns the result of <code>getService()</code>.
+	 * @throws InterruptedException If another thread has interrupted the
+	 *         current thread.
+	 * @throws IllegalArgumentException If the value of timeout is negative.
+	 */
+	public Object waitForService(long timeout) throws InterruptedException {
+		if (timeout < 0) {
+			throw new IllegalArgumentException("timeout value is negative"); //$NON-NLS-1$
+		}
+		Object object = getService();
+		while (object == null) {
+			Tracked tracked = this.tracked; /*
+											 * use local var since we are not
+											 * synchronized
+											 */
+			if (tracked == null) { /* if ServiceTracker is not open */
+				return null;
+			}
+			synchronized (tracked) {
+				if (tracked.size() == 0) {
+					tracked.wait(timeout);
+				}
+			}
+			object = getService();
+			if (timeout > 0) {
+				return object;
+			}
+		}
+		return object;
+	}
+
+	/**
+	 * Return an array of <code>ServiceReference</code> objects for all
+	 * services being tracked by this <code>ServiceTracker</code> object.
+	 * 
+	 * @return Array of <code>ServiceReference</code> objects or
+	 *         <code>null</code> if no service are being tracked.
+	 */
+	public ServiceReference[] getServiceReferences() {
+		Tracked tracked = this.tracked; /*
+										 * use local var since we are not
+										 * synchronized
+										 */
+		if (tracked == null) { /* if ServiceTracker is not open */
+			return null;
+		}
+		synchronized (tracked) {
+			int length = tracked.size();
+			if (length == 0) {
+				return null;
+			}
+			ServiceReference[] references = new ServiceReference[length];
+			Enumeration keys = tracked.keys();
+			for (int i = 0; i < length; i++) {
+				references[i] = (ServiceReference) keys.nextElement();
+			}
+			return references;
+		}
+	}
+
+	/**
+	 * Returns a <code>ServiceReference</code> object for one of the services
+	 * being tracked by this <code>ServiceTracker</code> object.
+	 * 
+	 * <p>
+	 * If multiple services are being tracked, the service with the highest
+	 * ranking (as specified in its <code>service.ranking</code> property) is
+	 * returned.
+	 * 
+	 * <p>
+	 * If there is a tie in ranking, the service with the lowest service ID (as
+	 * specified in its <code>service.id</code> property); that is, the
+	 * service that was registered first is returned.
+	 * <p>
+	 * This is the same algorithm used by
+	 * <code>BundleContext.getServiceReference</code>.
+	 * 
+	 * @return <code>ServiceReference</code> object or <code>null</code> if
+	 *         no service is being tracked.
+	 * @since 1.1
+	 */
+	public ServiceReference getServiceReference() {
+		ServiceReference reference = cachedReference;
+		if (reference != null) {
+			if (DEBUG) {
+				System.out
+						.println("ServiceTracker.getServiceReference[cached]: " + filter); //$NON-NLS-1$
+			}
+			return reference;
+		}
+		if (DEBUG) {
+			System.out.println("ServiceTracker.getServiceReference: " + filter); //$NON-NLS-1$
+		}
+		ServiceReference[] references = getServiceReferences();
+		int length = (references == null) ? 0 : references.length;
+		if (length == 0) /* if no service is being tracked */
+		{
+			return null;
+		}
+		int index = 0;
+		if (length > 1) /* if more than one service, select highest ranking */
+		{
+			int rankings[] = new int[length];
+			int count = 0;
+			int maxRanking = Integer.MIN_VALUE;
+			for (int i = 0; i < length; i++) {
+				Object property = references[i]
+						.getProperty(Constants.SERVICE_RANKING);
+				int ranking = (property instanceof Integer) ? ((Integer) property)
+						.intValue()
+						: 0;
+				rankings[i] = ranking;
+				if (ranking > maxRanking) {
+					index = i;
+					maxRanking = ranking;
+					count = 1;
+				}
+				else {
+					if (ranking == maxRanking) {
+						count++;
+					}
+				}
+			}
+			if (count > 1) /* if still more than one service, select lowest id */
+			{
+				long minId = Long.MAX_VALUE;
+				for (int i = 0; i < length; i++) {
+					if (rankings[i] == maxRanking) {
+						long id = ((Long) (references[i]
+								.getProperty(Constants.SERVICE_ID)))
+								.longValue();
+						if (id < minId) {
+							index = i;
+							minId = id;
+						}
+					}
+				}
+			}
+		}
+		return cachedReference = references[index];
+	}
+
+	/**
+	 * Returns the service object for the specified
+	 * <code>ServiceReference</code> object if the referenced service is being
+	 * tracked by this <code>ServiceTracker</code> object.
+	 * 
+	 * @param reference Reference to the desired service.
+	 * @return Service object or <code>null</code> if the service referenced
+	 *         by the specified <code>ServiceReference</code> object is not
+	 *         being tracked.
+	 */
+	public Object getService(ServiceReference reference) {
+		Tracked tracked = this.tracked; /*
+										 * use local var since we are not
+										 * synchronized
+										 */
+		if (tracked == null) { /* if ServiceTracker is not open */
+			return null;
+		}
+		synchronized (tracked) {
+			return tracked.get(reference);
+		}
+	}
+
+	/**
+	 * Return an array of service objects for all services being tracked by this
+	 * <code>ServiceTracker</code> object.
+	 * 
+	 * @return Array of service objects or <code>null</code> if no service are
+	 *         being tracked.
+	 */
+	public Object[] getServices() {
+		Tracked tracked = this.tracked; /*
+										 * use local var since we are not
+										 * synchronized
+										 */
+		if (tracked == null) { /* if ServiceTracker is not open */
+			return null;
+		}
+		synchronized (tracked) {
+			ServiceReference[] references = getServiceReferences();
+			int length = (references == null) ? 0 : references.length;
+			if (length == 0) {
+				return null;
+			}
+			Object[] objects = new Object[length];
+			for (int i = 0; i < length; i++) {
+				objects[i] = getService(references[i]);
+			}
+			return objects;
+		}
+	}
+
+	/**
+	 * Returns a service object for one of the services being tracked by this
+	 * <code>ServiceTracker</code> object.
+	 * 
+	 * <p>
+	 * If any services are being tracked, this method returns the result of
+	 * calling <code>getService(getServiceReference())</code>.
+	 * 
+	 * @return Service object or <code>null</code> if no service is being
+	 *         tracked.
+	 */
+	public Object getService() {
+		Object service = cachedService;
+		if (service != null) {
+			if (DEBUG) {
+				System.out
+						.println("ServiceTracker.getService[cached]: " + filter); //$NON-NLS-1$
+			}
+			return service;
+		}
+		if (DEBUG) {
+			System.out.println("ServiceTracker.getService: " + filter); //$NON-NLS-1$
+		}
+		ServiceReference reference = getServiceReference();
+		if (reference == null) {
+			return null;
+		}
+		return cachedService = getService(reference);
+	}
+
+	/**
+	 * Remove a service from this <code>ServiceTracker</code> object.
+	 * 
+	 * The specified service will be removed from this
+	 * <code>ServiceTracker</code> object. If the specified service was being
+	 * tracked then the <code>ServiceTrackerCustomizer.removedService</code>
+	 * method will be called for that service.
+	 * 
+	 * @param reference Reference to the service to be removed.
+	 */
+	public void remove(ServiceReference reference) {
+		Tracked tracked = this.tracked; /*
+										 * use local var since we are not
+										 * synchronized
+										 */
+		if (tracked == null) { /* if ServiceTracker is not open */
+			return;
+		}
+		tracked.untrack(reference);
+	}
+
+	/**
+	 * Return the number of services being tracked by this
+	 * <code>ServiceTracker</code> object.
+	 * 
+	 * @return Number of services being tracked.
+	 */
+	public int size() {
+		Tracked tracked = this.tracked; /*
+										 * use local var since we are not
+										 * synchronized
+										 */
+		if (tracked == null) { /* if ServiceTracker is not open */
+			return 0;
+		}
+		return tracked.size();
+	}
+
+	/**
+	 * Returns the tracking count for this <code>ServiceTracker</code> object.
+	 * 
+	 * The tracking count is initialized to 0 when this
+	 * <code>ServiceTracker</code> object is opened. Every time a service is
+	 * added or removed from this <code>ServiceTracker</code> object the
+	 * tracking count is incremented.
+	 * 
+	 * <p>
+	 * The tracking count can be used to determine if this
+	 * <code>ServiceTracker</code> object has added or removed a service by
+	 * comparing a tracking count value previously collected with the current
+	 * tracking count value. If the value has not changed, then no service has
+	 * been added or removed from this <code>ServiceTracker</code> object
+	 * since the previous tracking count was collected.
+	 * 
+	 * @since 1.2
+	 * @return The tracking count for this <code>ServiceTracker</code> object
+	 *         or -1 if this <code>ServiceTracker</code> object is not open.
+	 */
+	public int getTrackingCount() {
+		return trackingCount;
+	}
+
+	/**
+	 * Called by the Tracked object whenever the set of tracked services is
+	 * modified. Increments the tracking count and clears the cache.
+	 */
+	/*
+	 * This method must not be synchronized since it is called by Tracked while
+	 * Tracked is synchronized. We don't want synchronization interactions
+	 * between the ServiceListener thread and the user thread.
+	 */
+	void modified() {
+		trackingCount++; /* increment modification count */
+		cachedReference = null; /* clear cached value */
+		cachedService = null; /* clear cached value */
+		if (DEBUG) {
+			System.out.println("ServiceTracker.modified: " + filter); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Finalize. This method no longer performs any function but it kept to
+	 * maintain binary compatibility with prior versions of this class.
+	 */
+	protected void finalize() throws Throwable {
+	}
+
+	/**
+	 * Inner class to track services. If a <code>ServiceTracker</code> object
+	 * is reused (closed then reopened), then a new Tracked object is used. This
+	 * class is a hashtable mapping <code>ServiceReference</code> object ->
+	 * customized Object. This class is the <code>ServiceListener</code>
+	 * object for the tracker. This class is used to synchronize access to the
+	 * tracked services. This is not a public class. It is only for use by the
+	 * implementation of the <code>ServiceTracker</code> class.
+	 * 
+	 */
+	class Tracked extends Hashtable implements ServiceListener {
+		static final long			serialVersionUID	= -7420065199791006079L;
+		/**
+		 * List of ServiceReferences in the process of being added. This is used
+		 * to deal with nesting of ServiceEvents. Since ServiceEvents are
+		 * synchronously delivered, ServiceEvents can be nested. For example,
+		 * when processing the adding of a service and the customizer causes the
+		 * service to be unregistered, notification to the nested call to
+		 * untrack that the service was unregistered can be made to the track
+		 * method.
+		 * 
+		 * Since the ArrayList implementation is not synchronized, all access to
+		 * this list must be protected by the same synchronized object for
+		 * thread safety.
+		 */
+		private ArrayList			adding;
+
+		/**
+		 * true if the tracked object is closed.
+		 * 
+		 * This field is volatile because it is set by one thread and read by
+		 * another.
+		 */
+		private volatile boolean	closed;
+
+		/**
+		 * Initial list of ServiceReferences for the tracker. This is used to
+		 * correctly process the initial services which could become
+		 * unregistered before they are tracked. This is necessary since the
+		 * initial set of tracked services are not "announced" by ServiceEvents
+		 * and therefore the ServiceEvent for unregistration could be delivered
+		 * before we track the service.
+		 * 
+		 * A service must not be in both the initial and adding lists at the
+		 * same time. A service must be moved from the initial list to the
+		 * adding list "atomically" before we begin tracking it.
+		 * 
+		 * Since the LinkedList implementation is not synchronized, all access
+		 * to this list must be protected by the same synchronized object for
+		 * thread safety.
+		 */
+		private LinkedList			initial;
+
+		/**
+		 * Tracked constructor.
+		 */
+		protected Tracked() {
+			super();
+			closed = false;
+			adding = new ArrayList(6);
+			initial = new LinkedList();
+		}
+
+		/**
+		 * Set initial list of services into tracker before ServiceEvents begin
+		 * to be received.
+		 * 
+		 * This method must be called from ServiceTracker.open while
+		 * synchronized on this object in the same synchronized block as the
+		 * addServiceListener call.
+		 * 
+		 * @param references The initial list of services to be tracked.
+		 */
+		protected void setInitialServices(ServiceReference[] references) {
+			if (references == null) {
+				return;
+			}
+			int size = references.length;
+			for (int i = 0; i < size; i++) {
+				if (DEBUG) {
+					System.out
+							.println("ServiceTracker.Tracked.setInitialServices: " + references[i]); //$NON-NLS-1$
+				}
+				initial.add(references[i]);
+			}
+		}
+
+		/**
+		 * Track the initial list of services. This is called after
+		 * ServiceEvents can begin to be received.
+		 * 
+		 * This method must be called from ServiceTracker.open while not
+		 * synchronized on this object after the addServiceListener call.
+		 * 
+		 */
+		protected void trackInitialServices() {
+			while (true) {
+				ServiceReference reference;
+				synchronized (this) {
+					if (initial.size() == 0) {
+						/*
+						 * if there are no more inital services
+						 */
+						return; /* we are done */
+					}
+					/*
+					 * move the first service from the initial list to the
+					 * adding list within this synchronized block.
+					 */
+					reference = (ServiceReference) initial.removeFirst();
+					if (this.get(reference) != null) {
+						/* if we are already tracking this service */
+						if (DEBUG) {
+							System.out
+									.println("ServiceTracker.Tracked.trackInitialServices[already tracked]: " + reference); //$NON-NLS-1$
+						}
+						continue; /* skip this service */
+					}
+					if (adding.contains(reference)) {
+						/*
+						 * if this service is already in the process of being
+						 * added.
+						 */
+						if (DEBUG) {
+							System.out
+									.println("ServiceTracker.Tracked.trackInitialServices[already adding]: " + reference); //$NON-NLS-1$
+						}
+						continue; /* skip this service */
+					}
+					adding.add(reference);
+				}
+				if (DEBUG) {
+					System.out
+							.println("ServiceTracker.Tracked.trackInitialServices: " + reference); //$NON-NLS-1$
+				}
+				trackAdding(reference); /*
+										 * Begin tracking it. We call
+										 * trackAdding since we have already put
+										 * the reference in the adding list.
+										 */
+			}
+		}
+
+		/**
+		 * Called by the owning <code>ServiceTracker</code> object when it is
+		 * closed.
+		 */
+		protected void close() {
+			closed = true;
+		}
+
+		/**
+		 * <code>ServiceListener</code> method for the
+		 * <code>ServiceTracker</code> class. This method must NOT be
+		 * synchronized to avoid deadlock potential.
+		 * 
+		 * @param event <code>ServiceEvent</code> object from the framework.
+		 */
+		public void serviceChanged(ServiceEvent event) {
+			/*
+			 * Check if we had a delayed call (which could happen when we
+			 * close).
+			 */
+			if (closed) {
+				return;
+			}
+			ServiceReference reference = event.getServiceReference();
+			if (DEBUG) {
+				System.out
+						.println("ServiceTracker.Tracked.serviceChanged[" + event.getType() + "]: " + reference); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+
+			switch (event.getType()) {
+				case ServiceEvent.REGISTERED :
+				case ServiceEvent.MODIFIED :
+					if (listenerFilter != null) { // constructor supplied
+													// filter
+						track(reference);
+						/*
+						 * If the customizer throws an unchecked exception, it
+						 * is safe to let it propagate
+						 */
+					}
+					else { // user supplied filter
+						if (filter.match(reference)) {
+							track(reference);
+							/*
+							 * If the customizer throws an unchecked exception,
+							 * it is safe to let it propagate
+							 */
+						}
+						else {
+							untrack(reference);
+							/*
+							 * If the customizer throws an unchecked exception,
+							 * it is safe to let it propagate
+							 */
+						}
+					}
+					break;
+				case ServiceEvent.UNREGISTERING :
+					untrack(reference);
+					/*
+					 * If the customizer throws an unchecked exception, it is
+					 * safe to let it propagate
+					 */
+					break;
+			}
+		}
+
+		/**
+		 * Begin to track the referenced service.
+		 * 
+		 * @param reference Reference to a service to be tracked.
+		 */
+		protected void track(ServiceReference reference) {
+			Object object;
+			synchronized (this) {
+				object = this.get(reference);
+			}
+			if (object != null) /* we are already tracking the service */
+			{
+				if (DEBUG) {
+					System.out
+							.println("ServiceTracker.Tracked.track[modified]: " + reference); //$NON-NLS-1$
+				}
+				/* Call customizer outside of synchronized region */
+				customizer.modifiedService(reference, object);
+				/*
+				 * If the customizer throws an unchecked exception, it is safe
+				 * to let it propagate
+				 */
+				return;
+			}
+			synchronized (this) {
+				if (adding.contains(reference)) { /*
+													 * if this service is
+													 * already in the process of
+													 * being added.
+													 */
+					if (DEBUG) {
+						System.out
+								.println("ServiceTracker.Tracked.track[already adding]: " + reference); //$NON-NLS-1$
+					}
+					return;
+				}
+				adding.add(reference); /* mark this service is being added */
+			}
+
+			trackAdding(reference); /*
+									 * call trackAdding now that we have put the
+									 * reference in the adding list
+									 */
+		}
+
+		/**
+		 * Common logic to add a service to the tracker used by track and
+		 * trackInitialServices. The specified reference must have been placed
+		 * in the adding list before calling this method.
+		 * 
+		 * @param reference Reference to a service to be tracked.
+		 */
+		private void trackAdding(ServiceReference reference) {
+			if (DEBUG) {
+				System.out
+						.println("ServiceTracker.Tracked.trackAdding: " + reference); //$NON-NLS-1$
+			}
+			Object object = null;
+			boolean becameUntracked = false;
+			/* Call customizer outside of synchronized region */
+			try {
+				object = customizer.addingService(reference);
+				/*
+				 * If the customizer throws an unchecked exception, it will
+				 * propagate after the finally
+				 */
+			}
+			finally {
+				synchronized (this) {
+					if (adding.remove(reference)) { /*
+													 * if the service was not
+													 * untracked during the
+													 * customizer callback
+													 */
+						if (object != null) {
+							this.put(reference, object);
+							modified(); /* increment modification count */
+							notifyAll(); /*
+											 * notify any waiters in
+											 * waitForService
+											 */
+						}
+					}
+					else {
+						becameUntracked = true;
+					}
+				}
+			}
+			/*
+			 * The service became untracked during the customizer callback.
+			 */
+			if (becameUntracked) {
+				if (DEBUG) {
+					System.out
+							.println("ServiceTracker.Tracked.trackAdding[removed]: " + reference); //$NON-NLS-1$
+				}
+				/* Call customizer outside of synchronized region */
+				customizer.removedService(reference, object);
+				/*
+				 * If the customizer throws an unchecked exception, it is safe
+				 * to let it propagate
+				 */
+			}
+		}
+
+		/**
+		 * Discontinue tracking the referenced service.
+		 * 
+		 * @param reference Reference to the tracked service.
+		 */
+		protected void untrack(ServiceReference reference) {
+			Object object;
+			synchronized (this) {
+				if (initial.remove(reference)) { /*
+													 * if this service is
+													 * already in the list of
+													 * initial references to
+													 * process
+													 */
+					if (DEBUG) {
+						System.out
+								.println("ServiceTracker.Tracked.untrack[removed from initial]: " + reference); //$NON-NLS-1$
+					}
+					return; /*
+							 * we have removed it from the list and it will not
+							 * be processed
+							 */
+				}
+
+				if (adding.remove(reference)) { /*
+												 * if the service is in the
+												 * process of being added
+												 */
+					if (DEBUG) {
+						System.out
+								.println("ServiceTracker.Tracked.untrack[being added]: " + reference); //$NON-NLS-1$
+					}
+					return; /*
+							 * in case the service is untracked while in the
+							 * process of adding
+							 */
+				}
+				object = this.remove(reference); /*
+													 * must remove from tracker
+													 * before calling customizer
+													 * callback
+													 */
+				if (object == null) { /* are we actually tracking the service */
+					return;
+				}
+				modified(); /* increment modification count */
+			}
+			if (DEBUG) {
+				System.out
+						.println("ServiceTracker.Tracked.untrack[removed]: " + reference); //$NON-NLS-1$
+			}
+			/* Call customizer outside of synchronized region */
+			customizer.removedService(reference, object);
+			/*
+			 * If the customizer throws an unchecked exception, it is safe to
+			 * let it propagate
+			 */
+		}
+	}
+
+	/**
+	 * Subclass of Tracked which implements the AllServiceListener interface.
+	 * This class is used by the ServiceTracker if open is called with true.
+	 * 
+	 * @since 1.3
+	 */
+	class AllTracked extends Tracked implements AllServiceListener {
+		static final long	serialVersionUID	= 4050764875305137716L;
+
+		/**
+		 * AllTracked constructor.
+		 */
+		protected AllTracked() {
+			super();
+		}
+	}
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTrackerCustomizer.java b/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTrackerCustomizer.java
new file mode 100644
index 0000000..cbf7d8e
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTrackerCustomizer.java
@@ -0,0 +1,92 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.tracker/src/org/osgi/util/tracker/ServiceTrackerCustomizer.java,v 1.9 2006/03/14 01:20:01 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2000, 2005). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.util.tracker;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * The <code>ServiceTrackerCustomizer</code> interface allows a
+ * <code>ServiceTracker</code> object to customize the service objects that are
+ * tracked. The <code>ServiceTrackerCustomizer</code> object is called when a
+ * service is being added to the <code>ServiceTracker</code> object. The
+ * <code>ServiceTrackerCustomizer</code> can then return an object for the tracked
+ * service. The <code>ServiceTrackerCustomizer</code> object is also called when a
+ * tracked service is modified or has been removed from the
+ * <code>ServiceTracker</code> object.
+ * 
+ * <p>
+ * The methods in this interface may be called as the result of a
+ * <code>ServiceEvent</code> being received by a <code>ServiceTracker</code> object.
+ * Since <code>ServiceEvent</code> s are synchronously delivered by the Framework,
+ * it is highly recommended that implementations of these methods do not
+ * register (<code>BundleContext.registerService</code>), modify (
+ * <code>ServiceRegistration.setProperties</code>) or unregister (
+ * <code>ServiceRegistration.unregister</code>) a service while being
+ * synchronized on any object.
+ * 
+ * @version $Revision: 1.9 $
+ */
+public interface ServiceTrackerCustomizer {
+	/**
+	 * A service is being added to the <code>ServiceTracker</code> object.
+	 * 
+	 * <p>
+	 * This method is called before a service which matched the search
+	 * parameters of the <code>ServiceTracker</code> object is added to it. This
+	 * method should return the service object to be tracked for this
+	 * <code>ServiceReference</code> object. The returned service object is stored
+	 * in the <code>ServiceTracker</code> object and is available from the
+	 * <code>getService</code> and <code>getServices</code> methods.
+	 * 
+	 * @param reference Reference to service being added to the
+	 *        <code>ServiceTracker</code> object.
+	 * @return The service object to be tracked for the
+	 *         <code>ServiceReference</code> object or <code>null</code> if the
+	 *         <code>ServiceReference</code> object should not be tracked.
+	 */
+	public Object addingService(ServiceReference reference);
+
+	/**
+	 * A service tracked by the <code>ServiceTracker</code> object has been
+	 * modified.
+	 * 
+	 * <p>
+	 * This method is called when a service being tracked by the
+	 * <code>ServiceTracker</code> object has had it properties modified.
+	 * 
+	 * @param reference Reference to service that has been modified.
+	 * @param service The service object for the modified service.
+	 */
+	public void modifiedService(ServiceReference reference,
+			Object service);
+
+	/**
+	 * A service tracked by the <code>ServiceTracker</code> object has been
+	 * removed.
+	 * 
+	 * <p>
+	 * This method is called after a service is no longer being tracked by the
+	 * <code>ServiceTracker</code> object.
+	 * 
+	 * @param reference Reference to service that has been removed.
+	 * @param service The service object for the removed service.
+	 */
+	public void removedService(ServiceReference reference,
+			Object service);
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/tracker/package.html b/org.osgi.compendium/src/main/java/org/osgi/util/tracker/package.html
new file mode 100644
index 0000000..2052965
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/tracker/package.html
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.util.tracker/src/org/osgi/util/tracker/package.html,v 1.3 2005/01/25 05:57:17 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Service Tracker Package. Specification Version 1.3.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.util.tracker; version=1.3
+</pre>
+</BODY>
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/tracker/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/util/tracker/packageinfo
new file mode 100644
index 0000000..6435862
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/tracker/packageinfo
@@ -0,0 +1 @@
+version 1.3.1
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/xml/XMLParserActivator.java b/org.osgi.compendium/src/main/java/org/osgi/util/xml/XMLParserActivator.java
new file mode 100644
index 0000000..c7a0287
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/xml/XMLParserActivator.java
@@ -0,0 +1,532 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.xml/src/org/osgi/util/xml/XMLParserActivator.java,v 1.8 2006/03/14 01:21:37 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2002, 2005). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.util.xml;
+
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+
+import javax.xml.parsers.*;
+
+import org.osgi.framework.*;
+
+/**
+ * A BundleActivator class that allows any JAXP compliant XML Parser to register
+ * itself as an OSGi parser service.
+ * 
+ * Multiple JAXP compliant parsers can concurrently register by using this
+ * BundleActivator class. Bundles who wish to use an XML parser can then use the
+ * framework's service registry to locate available XML Parsers with the desired
+ * characteristics such as validating and namespace-aware.
+ * 
+ * <p>
+ * The services that this bundle activator enables a bundle to provide are:
+ * <ul>
+ * <li><code>javax.xml.parsers.SAXParserFactory</code>({@link #SAXFACTORYNAME})
+ * <li><code>javax.xml.parsers.DocumentBuilderFactory</code>(
+ * {@link #DOMFACTORYNAME})
+ * </ul>
+ * 
+ * <p>
+ * The algorithm to find the implementations of the abstract parsers is derived
+ * from the JAR file specifications, specifically the Services API.
+ * <p>
+ * An XMLParserActivator assumes that it can find the class file names of the
+ * factory classes in the following files:
+ * <ul>
+ * <li><code>/META-INF/services/javax.xml.parsers.SAXParserFactory</code> is
+ * a file contained in a jar available to the runtime which contains the
+ * implementation class name(s) of the SAXParserFactory.
+ * <li><code>/META-INF/services/javax.xml.parsers.DocumentBuilderFactory</code>
+ * is a file contained in a jar available to the runtime which contains the
+ * implementation class name(s) of the <code>DocumentBuilderFactory</code>
+ * </ul>
+ * <p>
+ * If either of the files does not exist, <code>XMLParserActivator</code>
+ * assumes that the parser does not support that parser type.
+ * 
+ * <p>
+ * <code>XMLParserActivator</code> attempts to instantiate both the
+ * <code>SAXParserFactory</code> and the <code>DocumentBuilderFactory</code>.
+ * It registers each factory with the framework along with service properties:
+ * <ul>
+ * <li>{@link #PARSER_VALIDATING}- indicates if this factory supports
+ * validating parsers. It's value is a <code>Boolean</code>.
+ * <li>{@link #PARSER_NAMESPACEAWARE}- indicates if this factory supports
+ * namespace aware parsers It's value is a <code>Boolean</code>.
+ * </ul>
+ * <p>
+ * Individual parser implementations may have additional features, properties,
+ * or attributes which could be used to select a parser with a filter. These can
+ * be added by extending this class and overriding the
+ * <code>setSAXProperties</code> and <code>setDOMProperties</code> methods.
+ */
+public class XMLParserActivator implements BundleActivator, ServiceFactory {
+	/** Context of this bundle */
+	private BundleContext		context;
+	/**
+	 * Filename containing the SAX Parser Factory Class name. Also used as the
+	 * basis for the <code>SERVICE_PID<code> registration property.
+	 */
+	public static final String	SAXFACTORYNAME			= "javax.xml.parsers.SAXParserFactory";
+	/**
+	 * Filename containing the DOM Parser Factory Class name. Also used as the
+	 * basis for the <code>SERVICE_PID</code> registration property.
+	 */
+	public static final String	DOMFACTORYNAME			= "javax.xml.parsers.DocumentBuilderFactory";
+	/** Path to the factory class name files */
+	private static final String	PARSERCLASSFILEPATH		= "/META-INF/services/";
+	/** Fully qualified path name of SAX Parser Factory Class Name file */
+	public static final String	SAXCLASSFILE			= PARSERCLASSFILEPATH
+																+ SAXFACTORYNAME;
+	/** Fully qualified path name of DOM Parser Factory Class Name file */
+	public static final String	DOMCLASSFILE			= PARSERCLASSFILEPATH
+																+ DOMFACTORYNAME;
+	/** SAX Factory Service Description */
+	private static final String	SAXFACTORYDESCRIPTION	= "A JAXP Compliant SAX Parser";
+	/** DOM Factory Service Description */
+	private static final String	DOMFACTORYDESCRIPTION	= "A JAXP Compliant DOM Parser";
+	/**
+	 * Service property specifying if factory is configured to support
+	 * validating parsers. The value is of type <code>Boolean</code>.
+	 */
+	public static final String	PARSER_VALIDATING		= "parser.validating";
+	/**
+	 * Service property specifying if factory is configured to support namespace
+	 * aware parsers. The value is of type <code>Boolean</code>.
+	 */
+	public static final String	PARSER_NAMESPACEAWARE	= "parser.namespaceAware";
+	/**
+	 * Key for parser factory name property - this must be saved in the parsers
+	 * properties hashtable so that the parser factory can be instantiated from
+	 * a ServiceReference
+	 */
+	private static final String	FACTORYNAMEKEY			= "parser.factoryname";
+
+	/**
+	 * Called when this bundle is started so the Framework can perform the
+	 * bundle-specific activities necessary to start this bundle. This method
+	 * can be used to register services or to allocate any resources that this
+	 * bundle needs.
+	 * 
+	 * <p>
+	 * This method must complete and return to its caller in a timely manner.
+	 * 
+	 * <p>
+	 * This method attempts to register a SAX and DOM parser with the
+	 * Framework's service registry.
+	 * 
+	 * @param context The execution context of the bundle being started.
+	 * @throws java.lang.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.
+	 * @see Bundle#start
+	 */
+	public void start(BundleContext context) throws Exception {
+		this.context = context;
+		Bundle parserBundle = context.getBundle();
+		try {
+			// check for sax parsers
+			registerSAXParsers(getParserFactoryClassNames(parserBundle
+					.getResource(SAXCLASSFILE)));
+			// check for dom parsers
+			registerDOMParsers(getParserFactoryClassNames(parserBundle
+					.getResource(DOMCLASSFILE)));
+		}
+		catch (IOException ioe) {
+			// if there were any IO errors accessing the resource files
+			// containing the class names
+			ioe.printStackTrace();
+			throw new FactoryConfigurationError(ioe);
+		}
+	}
+
+	/**
+	 * <p>
+	 * This method has nothing to do as all active service registrations will
+	 * automatically get unregistered when the bundle stops.
+	 * 
+	 * @param context The execution context of the bundle being stopped.
+	 * @throws java.lang.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.
+	 * @see Bundle#stop
+	 */
+	public void stop(BundleContext context) throws Exception {
+	}
+
+	/**
+	 * Given the URL for a file, reads and returns the parser class names. There
+	 * may be multiple classes specified in this file, one per line. There may
+	 * also be comment lines in the file, which begin with "#".
+	 * 
+	 * @param parserUrl The URL of the service file containing the parser class
+	 *        names
+	 * @return A vector of strings containing the parser class names or null if
+	 *         parserUrl is null
+	 * @throws IOException if there is a problem reading the URL input stream
+	 */
+	private Vector getParserFactoryClassNames(URL parserUrl) throws IOException {
+		Vector v = new Vector(1);
+		if (parserUrl != null) {
+			String parserFactoryClassName = null;
+			InputStream is = parserUrl.openStream();
+			BufferedReader br = new BufferedReader(new InputStreamReader(is));
+			while (true) {
+				parserFactoryClassName = br.readLine();
+				if (parserFactoryClassName == null) {
+					break; // end of file reached
+				}
+				String pfcName = parserFactoryClassName.trim();
+				if (pfcName.length() == 0) {
+					continue; // blank line
+				}
+				int commentIdx = pfcName.indexOf("#");
+				if (commentIdx == 0) { // comment line
+					continue;
+				}
+				else
+					if (commentIdx < 0) { // no comment on this line
+						v.addElement(pfcName);
+					}
+					else {
+						v.addElement(pfcName.substring(0, commentIdx).trim());
+					}
+			}
+			return v;
+		}
+		else {
+			return null;
+		}
+	}
+
+	/**
+	 * Register SAX Parser Factory Services with the framework.
+	 * 
+	 * @param parserFactoryClassNames - a <code>Vector</code> of
+	 *        <code>String</code> objects containing the names of the parser
+	 *        Factory Classes
+	 * @throws FactoryConfigurationError if thrown from <code>getFactory</code>
+	 */
+	private void registerSAXParsers(Vector parserFactoryClassNames)
+			throws FactoryConfigurationError {
+		if (parserFactoryClassNames != null) {
+			Enumeration e = parserFactoryClassNames.elements();
+			int index = 0;
+			while (e.hasMoreElements()) {
+				String parserFactoryClassName = (String) e.nextElement();
+				// create a sax parser factory just to get it's default
+				// properties. It will never be used since
+				// this class will operate as a service factory and give each
+				// service requestor it's own SaxParserFactory
+				SAXParserFactory factory = (SAXParserFactory) getFactory(parserFactoryClassName);
+				Hashtable properties = new Hashtable(7);
+				// figure out the default properties of the parser
+				setDefaultSAXProperties(factory, properties, index);
+				// store the parser factory class name in the properties so that
+				// it can be retrieved when getService is called
+				// to return a parser factory
+				properties.put(FACTORYNAMEKEY, parserFactoryClassName);
+				// release the factory
+				factory = null;
+				// register the factory as a service
+				context.registerService(SAXFACTORYNAME, this, properties);
+				index++;
+			}
+		}
+	}
+
+	/**
+	 * <p>
+	 * Set the SAX Parser Service Properties. By default, the following
+	 * properties are set:
+	 * <ul>
+	 * <li><code>SERVICE_DESCRIPTION</code>
+	 * <li><code>SERVICE_PID</code>
+	 * <li><code>PARSER_VALIDATING</code>- instantiates a parser and queries
+	 * it to find out whether it is validating or not
+	 * <li><code>PARSER_NAMESPACEAWARE</code>- instantiates a parser and
+	 * queries it to find out whether it is namespace aware or not
+	 * <ul>
+	 * 
+	 * @param factory The <code>SAXParserFactory</code> object
+	 * @param props <code>Hashtable</code> of service properties.
+	 */
+	private void setDefaultSAXProperties(SAXParserFactory factory,
+			Hashtable props, int index) {
+		props.put(Constants.SERVICE_DESCRIPTION, SAXFACTORYDESCRIPTION);
+		props.put(Constants.SERVICE_PID, SAXFACTORYNAME + "."
+				+ context.getBundle().getBundleId() + "." + index);
+		setSAXProperties(factory, props);
+	}
+
+	/**
+	 * <p>
+	 * Set the customizable SAX Parser Service Properties.
+	 * 
+	 * <p>
+	 * This method attempts to instantiate a validating parser and a
+	 * namespaceaware parser to determine if the parser can support those
+	 * features. The appropriate properties are then set in the specified
+	 * properties object.
+	 * 
+	 * <p>
+	 * This method can be overridden to add additional SAX2 features and
+	 * properties. If you want to be able to filter searches of the OSGi service
+	 * registry, this method must put a key, value pair into the properties
+	 * object for each feature or property. For example,
+	 * 
+	 * properties.put("http://www.acme.com/features/foo", Boolean.TRUE);
+	 * 
+	 * @param factory - the SAXParserFactory object
+	 * @param properties - the properties object for the service
+	 */
+	public void setSAXProperties(SAXParserFactory factory, Hashtable properties) {
+		SAXParser parser = null;
+		// check if this parser can be configured to validate
+		boolean validating = true;
+		factory.setValidating(true);
+		factory.setNamespaceAware(false);
+		try {
+			parser = factory.newSAXParser();
+		}
+		catch (Exception pce_val) {
+			validating = false;
+		}
+		// check if this parser can be configured to be namespaceaware
+		boolean namespaceaware = true;
+		factory.setValidating(false);
+		factory.setNamespaceAware(true);
+		try {
+			parser = factory.newSAXParser();
+		}
+		catch (Exception pce_nsa) {
+			namespaceaware = false;
+		}
+		// set the factory values
+		factory.setValidating(validating);
+		factory.setNamespaceAware(namespaceaware);
+		// set the OSGi service properties
+		properties.put(PARSER_NAMESPACEAWARE, new Boolean(namespaceaware));
+		properties.put(PARSER_VALIDATING, new Boolean(validating));
+	}
+
+	/**
+	 * Register DOM Parser Factory Services with the framework.
+	 * 
+	 * @param parserFactoryClassNames - a <code>Vector</code> of
+	 *        <code>String</code> objects containing the names of the parser
+	 *        Factory Classes
+	 * @throws FactoryConfigurationError if thrown from <code>getFactory</code>
+	 */
+	private void registerDOMParsers(Vector parserFactoryClassNames)
+			throws FactoryConfigurationError {
+		if (parserFactoryClassNames != null) {
+			Enumeration e = parserFactoryClassNames.elements();
+			int index = 0;
+			while (e.hasMoreElements()) {
+				String parserFactoryClassName = (String) e.nextElement();
+				// create a dom parser factory just to get it's default
+				// properties. It will never be used since
+				// this class will operate as a service factory and give each
+				// service requestor it's own DocumentBuilderFactory
+				DocumentBuilderFactory factory = (DocumentBuilderFactory) getFactory(parserFactoryClassName);
+				Hashtable properties = new Hashtable(7);
+				// figure out the default properties of the parser
+				setDefaultDOMProperties(factory, properties, index);
+				// store the parser factory class name in the properties so that
+				// it can be retrieved when getService is called
+				// to return a parser factory
+				properties.put(FACTORYNAMEKEY, parserFactoryClassName);
+				// release the factory
+				factory = null;
+				// register the factory as a service
+				context.registerService(DOMFACTORYNAME, this, properties);
+				index++;
+			}
+		}
+	}
+
+	/**
+	 * Set the DOM parser service properties.
+	 * 
+	 * By default, the following properties are set:
+	 * <ul>
+	 * <li><code>SERVICE_DESCRIPTION</code>
+	 * <li><code>SERVICE_PID</code>
+	 * <li><code>PARSER_VALIDATING</code>
+	 * <li><code>PARSER_NAMESPACEAWARE</code>
+	 * <ul>
+	 * 
+	 * @param factory The <code>DocumentBuilderFactory</code> object
+	 * @param props <code>Hashtable</code> of service properties.
+	 */
+	private void setDefaultDOMProperties(DocumentBuilderFactory factory,
+			Hashtable props, int index) {
+		props.put(Constants.SERVICE_DESCRIPTION, DOMFACTORYDESCRIPTION);
+		props.put(Constants.SERVICE_PID, DOMFACTORYNAME + "."
+				+ context.getBundle().getBundleId() + "." + index);
+		setDOMProperties(factory, props);
+	}
+
+	/**
+	 * <p>
+	 * Set the customizable DOM Parser Service Properties.
+	 * 
+	 * <p>
+	 * This method attempts to instantiate a validating parser and a
+	 * namespaceaware parser to determine if the parser can support those
+	 * features. The appropriate properties are then set in the specified props
+	 * object.
+	 * 
+	 * <p>
+	 * This method can be overridden to add additional DOM2 features and
+	 * properties. If you want to be able to filter searches of the OSGi service
+	 * registry, this method must put a key, value pair into the properties
+	 * object for each feature or property. For example,
+	 * 
+	 * properties.put("http://www.acme.com/features/foo", Boolean.TRUE);
+	 * 
+	 * @param factory - the DocumentBuilderFactory object
+	 * @param props - Hashtable of service properties.
+	 */
+	public void setDOMProperties(DocumentBuilderFactory factory, Hashtable props) {
+		DocumentBuilder parser = null;
+		// check if this parser can be configured to validate
+		boolean validating = true;
+		factory.setValidating(true);
+		factory.setNamespaceAware(false);
+		try {
+			parser = factory.newDocumentBuilder();
+		}
+		catch (Exception pce_val) {
+			validating = false;
+		}
+		// check if this parser can be configured to be namespaceaware
+		boolean namespaceaware = true;
+		factory.setValidating(false);
+		factory.setNamespaceAware(true);
+		try {
+			parser = factory.newDocumentBuilder();
+		}
+		catch (Exception pce_nsa) {
+			namespaceaware = false;
+		}
+		// set the factory values
+		factory.setValidating(validating);
+		factory.setNamespaceAware(namespaceaware);
+		// set the OSGi service properties
+		props.put(PARSER_VALIDATING, new Boolean(validating));
+		props.put(PARSER_NAMESPACEAWARE, new Boolean(namespaceaware));
+	}
+
+	/**
+	 * Given a parser factory class name, instantiate that class.
+	 * 
+	 * @param parserFactoryClassName A <code>String</code> object containing
+	 *        the name of the parser factory class
+	 * @return a parserFactoryClass Object
+	 * @pre parserFactoryClassName!=null
+	 */
+	private Object getFactory(String parserFactoryClassName)
+			throws FactoryConfigurationError {
+		Exception e = null;
+		try {
+			return Class.forName(parserFactoryClassName).newInstance();
+		}
+		catch (ClassNotFoundException cnfe) {
+			e = cnfe;
+		}
+		catch (InstantiationException ie) {
+			e = ie;
+		}
+		catch (IllegalAccessException iae) {
+			e = iae;
+		}
+		throw new FactoryConfigurationError(e);
+	}
+
+	/**
+	 * Creates a new XML Parser Factory object.
+	 * 
+	 * <p>
+	 * A unique XML Parser Factory object is returned for each call to this
+	 * method.
+	 * 
+	 * <p>
+	 * The returned XML Parser Factory object will be configured for validating
+	 * and namespace aware support as specified in the service properties of the
+	 * specified ServiceRegistration object.
+	 * 
+	 * This method can be overridden to configure additional features in the
+	 * returned XML Parser Factory object.
+	 * 
+	 * @param bundle The bundle using the service.
+	 * @param registration The <code>ServiceRegistration</code> object for the
+	 *        service.
+	 * @return A new, configured XML Parser Factory object or null if a
+	 *         configuration error was encountered
+	 */
+	public Object getService(Bundle bundle, ServiceRegistration registration) {
+		ServiceReference sref = registration.getReference();
+		String parserFactoryClassName = (String) sref
+				.getProperty(FACTORYNAMEKEY);
+		try {
+			// need to set factory properties
+			Object factory = getFactory(parserFactoryClassName);
+			if (factory instanceof SAXParserFactory) {
+				((SAXParserFactory) factory).setValidating(((Boolean) sref
+						.getProperty(PARSER_VALIDATING)).booleanValue());
+				((SAXParserFactory) factory).setNamespaceAware(((Boolean) sref
+						.getProperty(PARSER_NAMESPACEAWARE)).booleanValue());
+			}
+			else
+				if (factory instanceof DocumentBuilderFactory) {
+					((DocumentBuilderFactory) factory)
+							.setValidating(((Boolean) sref
+									.getProperty(PARSER_VALIDATING))
+									.booleanValue());
+					((DocumentBuilderFactory) factory)
+							.setNamespaceAware(((Boolean) sref
+									.getProperty(PARSER_NAMESPACEAWARE))
+									.booleanValue());
+				}
+			return factory;
+		}
+		catch (FactoryConfigurationError fce) {
+			fce.printStackTrace();
+			return null;
+		}
+	}
+
+	/**
+	 * Releases a XML Parser Factory object.
+	 * 
+	 * @param bundle The bundle releasing the service.
+	 * @param registration The <code>ServiceRegistration</code> object for the
+	 *        service.
+	 * @param service The XML Parser Factory object returned by a previous call
+	 *        to the <code>getService</code> method.
+	 */
+	public void ungetService(Bundle bundle, ServiceRegistration registration,
+			Object service) {
+	}
+}
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/xml/package.html b/org.osgi.compendium/src/main/java/org/osgi/util/xml/package.html
new file mode 100644
index 0000000..765c81a
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/xml/package.html
@@ -0,0 +1,4 @@
+<!-- $Header: /cvshome/build/org.osgi.util.xml/src/org/osgi/util/xml/package.html,v 1.1 2004/07/02 09:34:46 pkriens Exp $ -->
+<BODY>
+<P>The OSGi XML Parser service Package. Specification Version 1.0.
+</BODY>
diff --git a/org.osgi.compendium/src/main/java/org/osgi/util/xml/packageinfo b/org.osgi.compendium/src/main/java/org/osgi/util/xml/packageinfo
new file mode 100644
index 0000000..a4f1546
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/org/osgi/util/xml/packageinfo
@@ -0,0 +1 @@
+version 1.0
\ No newline at end of file
diff --git a/org.osgi.compendium/src/main/resources/LICENSE b/org.osgi.compendium/src/main/resources/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/org.osgi.compendium/src/main/resources/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/org.osgi.compendium/src/main/resources/about.html b/org.osgi.compendium/src/main/resources/about.html
new file mode 100644
index 0000000..eb1ec76
--- /dev/null
+++ b/org.osgi.compendium/src/main/resources/about.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<!-- $Header: /cvshome/build/osgi/about.html,v 1.3 2006/03/14 01:21:34 hargrave Exp $ -->
+<html>
+<head>
+<title>About</title>
+<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+ 
+<h3>Copyright</h3>
+<p>Copyright (c) 2000, 2005</p>
+
+<p>OSGi Alliance<br/>
+Bishop Ranch 6<br/>
+2400 Camino Ramon, Suite 375<br/>
+San Ramon, CA 94583 USA
+</p>
+<p>All Rights Reserved.</p>
+
+<h3>License</h3>
+<p>The OSGi Alliance makes available all content in this jar (&quot;Work&quot;).  Unless otherwise indicated below, the Work is provided to you under the terms and conditions of the
+Apache License, Version 2.0 (the &quot;License&quot;).  A copy of the License is available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>.</p>
+
+<h3>Notices</h3>
+<p>Implementation of certain elements of the Content may be subject to third party
+intellectual property rights, including without limitation, patent rights (such a third party may
+or may not be a member of the OSGi Alliance). The OSGi Alliance and its members are not responsible 
+and shall not be held responsible in any manner for identifying or failing to identify any or 
+all such third party intellectual property rights.</p>
+
+<p>OSGi&trade; is a trademark, registered trademark, or service mark
+of The OSGi Alliance in the US and other countries. Java is a trademark,
+registered trademark, or service mark of Sun Microsystems, Inc. in the US
+and other countries. All other trademarks, registered trademarks, or
+service marks used in the Content are the property of their respective
+owners and are hereby recognized.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/org.osgi.compendium/xmlns/metatype/metatype.xsd b/org.osgi.compendium/xmlns/metatype/metatype.xsd
new file mode 100644
index 0000000..6d9a509
--- /dev/null
+++ b/org.osgi.compendium/xmlns/metatype/metatype.xsd
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+ * $Header: /cvshome/build/xmlns/metatype/metatype.xsd,v 1.19 2006/03/14 01:21:41 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005, 2006). 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.
+ */
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+	targetNamespace="http://www.osgi.org/xmlns/metatype/v1.0.0"
+	xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0">
+
+	<complexType name="MetaData">
+		<sequence>
+			<element name="OCD" type="metatype:OCD" minOccurs="0"
+				maxOccurs="unbounded" />
+			<element name="Designate" type="metatype:Designate"
+				minOccurs="0" maxOccurs="unbounded" />
+		</sequence>
+		<attribute name="localization" type="string" use="optional" />
+	</complexType>
+
+	<complexType name="OCD">
+		<sequence>
+			<element name="AD" type="metatype:AD" minOccurs="1"
+				maxOccurs="unbounded" />
+			<element name="Icon" type="metatype:Icon" minOccurs="0"
+				maxOccurs="1" />
+		</sequence>
+		<attribute name="name" type="string" use="required" />
+		<attribute name="description" type="string" use="optional" />
+		<attribute name="id" type="string" use="required" />
+	</complexType>
+
+	<complexType name="AD">
+		<sequence>
+			<element name="Option" type="metatype:Option" minOccurs="0"
+				maxOccurs="unbounded" />
+		</sequence>
+		<attribute name="name" type="string" use="optional" />
+		<attribute name="description" type="string" use="optional" />
+		<attribute name="id" type="string" use="required" />
+		<attribute name="type" type="metatype:Scalar" use="required" />
+		<attribute name="cardinality" type="int" use="optional"
+			default="0" />
+		<attribute name="min" type="string" use="optional" />
+		<attribute name="max" type="string" use="optional" />
+		<attribute name="default" type="string" use="optional" />
+		<attribute name="required" type="boolean" use="optional"
+			default="true" />
+	</complexType>
+
+	<complexType name="Object">
+		<sequence>
+			<element name="Attribute" type="metatype:Attribute"
+				minOccurs="0" maxOccurs="unbounded" />
+		</sequence>
+		<attribute name="ocdref" type="string" use="required" />
+	</complexType>
+
+	<complexType name="Attribute">
+		<sequence>
+			<element name="Value" type="string" minOccurs="0"
+				maxOccurs="unbounded" />
+		</sequence>
+		<attribute name="adref" type="string" use="required" />
+		<attribute name="content" type="string" use="optional" />
+	</complexType>
+
+	<complexType name="Designate">
+		<sequence>
+			<element name="Object" type="metatype:Object" minOccurs="1"
+				maxOccurs="1" />
+		</sequence>
+		<attribute name="pid" type="string" use="required" />
+		<attribute name="factoryPid" type="string" use="optional" />
+		<attribute name="bundle" type="string" use="optional" />
+		<attribute name="optional" type="boolean" default="false"
+			use="optional" />
+		<attribute name="merge" type="boolean" default="false"
+			use="optional" />
+	</complexType>
+
+	<simpleType name="Scalar">
+		<restriction base="string">
+			<enumeration value="String" />
+			<enumeration value="Long" />
+			<enumeration value="Double" />
+			<enumeration value="Float" />
+			<enumeration value="Integer" />
+			<enumeration value="Byte" />
+			<enumeration value="Char" />
+			<enumeration value="Boolean" />
+			<enumeration value="Short" />
+		</restriction>
+	</simpleType>
+
+	<complexType name="Option">
+		<attribute name="label" type="string" use="required" />
+		<attribute name="value" type="string" use="required" />
+	</complexType>
+
+	<complexType name="Icon">
+		<attribute name="resource" type="string" use="required" />
+		<attribute name="size" type="positiveInteger" use="required" />
+	</complexType>
+
+	<element name="MetaData" type="metatype:MetaData" />
+</schema>
\ No newline at end of file
diff --git a/org.osgi.compendium/xmlns/scr/scr.xsd b/org.osgi.compendium/xmlns/scr/scr.xsd
new file mode 100644
index 0000000..21fa725
--- /dev/null
+++ b/org.osgi.compendium/xmlns/scr/scr.xsd
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+ * $Header: /cvshome/build/xmlns/scr/scr.xsd,v 1.11 2006/03/14 01:21:41 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005). 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.
+ */
+-->		
+<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.osgi.org/xmlns/scr/v1.0.0" xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0">
+	<annotation>
+		<documentation xml:lang="en">
+This is the XML Schema for component descriptions used by the Service Component Runtime (SCR).
+Component description documents may be embedded in other XML documents. The SCR will
+process all XML documents listed in the Service-Component manifest header of a bundle. 
+XML documents containing component descriptions may contain a single, root component 
+element or one or more component elements embedded in a larger document. Use of the 
+namespace is optional if the document only contains a root component element. In this 
+case, the scr namespace is assumed. Otherwise the namespace must be used.
+		</documentation>
+	</annotation>
+
+	<element name="component" type="scr:Tcomponent"/>
+
+	<complexType name="Tcomponent">
+		<annotation>
+			<documentation xml:lang="en">
+			Implementations of SCR must not require component descriptions to specify the subelements 
+			of the component element in the order as required by the schema. SCR implementations must 
+			allow other orderings since arbitrary orderings do not affect the meaning of the component 
+			description. Only the relative ordering of property and properties element have meaning.
+			</documentation>
+		</annotation>
+		<sequence>
+			<element name="implementation" type="scr:Timplementation" minOccurs="1" maxOccurs="1"/>
+			<choice minOccurs="0" maxOccurs="unbounded">
+				<element name="property" type="scr:Tproperty"/>
+				<element name="properties" type="scr:Tproperties"/>
+			</choice>
+			<element name="service" type="scr:Tservice" minOccurs="0" maxOccurs="1"/>
+			<element name="reference" type="scr:Treference" minOccurs="0" maxOccurs="unbounded"/>
+		</sequence>
+		<attribute name="enabled" type="boolean" default="true" use="optional"/>
+		<attribute name="name" type="token" use="required"/>
+		<attribute name="factory" type="string" use="optional"/>
+		<attribute name="immediate" type="boolean" use="optional"/>
+	</complexType>
+
+	<complexType name="Timplementation">
+		<attribute name="class" type="token" use="required"/>
+	</complexType>
+
+	<complexType name="Tproperty">
+		<simpleContent>
+			<extension base="string">
+				<attribute name="name" type="string" use="required"/>
+				<attribute name="value" type="string" use="optional"/>
+				<attribute name="type" type="scr:TjavaTypes" default="String" use="optional"/>
+			</extension>
+		</simpleContent>
+	</complexType>
+
+	<complexType name="Tproperties">
+		<attribute name="entry" type="string" use="required"/>
+	</complexType>
+
+	<complexType name="Tservice">
+		<sequence>
+			<element name="provide" type="scr:Tprovide" minOccurs="1" maxOccurs="unbounded"/>
+		</sequence>
+		<attribute name="servicefactory" type="boolean" default="false" use="optional"/>
+	</complexType>
+
+	<complexType name="Tprovide">
+		<attribute name="interface" type="token" use="required"/>
+	</complexType>
+
+	<complexType name="Treference">
+		<attribute name="name" type="NMTOKEN" use="required"/>
+		<attribute name="interface" type="token" use="required"/>
+		<attribute name="cardinality" type="scr:Tcardinality" default="1..1" use="optional"/>
+		<attribute name="policy" type="scr:Tpolicy" default="static" use="optional"/>
+		<attribute name="target" type="string" use="optional"/>
+		<attribute name="bind" type="token" use="optional"/>
+		<attribute name="unbind" type="token" use="optional"/>
+	</complexType>
+
+	<simpleType name="TjavaTypes">
+		<restriction base="string">
+			<enumeration value="String"/>
+			<enumeration value="Long"/>
+			<enumeration value="Double"/>
+			<enumeration value="Float"/>
+			<enumeration value="Integer"/>
+			<enumeration value="Byte"/>
+			<enumeration value="Char"/>
+			<enumeration value="Boolean"/>
+			<enumeration value="Short"/>
+		</restriction>
+	</simpleType>
+
+	<simpleType name="Tcardinality">
+		<restriction base="string">
+			<enumeration value="0..1"/>
+			<enumeration value="0..n"/>
+			<enumeration value="1..1"/>
+			<enumeration value="1..n"/>
+		</restriction>
+	</simpleType>
+
+	<simpleType name="Tpolicy">
+		<restriction base="string">
+			<enumeration value="static"/>
+			<enumeration value="dynamic"/>
+		</restriction>
+	</simpleType>
+
+</schema>
\ No newline at end of file