FELIX-4401 Update ServiceComponentRuntime to spec, enable/disable are async returhing Promise

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1604452 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/bnd.bnd b/scr/bnd.bnd
index a1b6682..fb7d41b 100644
--- a/scr/bnd.bnd
+++ b/scr/bnd.bnd
@@ -9,9 +9,11 @@
 Export-Package: org.apache.felix.scr;version=2.0, \
  org.apache.felix.scr.component;version=1.1.0;mandatory:="status"; status="provisional", \
  org.osgi.service.component, \
- org.osgi.service.component.runtime.*;version=1.8, \
- org.osgi.dto;version=1.8, \
- org.osgi.framework.dto;version=1.8
+ org.osgi.service.component.runtime.*;version=1.3, \
+ org.osgi.dto;version=1.0, \
+ org.osgi.framework.dto;version=1.8, \
+ org.osgi.util.function;version=1.0, \
+ org.osgi.util.promise;version=1.0
 
 Private-Package: org.apache.felix.scr.impl.*, \
  org.osgi.util.tracker, \
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
index 2ca10f4..122fb75 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
@@ -25,6 +25,7 @@
 import org.apache.felix.scr.impl.BundleComponentActivator;
 import org.apache.felix.scr.impl.TargetedPID;
 import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.osgi.util.promise.Promise;
 
 
 /**
@@ -102,7 +103,7 @@
      * @param async Whether the actual activation should take place
      *      asynchronously or not.
      */
-    void enableComponents( boolean async );
+    Promise<Void> enableComponents( boolean async );
 
 
     /**
@@ -111,7 +112,7 @@
      * @param async Whether the actual deactivation should take place
      *      asynchronously or not.
      */
-    void disableComponents( boolean async );
+    Promise<Void> disableComponents( boolean async );
     
     /**
      * whether the component is currently enabled
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
index 25bb54e..7579812 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
@@ -43,6 +43,9 @@
 import org.osgi.framework.Constants;
 import org.osgi.service.component.ComponentConstants;
 import org.osgi.service.log.LogService;
+import org.osgi.util.promise.Deferred;
+import org.osgi.util.promise.Promise;
+import org.osgi.util.promise.Promises;
 
 
 /**
@@ -587,7 +590,7 @@
         return m_enabled;
     }
 
-    public void enableComponents( final boolean async )
+    public Promise<Void> enableComponents( final boolean async )
     {
         List<AbstractComponentManager<S>> cms = new ArrayList<AbstractComponentManager<S>>();
         synchronized ( m_components )
@@ -612,14 +615,16 @@
             }
             m_enabled = true;
         }
+        List<Promise<Void>> promises = new ArrayList<Promise<Void>>();
         for ( AbstractComponentManager<S> cm : cms )
         {
-            cm.enable( async );
+            promises.add(cm.enable( async ));
         }
+        return new Deferred().resolveWith(Promises.all(promises));
     }
 
 
-    public void disableComponents( final boolean async )
+    public Promise<Void> disableComponents( final boolean async )
     {
         List<AbstractComponentManager<S>> cms;
         synchronized ( m_components )
@@ -628,10 +633,12 @@
 
             cms = getComponentManagers( true );
         }
+        List<Promise<Void>> promises = new ArrayList<Promise<Void>>();
         for ( AbstractComponentManager<S> cm : cms )
         {
-            cm.disable( async );
+            promises.add(cm.disable( async ));
         }
+        return new Deferred().resolveWith(Promises.all(promises));
     }
 
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
index 63a1310..25b27a8 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.scr.impl.manager;
 
+import java.lang.reflect.InvocationTargetException;
 import java.security.Permission;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -60,6 +61,9 @@
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.ComponentConstants;
 import org.osgi.service.log.LogService;
+import org.osgi.util.promise.Deferred;
+import org.osgi.util.promise.Promise;
+import org.osgi.util.promise.Promises;
 
 
 /**
@@ -103,7 +107,7 @@
      * This latch prevents concurrent enable, disable, and reconfigure.  Since the enable and disable operations may use 
      * two threads and the initiating thread does not wait for the operation to complete, we can't use a regular lock.
      */
-    private final AtomicReference< CountDownLatch> m_enabledLatchRef = new AtomicReference<CountDownLatch>( new CountDownLatch(0) );
+    private final AtomicReference< Deferred<Void>> m_enabledLatchRef = new AtomicReference<Deferred<Void>>( new Deferred<Void>() );
 
     protected volatile boolean m_enabled;
     protected volatile boolean m_internalEnabled;
@@ -138,6 +142,7 @@
     
     protected AbstractComponentManager( ComponentContainer<S> container, ComponentMethods componentMethods, boolean factoryInstance )
     {
+        m_enabledLatchRef.get().resolve(null);
         m_factoryInstance = factoryInstance;
         m_container = container;
         m_componentMethods = componentMethods;
@@ -386,13 +391,13 @@
     //---------- Asynchronous frontend to state change methods ----------------
     private static final AtomicLong taskCounter = new AtomicLong( );
 
-    public final void enable( final boolean async )
+    public final Promise<Void> enable( final boolean async )
     {
         if (m_enabled)
         {
-            return;
+            return Promises.resolved(null);
         }
-        CountDownLatch enableLatch = null;
+        Deferred<Void> enableLatch = null;
         try
         {
             enableLatch = enableLatchWait();
@@ -406,14 +411,14 @@
         {
             if ( !async )
             {
-                enableLatch.countDown();
+                enableLatch.resolve(null);
             }
             m_enabled = true;
         }
 
         if ( async )
         {
-            final CountDownLatch latch = enableLatch;
+            final Deferred<Void> latch = enableLatch;
             getActivator().schedule( new Runnable()
             {
 
@@ -427,7 +432,7 @@
                     }
                     finally
                     {
-                        latch.countDown();
+                        latch.resolve(null);
                     }
                 }
 
@@ -437,6 +442,7 @@
                 }
             } );
         }
+        return enableLatch.getPromise();
     }
 
     /**
@@ -446,10 +452,10 @@
      * @return the latch to count down when the operation is complete (in the calling or another thread)
      * @throws InterruptedException
      */
-    CountDownLatch enableLatchWait()
+    Deferred<Void> enableLatchWait()
     {
-        CountDownLatch enabledLatch;
-        CountDownLatch newEnabledLatch;
+        Deferred<Void> enabledLatch;
+        Deferred<Void> newEnabledLatch;
         do
         {
             enabledLatch = m_enabledLatchRef.get();
@@ -459,19 +465,23 @@
             {
                 try
                 {
-                    enabledLatch.await();
+                    enabledLatch.getPromise().getValue();
                     waited = true;
                 }
                 catch ( InterruptedException e )
                 {
                     interrupted = true;
                 }
+                catch (InvocationTargetException e)
+                {
+                    //this is not going to happen
+                }
             }
             if ( interrupted )
             {
                 Thread.currentThread().interrupt();
             }
-            newEnabledLatch = new CountDownLatch(1);
+            newEnabledLatch = new Deferred<Void>();
         }
         while ( !m_enabledLatchRef.compareAndSet( enabledLatch, newEnabledLatch) );
         return newEnabledLatch;  
@@ -489,13 +499,13 @@
     }
 
 
-    public final void disable( final boolean async )
+    public final Promise<Void> disable( final boolean async )
     {
         if (!m_enabled)
         {
-            return;
+            return Promises.resolved(null);
         }
-        CountDownLatch enableLatch = null;
+        Deferred<Void> enableLatch = null;
         try
         {
             enableLatch = enableLatchWait();
@@ -509,14 +519,14 @@
         {
             if (!async)
             {
-                enableLatch.countDown();
+                enableLatch.resolve(null);
             }
             m_enabled = false;
         }
 
         if ( async )
         {
-            final CountDownLatch latch = enableLatch;
+            final Deferred<Void> latch = enableLatch;
             getActivator().schedule( new Runnable()
             {
 
@@ -530,7 +540,7 @@
                     }
                     finally
                     {
-                        latch.countDown();
+                        latch.resolve(null);
                     }
                 }
 
@@ -541,6 +551,7 @@
 
             } );
         }
+        return enableLatch.getPromise();
     }
 
     // supports the ComponentInstance.dispose() method
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
index 730d6c6..0c30ea8 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
@@ -42,6 +42,8 @@
 import org.osgi.service.component.ComponentConstants;
 import org.osgi.service.component.ComponentInstance;
 import org.osgi.service.log.LogService;
+import org.osgi.util.promise.Deferred;
+import org.osgi.util.promise.Promise;
 
 
 /**
@@ -545,7 +547,7 @@
 
     void reconfigure(boolean configurationDeleted)
     {
-        CountDownLatch enableLatch = enableLatchWait();
+        Deferred<Void> enableLatch = enableLatchWait();
         try
         {
             // clear the current properties to force using the configuration data
@@ -609,7 +611,7 @@
         }
         finally
         {
-            enableLatch.countDown();
+            enableLatch.resolve(null);
         }
     }
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/runtime/ServiceComponentRuntimeImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/runtime/ServiceComponentRuntimeImpl.java
index 727b2cc..1bd73b6 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/runtime/ServiceComponentRuntimeImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/runtime/ServiceComponentRuntimeImpl.java
@@ -40,6 +40,7 @@
 import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
 import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
 import org.osgi.service.component.runtime.dto.ReferenceDTO;
+import org.osgi.util.promise.Promise;
 
 public class ServiceComponentRuntimeImpl implements ServiceComponentRuntime {
 	
@@ -110,14 +111,14 @@
 		return holder.isEnabled();
 	}
 
-	public void enableComponent(ComponentDescriptionDTO description) {
+	public Promise<Void> enableComponent(ComponentDescriptionDTO description) {
 		ComponentHolder<?> holder = getHolderFromDescription( description);
-		holder.enableComponents(false); //synchronous
+		return holder.enableComponents(true);
 	}
 
-	public void disableComponent(ComponentDescriptionDTO description) {
+	public Promise<Void> disableComponent(ComponentDescriptionDTO description) {
 		ComponentHolder<?> holder = getHolderFromDescription( description);
-		holder.disableComponents(false); //synchronous
+		return holder.disableComponents(true); //synchronous
 	}
 	
 	private ComponentConfigurationDTO managerToConfiguration(
diff --git a/scr/src/main/java/org/osgi/annotation/versioning/ConsumerType.java b/scr/src/main/java/org/osgi/annotation/versioning/ConsumerType.java
new file mode 100644
index 0000000..f5fa786
--- /dev/null
+++ b/scr/src/main/java/org/osgi/annotation/versioning/ConsumerType.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) OSGi Alliance (2013, 2014). 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.annotation.versioning;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A type implemented by the Consumer Role.
+ * 
+ * <p>
+ * A non-binary compatible change to a consumer type normally requires
+ * incrementing the major version of the type's package. This change will
+ * require all providers and all consumers to be updated to handle the change
+ * since consumers implement the consumer type and all providers must understand
+ * the change in the consumer type.
+ * 
+ * <p>
+ * A type can be marked {@link ConsumerType} or {@link ProviderType} but not
+ * both. A type is assumed to be {@link ConsumerType} if it is not marked either
+ * {@link ConsumerType} or {@link ProviderType}.
+ * 
+ * <p>
+ * This annotation is not retained at runtime. It is for use by tools to
+ * understand the semantic version of a package. When a bundle implements a
+ * consumer type from an imported package, then the bundle's import range for
+ * that package must require the exact major version and a minor version greater
+ * than or equal to the package's version.
+ * 
+ * @see <a href="http://www.osgi.org/wiki/uploads/Links/SemanticVersioning.pdf"
+ *      >Semantic Versioning</a>
+ * @author $Id: 319ac9d62b568a8cde1523e0059aa3e44c7e86af $
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface ConsumerType {
+	// marker annotation
+}
diff --git a/scr/src/main/java/org/osgi/annotation/versioning/ProviderType.java b/scr/src/main/java/org/osgi/annotation/versioning/ProviderType.java
new file mode 100644
index 0000000..fdfee9e
--- /dev/null
+++ b/scr/src/main/java/org/osgi/annotation/versioning/ProviderType.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) OSGi Alliance (2013, 2014). 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.annotation.versioning;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A type implemented by the Provider Role.
+ * 
+ * <p>
+ * A non-binary compatible change to a provider type normally requires
+ * incrementing the minor version of the type's package. This change will
+ * require all providers to be updated to handle the change, but consumers of
+ * that package will not require changes since they only use, and do not
+ * implement, the provider type.
+ * 
+ * <p>
+ * A type can be marked {@link ConsumerType} or {@link ProviderType} but not
+ * both. A type is assumed to be {@link ConsumerType} if it is not marked either
+ * {@link ConsumerType} or {@link ProviderType}.
+ * 
+ * <p>
+ * This annotation is not retained at runtime. It is for use by tools to
+ * understand the semantic version of a package. When a bundle implements a
+ * provider type from an imported package, then the bundle's import range for
+ * that package must require the package's exact major and minor version.
+ * 
+ * @see <a href="http://www.osgi.org/wiki/uploads/Links/SemanticVersioning.pdf"
+ *      >Semantic Versioning</a>
+ * @author $Id: 46ccfd7aa446f79451d090e0c23e257c3c5c3cf0 $
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface ProviderType {
+	// marker annotation
+}
diff --git a/scr/src/main/java/org/osgi/annotation/versioning/Version.java b/scr/src/main/java/org/osgi/annotation/versioning/Version.java
new file mode 100644
index 0000000..982680a
--- /dev/null
+++ b/scr/src/main/java/org/osgi/annotation/versioning/Version.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) OSGi Alliance (2013). 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.annotation.versioning;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Specify the version of a package.
+ * 
+ * <p>
+ * This annotation is not retained at runtime. It is for use by tools to
+ * generate bundle manifests or otherwise process the version of a package.
+ * 
+ * @see <a href="http://www.osgi.org/wiki/uploads/Links/SemanticVersioning.pdf"
+ *      >Semantic Versioning</a>
+ * @author $Id: dcb5aff364bf7d59d647211711ae0e32697cc56f $
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.PACKAGE)
+public @interface Version {
+	/**
+	 * The version of the annotated package.
+	 * 
+	 * <p>
+	 * The version must be a valid OSGi version string.
+	 */
+	String value();
+}
diff --git a/scr/src/main/java/org/osgi/annotation/versioning/package-info.java b/scr/src/main/java/org/osgi/annotation/versioning/package-info.java
new file mode 100644
index 0000000..7268d2d
--- /dev/null
+++ b/scr/src/main/java/org/osgi/annotation/versioning/package-info.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) OSGi Alliance (2013). 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.
+ */
+
+/**
+ * OSGi Versioning Annotations Package Version 1.0.
+ *
+ * <p>
+ * This package is not used at runtime.
+ *
+ * @see <a href="http://www.osgi.org/wiki/uploads/Links/SemanticVersioning.pdf"
+ *      >Semantic Versioning</a>
+ * @version 1.0
+ * @author $Id: 1bffd081f72d9ddcdc31a7c49493b35b009ba0e3 $
+ */
+@Version("1.0")
+package org.osgi.annotation.versioning;
+
diff --git a/scr/src/main/java/org/osgi/service/component/runtime/ServiceComponentRuntime.java b/scr/src/main/java/org/osgi/service/component/runtime/ServiceComponentRuntime.java
index 45db87df..b34a4ba 100755
--- a/scr/src/main/java/org/osgi/service/component/runtime/ServiceComponentRuntime.java
+++ b/scr/src/main/java/org/osgi/service/component/runtime/ServiceComponentRuntime.java
@@ -17,11 +17,12 @@
 package org.osgi.service.component.runtime;
 
 import java.util.Collection;
-//import org.osgi.annotation.versioning.ProviderType;
+import org.osgi.annotation.versioning.ProviderType;
 import org.osgi.framework.Bundle;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
 import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
+import org.osgi.util.promise.Promise;
 
 /**
  * The {@code ServiceComponentRuntime} service represents the Declarative
@@ -45,9 +46,9 @@
  * 
  * @ThreadSafe
  * @since 1.3
- * @author $Id: 0b736eb18ed9ae337ef04765d1c006049a246c56 $
+ * @author $Id: 2b9c69ef323cb6b4be2601f893bea8505c984980 $
  */
-//@ProviderType
+@ProviderType
 public interface ServiceComponentRuntime {
 
 	/**
@@ -124,11 +125,20 @@
 	 * If the specified component description is currently enabled, this method
 	 * has no effect.
 	 * 
+	 * <p>
+	 * This method must return after changing the enabled state of the specified
+	 * component description. Any actions that result from this, such as
+	 * activating or deactivating a component configuration, must occur
+	 * asynchronously to this method call.
+	 * 
 	 * @param description The component description to enable. Must not be
 	 *        {@code null}.
+	 * @return A promise that will be resolved when the actions that result from
+	 *         changing the enabled state of the specified component have
+	 *         completed.
 	 * @see #isComponentEnabled(ComponentDescriptionDTO)
 	 */
-	void enableComponent(ComponentDescriptionDTO description);
+	Promise<Void> enableComponent(ComponentDescriptionDTO description);
 
 	/**
 	 * Disables the specified component description.
@@ -137,9 +147,18 @@
 	 * If the specified component description is currently disabled, this method
 	 * has no effect.
 	 * 
+	 * <p>
+	 * This method must return after changing the enabled state of the specified
+	 * component description. Any actions that result from this, such as
+	 * activating or deactivating a component configuration, must occur
+	 * asynchronously to this method call.
+	 * 
 	 * @param description The component description to disable. Must not be
 	 *        {@code null}.
+	 * @return A promise that will be resolved when the actions that result from
+	 *         changing the enabled state of the specified component have
+	 *         completed.
 	 * @see #isComponentEnabled(ComponentDescriptionDTO)
 	 */
-	void disableComponent(ComponentDescriptionDTO description);
+	Promise<Void> disableComponent(ComponentDescriptionDTO description);
 }
diff --git a/scr/src/main/java/org/osgi/service/component/runtime/dto/ComponentConfigurationDTO.java b/scr/src/main/java/org/osgi/service/component/runtime/dto/ComponentConfigurationDTO.java
index fbed36d..6b87ee0 100755
--- a/scr/src/main/java/org/osgi/service/component/runtime/dto/ComponentConfigurationDTO.java
+++ b/scr/src/main/java/org/osgi/service/component/runtime/dto/ComponentConfigurationDTO.java
@@ -26,7 +26,7 @@
  * 
  * @since 1.3
  * @NotThreadSafe
- * @author $Id: b3f49d694f497e55dc7ffed0e7d910fb3bab83da $
+ * @author $Id: e852b2edb4d364069d01ca41130aac4a3b3112a3 $
  */
 public class ComponentConfigurationDTO extends DTO {
 	/**
@@ -69,6 +69,15 @@
 	public ComponentDescriptionDTO	description;
 
 	/**
+	 * The id of the component configuration.
+	 * 
+	 * <p>
+	 * The id is a non-persistent, unique value assigned at runtime. The id is
+	 * also available as the {@code component.id} component property.
+	 */
+	public long						id;
+
+	/**
 	 * The current state of the component configuration.
 	 * 
 	 * <p>
@@ -93,13 +102,4 @@
 	 * component configuration has no bound references.
 	 */
 	public BoundReferenceDTO[]		boundReferences;
-	
-	/**
-	 * The id of the component description.
-	 * 
-	 * <p>
-	 * The id is a non-persistent, unique value assigned at runtime. The id is
-	 * also available as the {@code component.id} component property.
-	 */
-	public long					id;
 }
diff --git a/scr/src/main/java/org/osgi/service/component/runtime/dto/ComponentDescriptionDTO.java b/scr/src/main/java/org/osgi/service/component/runtime/dto/ComponentDescriptionDTO.java
index 986d463..bab6ad4 100755
--- a/scr/src/main/java/org/osgi/service/component/runtime/dto/ComponentDescriptionDTO.java
+++ b/scr/src/main/java/org/osgi/service/component/runtime/dto/ComponentDescriptionDTO.java
@@ -25,7 +25,7 @@
  * 
  * @since 1.3
  * @NotThreadSafe
- * @author $Id: f0bf3f3036179db049645595e631489455affe8a $
+ * @author $Id: 5ed89a27964e91018c55dc9e72434eb92a438fa6 $
  */
 public class ComponentDescriptionDTO extends DTO {
 	/**
@@ -58,7 +58,8 @@
 	 * 
 	 * <p>
 	 * This is declared in the {@code scope} attribute of the {@code service}
-	 * element.
+	 * element. This will be {@code null} if the component description does not
+	 * declare any service interfaces.
 	 */
 	public String				scope;
 
@@ -159,13 +160,12 @@
 	public String				configurationPolicy;
 
 	/**
-	 * The configuration pid.
+	 * The configuration pids.
 	 * 
 	 * <p>
-	 * This is declared in the {@code configuration-pid} attribute of the
-	 * {@code component} element. This will be the default configuration pid if
-	 * the component description does not declare a configuration pid.
+	 * These are declared in the {@code configuration-pid} attribute of the
+	 * {@code component} element. This will contain the default configuration
+	 * pid if the component description does not declare a configuration pid.
 	 */
 	public String[]				configurationPid;
-
 }
diff --git a/scr/src/main/java/org/osgi/service/component/runtime/dto/package-info.java b/scr/src/main/java/org/osgi/service/component/runtime/dto/package-info.java
index bc806dd..75c3b78 100644
--- a/scr/src/main/java/org/osgi/service/component/runtime/dto/package-info.java
+++ b/scr/src/main/java/org/osgi/service/component/runtime/dto/package-info.java
@@ -35,8 +35,8 @@
  * @author $Id: d7d82da09d67a3ce4274ad8554966c1952a2b4de $
  */
 
-//@Version("1.3")
+@Version("1.3")
 package org.osgi.service.component.runtime.dto;
 
-//import org.osgi.annotation.versioning.Version;
+import org.osgi.annotation.versioning.Version;
 
diff --git a/scr/src/main/java/org/osgi/service/component/runtime/package-info.java b/scr/src/main/java/org/osgi/service/component/runtime/package-info.java
index 55a20c1..1dd3488 100644
--- a/scr/src/main/java/org/osgi/service/component/runtime/package-info.java
+++ b/scr/src/main/java/org/osgi/service/component/runtime/package-info.java
@@ -35,8 +35,8 @@
  * @author $Id: 3d4fa42ce33a4682cbaeee3f094b558e6ea6080f $
  */
 
-//@Version("1.3")
+@Version("1.3")
 package org.osgi.service.component.runtime;
 
-//import org.osgi.annotation.versioning.Version;
+import org.osgi.annotation.versioning.Version;
 
diff --git a/scr/src/main/java/org/osgi/util/function/Function.java b/scr/src/main/java/org/osgi/util/function/Function.java
new file mode 100644
index 0000000..313d772
--- /dev/null
+++ b/scr/src/main/java/org/osgi/util/function/Function.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) OSGi Alliance (2014). 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.function;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * A function that accepts a single argument and produces a result.
+ *
+ * <p>
+ * This is a functional interface and can be used as the assignment target for a
+ * lambda expression or method reference.
+ * 
+ * @param <T> The type of the function input.
+ * @param <R> The type of the function output.
+ * 
+ * @ThreadSafe
+ * @author $Id: 5d812f75c0b4f88f01083189babb3ef7476b5ced $
+ */
+@ConsumerType
+public interface Function<T, R> {
+	/**
+	 * Applies this function to the specified argument.
+	 * 
+	 * @param t The input to this function.
+	 * @return The output of this function.
+	 */
+	R apply(T t);
+}
diff --git a/scr/src/main/java/org/osgi/util/function/Predicate.java b/scr/src/main/java/org/osgi/util/function/Predicate.java
new file mode 100644
index 0000000..8b4c695
--- /dev/null
+++ b/scr/src/main/java/org/osgi/util/function/Predicate.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) OSGi Alliance (2014). 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.function;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * A predicate that accepts a single argument and produces a boolean result.
+ *
+ * <p>
+ * This is a functional interface and can be used as the assignment target for a
+ * lambda expression or method reference.
+ * 
+ * @param <T> The type of the predicate input.
+ * 
+ * @ThreadSafe
+ * @author $Id: 0c2c61f78bede4e2afc4278af4f5e4b873769347 $
+ */
+@ConsumerType
+public interface Predicate<T> {
+	/**
+	 * Evaluates this predicate on the specified argument.
+	 * 
+	 * @param t The input to this predicate.
+	 * @return {@code true} if the specified argument is accepted by this
+	 *         predicate; {@code false} otherwise.
+	 */
+	boolean test(T t);
+}
diff --git a/scr/src/main/java/org/osgi/util/function/package-info.java b/scr/src/main/java/org/osgi/util/function/package-info.java
new file mode 100644
index 0000000..6dcf3b8
--- /dev/null
+++ b/scr/src/main/java/org/osgi/util/function/package-info.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) OSGi Alliance (2014). 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.
+ */
+
+/**
+ * Function Package Version 1.0.
+ * 
+ * <p>
+ * Bundles wishing to use this package must list the package in the
+ * Import-Package header of the bundle's manifest.
+ * 
+ * <p>
+ * Example import for consumers using the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.util.function; version="[1.0,2.0)"}
+ * <p>
+ * Example import for providers implementing the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.util.function; version="[1.0,1.1)"}
+ * 
+ * @author $Id: 899d786b27012f55ed87b4c872a6ab2087a20a39 $
+ */
+
+@Version("1.0")
+package org.osgi.util.function;
+
+import org.osgi.annotation.versioning.Version;
+
diff --git a/scr/src/main/java/org/osgi/util/promise/Deferred.java b/scr/src/main/java/org/osgi/util/promise/Deferred.java
new file mode 100644
index 0000000..29efdeb
--- /dev/null
+++ b/scr/src/main/java/org/osgi/util/promise/Deferred.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) OSGi Alliance (2014). 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.promise;
+
+import static org.osgi.util.promise.PromiseImpl.requireNonNull;
+
+/**
+ * A Deferred Promise resolution.
+ * 
+ * <p>
+ * Instances of this class can be used to create a {@link Promise} that can be
+ * resolved in the future. The {@link #getPromise() associated} Promise can be
+ * successfully resolved with {@link #resolve(Object)} or resolved with a
+ * failure with {@link #fail(Throwable)}. It can also be resolved with the
+ * resolution of another promise using {@link #resolveWith(Promise)}.
+ * 
+ * <p>
+ * The associated Promise can be provided to any one, but the Deferred object
+ * should be made available only to the party that will responsible for
+ * resolving the Promise.
+ * 
+ * @param <T> The value type associated with the created Promise.
+ * 
+ * @Immutable
+ * @author $Id: b12288b7edc994f615dc1305d6aeaeeb56208df7 $
+ */
+public class Deferred<T> {
+	private final PromiseImpl<T>	promise;
+
+	/**
+	 * Create a new Deferred with an associated Promise.
+	 */
+	public Deferred() {
+		promise = new PromiseImpl<T>();
+	}
+
+	/**
+	 * Returns the Promise associated with this Deferred.
+	 * 
+	 * @return The Promise associated with this Deferred.
+	 */
+	public Promise<T> getPromise() {
+		return promise;
+	}
+
+	/**
+	 * Successfully resolve the Promise associated with this Deferred.
+	 * 
+	 * <p>
+	 * After the associated Promise is resolved with the specified value, all
+	 * registered {@link Promise#onResolve(Runnable) callbacks} are called and
+	 * any {@link Promise#then(Success, Failure) chained} Promises are resolved.
+	 * 
+	 * <p>
+	 * Resolving the associated Promise <i>happens-before</i> any registered
+	 * callback is called. That is, in a registered callback,
+	 * {@link Promise#isDone()} must return {@code true} and
+	 * {@link Promise#getValue()} and {@link Promise#getFailure()} must not
+	 * block.
+	 * 
+	 * @param value The value of the resolved Promise.
+	 * @throws IllegalStateException If the associated Promise was already
+	 *         resolved.
+	 */
+	public void resolve(T value) {
+		promise.resolve(value, null);
+	}
+
+	/**
+	 * Fail the Promise associated with this Deferred.
+	 * 
+	 * <p>
+	 * After the associated Promise is resolved with the specified failure, all
+	 * registered {@link Promise#onResolve(Runnable) callbacks} are called and
+	 * any {@link Promise#then(Success, Failure) chained} Promises are resolved.
+	 * 
+	 * <p>
+	 * Resolving the associated Promise <i>happens-before</i> any registered
+	 * callback is called. That is, in a registered callback,
+	 * {@link Promise#isDone()} must return {@code true} and
+	 * {@link Promise#getValue()} and {@link Promise#getFailure()} must not
+	 * block.
+	 * 
+	 * @param failure The failure of the resolved Promise. Must not be
+	 *        {@code null}.
+	 * @throws IllegalStateException If the associated Promise was already
+	 *         resolved.
+	 */
+	public void fail(Throwable failure) {
+		promise.resolve(null, requireNonNull(failure));
+	}
+
+	/**
+	 * Resolve the Promise associated with this Deferred with the specified
+	 * Promise.
+	 * 
+	 * <p>
+	 * If the specified Promise is successfully resolved, the associated Promise
+	 * is resolved with the value of the specified Promise. If the specified
+	 * Promise is resolved with a failure, the associated Promise is resolved
+	 * with the failure of the specified Promise.
+	 * 
+	 * <p>
+	 * After the associated Promise is resolved with the specified Promise, all
+	 * registered {@link Promise#onResolve(Runnable) callbacks} are called and
+	 * any {@link Promise#then(Success, Failure) chained} Promises are resolved.
+	 * 
+	 * <p>
+	 * Resolving the associated Promise <i>happens-before</i> any registered
+	 * callback is called. That is, in a registered callback,
+	 * {@link Promise#isDone()} must return {@code true} and
+	 * {@link Promise#getValue()} and {@link Promise#getFailure()} must not
+	 * block.
+	 * 
+	 * @param with A Promise whose value or failure will be used to resolve the
+	 *        associated Promise. Must not be {@code null}.
+	 * @return A Promise that is resolved only when the associated Promise is
+	 *         resolved by the specified Promise. The returned Promise will be
+	 *         successfully resolved, with the value {@code null}, if the
+	 *         associated Promise was resolved by the specified Promise. The
+	 *         returned Promise will be resolved with a failure of
+	 *         {@link IllegalStateException} if the associated Promise was
+	 *         already resolved when the specified Promise was resolved.
+	 */
+	public Promise<Void> resolveWith(Promise<? extends T> with) {
+		return promise.resolveWith(with);
+	}
+}
diff --git a/scr/src/main/java/org/osgi/util/promise/FailedPromisesException.java b/scr/src/main/java/org/osgi/util/promise/FailedPromisesException.java
new file mode 100644
index 0000000..6d9c472
--- /dev/null
+++ b/scr/src/main/java/org/osgi/util/promise/FailedPromisesException.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) OSGi Alliance (2014). 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.promise;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Promise failure exception for a collection of failed Promises.
+ * 
+ * @author $Id: 95546abe53fcca0c3daa3d2847a915fe94b9cef8 $
+ */
+public class FailedPromisesException extends RuntimeException {
+	private static final long				serialVersionUID	= 1L;
+	private final Collection<Promise<?>>	failed;
+
+	/**
+	 * Create a new FailedPromisesException with the specified Promises.
+	 * 
+	 * @param failed A collection of Promises that have been resolved with a
+	 *        failure. Must not be {@code null}, must not be empty and all of
+	 *        the elements in the collection must not be {@code null}.
+	 * @param cause The cause of this exception. This is typically the failure
+	 *        of the first Promise in the specified collection.
+	 */
+	public FailedPromisesException(Collection<Promise<?>> failed, Throwable cause) {
+		super(cause);
+		this.failed = Collections.unmodifiableCollection(failed);
+	}
+
+	/**
+	 * Returns the collection of Promises that have been resolved with a
+	 * failure.
+	 * 
+	 * @return The collection of Promises that have been resolved with a
+	 *         failure. The returned collection is unmodifiable.
+	 */
+	public Collection<Promise<?>> getFailedPromises() {
+		return failed;
+	}
+}
diff --git a/scr/src/main/java/org/osgi/util/promise/Failure.java b/scr/src/main/java/org/osgi/util/promise/Failure.java
new file mode 100644
index 0000000..ab93794
--- /dev/null
+++ b/scr/src/main/java/org/osgi/util/promise/Failure.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) OSGi Alliance (2014). 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.promise;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * Failure callback for a Promise.
+ * 
+ * <p>
+ * A Failure callback is registered with a {@link Promise} using the
+ * {@link Promise#then(Success, Failure)} method and is called if the Promise is
+ * resolved with a failure.
+ * 
+ * <p>
+ * This is a functional interface and can be used as the assignment target for a
+ * lambda expression or method reference.
+ * 
+ * @ThreadSafe
+ * @author $Id: a4bd1ef9948a4abb9fc01a140bd9562be0beb9aa $
+ */
+@ConsumerType
+public interface Failure {
+	/**
+	 * Failure callback for a Promise.
+	 * 
+	 * <p>
+	 * This method is called if the Promise with which it is registered resolves
+	 * with a failure.
+	 * 
+	 * <p>
+	 * In the remainder of this description we will refer to the Promise
+	 * returned by {@link Promise#then(Success, Failure)} when this Failure
+	 * callback was registered as the chained Promise.
+	 * 
+	 * <p>
+	 * If this methods completes normally, the chained Promise will be failed
+	 * with the same exception which failed the resolved Promise. If this method
+	 * throws an exception, the chained Promise will be failed with the thrown
+	 * exception.
+	 * 
+	 * @param resolved The failed resolved {@link Promise}.
+	 * @throws Exception The chained Promise will be failed with the thrown
+	 *         exception.
+	 */
+	void fail(Promise<?> resolved) throws Exception;
+}
diff --git a/scr/src/main/java/org/osgi/util/promise/Promise.java b/scr/src/main/java/org/osgi/util/promise/Promise.java
new file mode 100644
index 0000000..74e4b59
--- /dev/null
+++ b/scr/src/main/java/org/osgi/util/promise/Promise.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) OSGi Alliance (2014). 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.promise;
+
+import java.lang.reflect.InvocationTargetException;
+import org.osgi.annotation.versioning.ProviderType;
+import org.osgi.util.function.Function;
+import org.osgi.util.function.Predicate;
+
+/**
+ * A Promise of a value.
+ * 
+ * <p>
+ * A Promise represents a future value. It handles the interactions for
+ * asynchronous processing. A {@link Deferred} object can be used to create a
+ * Promise and later resolve the Promise. A Promise is used by the caller of an
+ * asynchronous function to get the result or handle the error. The caller can
+ * either get a callback when the Promise is resolved with a value or an error,
+ * or the Promise can be used in chaining. In chaining, callbacks are provided
+ * that receive the resolved Promise, and a new Promise is generated that
+ * resolves based upon the result of a callback.
+ * 
+ * <p>
+ * Both {@link #onResolve(Runnable) callbacks} and
+ * {@link #then(Success, Failure) chaining} can be repeated any number of times,
+ * even after the Promise has been resolved.
+ * <p>
+ * Example callback usage:
+ * 
+ * <pre>
+ * final Promise&lt;String&gt; foo = foo();
+ * foo.onResolve(new Runnable() {
+ *   public void run() {
+ *     System.out.println(foo.getValue());
+ *   }
+ * });
+ * </pre>
+ * 
+ * Example chaining usage;
+ * 
+ * <pre>
+ * Success&lt;String,String&gt; doubler = new Success&lt;String,String&gt;() {
+ *   public Promise&lt;String&gt; call(Promise&lt;String&gt; p) throws Exception {
+ *     return Promises.resolved(p.getValue()+p.getValue());
+ *   }
+ * };
+ * final Promise&lt;String&gt; foo = foo().then(doubler).then(doubler);
+ * foo.onResolve(new Runnable() {
+ *   public void run() {
+ *     System.out.println(foo.getValue());
+ *   }
+ * });
+ * </pre>
+ * 
+ * @param <T> The value type associated with this Promise.
+ * 
+ * @ThreadSafe
+ * @author $Id: 8a24f66339967ecdd03def57f31ac8c371a7f4cd $
+ */
+@ProviderType
+public interface Promise<T> {
+
+	/**
+	 * Returns whether this Promise has been resolved.
+	 * 
+	 * <p>
+	 * This Promise may be successfully resolved or resolved with a failure.
+	 * 
+	 * @return {@code true} if this Promise was resolved either successfully or
+	 *         with a failure; {@code false} if this Promise is unresolved.
+	 */
+	boolean isDone();
+
+	/**
+	 * Returns the value of this Promise.
+	 * 
+	 * <p>
+	 * If this Promise is not {@link #isDone() resolved}, this method must block
+	 * and wait for this Promise to be resolved before completing.
+	 * 
+	 * <p>
+	 * If this Promise was successfully resolved, this method returns with the
+	 * value of this Promise. If this Promise was resolved with a failure, this
+	 * method must throw an {@code InvocationTargetException} with the
+	 * {@link #getFailure() failure exception} as the cause.
+	 * 
+	 * @return The value of this resolved Promise.
+	 * @throws InvocationTargetException If this Promise was resolved with a
+	 *         failure. The cause of the {@code InvocationTargetException} is
+	 *         the failure exception.
+	 * @throws InterruptedException If the current thread was interrupted while
+	 *         waiting.
+	 */
+	T getValue() throws InvocationTargetException, InterruptedException;
+
+	/**
+	 * Returns the failure of this Promise.
+	 * 
+	 * <p>
+	 * If this Promise is not {@link #isDone() resolved}, this method must block
+	 * and wait for this Promise to be resolved before completing.
+	 * 
+	 * <p>
+	 * If this Promise was resolved with a failure, this method returns with the
+	 * failure of this Promise. If this Promise was successfully resolved, this
+	 * method must return {@code null}.
+	 * 
+	 * @return The failure of this resolved Promise or {@code null} if this
+	 *         Promise was successfully resolved.
+	 * @throws InterruptedException If the current thread was interrupted while
+	 *         waiting.
+	 */
+	Throwable getFailure() throws InterruptedException;
+
+	/**
+	 * Register a callback to be called when this Promise is resolved.
+	 * 
+	 * <p>
+	 * The specified callback is called when this Promise is resolved either
+	 * successfully or with a failure.
+	 * 
+	 * <p>
+	 * This method may be called at any time including before and after this
+	 * Promise has been resolved.
+	 * 
+	 * <p>
+	 * Resolving this Promise <i>happens-before</i> any registered callback is
+	 * called. That is, in a registered callback, {@link #isDone()} must return
+	 * {@code true} and {@link #getValue()} and {@link #getFailure()} must not
+	 * block.
+	 * 
+	 * <p>
+	 * A callback may be called on a different thread than the thread which
+	 * registered the callback. So the callback must be thread safe but can rely
+	 * upon that the registration of the callback <i>happens-before</i> the
+	 * registered callback is called.
+	 * 
+	 * @param callback A callback to be called when this Promise is resolved.
+	 *        Must not be {@code null}.
+	 * @return This Promise.
+	 */
+	Promise<T> onResolve(Runnable callback);
+
+	/**
+	 * Chain a new Promise to this Promise with Success and Failure callbacks.
+	 * 
+	 * <p>
+	 * The specified {@link Success} callback is called when this Promise is
+	 * successfully resolved and the specified {@link Failure} callback is
+	 * called when this Promise is resolved with a failure.
+	 * 
+	 * <p>
+	 * This method returns a new Promise which is chained to this Promise. The
+	 * returned Promise must be resolved when this Promise is resolved after the
+	 * specified Success or Failure callback is executed. The result of the
+	 * executed callback must be used to resolve the returned Promise. Multiple
+	 * calls to this method can be used to create a chain of promises which are
+	 * resolved in sequence.
+	 * 
+	 * <p>
+	 * If this Promise is successfully resolved, the Success callback is
+	 * executed and the result Promise, if any, or thrown exception is used to
+	 * resolve the returned Promise from this method. If this Promise is
+	 * resolved with a failure, the Failure callback is executed and the
+	 * returned Promise from this method is failed.
+	 * 
+	 * <p>
+	 * This method may be called at any time including before and after this
+	 * Promise has been resolved.
+	 * 
+	 * <p>
+	 * Resolving this Promise <i>happens-before</i> any registered callback is
+	 * called. That is, in a registered callback, {@link #isDone()} must return
+	 * {@code true} and {@link #getValue()} and {@link #getFailure()} must not
+	 * block.
+	 * 
+	 * <p>
+	 * A callback may be called on a different thread than the thread which
+	 * registered the callback. So the callback must be thread safe but can rely
+	 * upon that the registration of the callback <i>happens-before</i> the
+	 * registered callback is called.
+	 * 
+	 * @param <R> The value type associated with the returned Promise.
+	 * @param success A Success callback to be called when this Promise is
+	 *        successfully resolved. May be {@code null} if no Success callback
+	 *        is required. In this case, the returned Promise must be resolved
+	 *        with the value {@code null} when this Promise is successfully
+	 *        resolved.
+	 * @param failure A Failure callback to be called when this Promise is
+	 *        resolved with a failure. May be {@code null} if no Failure
+	 *        callback is required.
+	 * @return A new Promise which is chained to this Promise. The returned
+	 *         Promise must be resolved when this Promise is resolved after the
+	 *         specified Success or Failure callback, if any, is executed.
+	 */
+	<R> Promise<R> then(Success<? super T, ? extends R> success, Failure failure);
+
+	/**
+	 * Chain a new Promise to this Promise with a Success callback.
+	 * 
+	 * <p>
+	 * This method performs the same function as calling
+	 * {@link #then(Success, Failure)} with the specified Success callback and
+	 * {@code null} for the Failure callback.
+	 * 
+	 * @param <R> The value type associated with the returned Promise.
+	 * @param success A Success callback to be called when this Promise is
+	 *        successfully resolved. May be {@code null} if no Success callback
+	 *        is required. In this case, the returned Promise must be resolved
+	 *        with the value {@code null} when this Promise is successfully
+	 *        resolved.
+	 * @return A new Promise which is chained to this Promise. The returned
+	 *         Promise must be resolved when this Promise is resolved after the
+	 *         specified Success, if any, is executed.
+	 * @see #then(Success, Failure)
+	 */
+	<R> Promise<R> then(Success<? super T, ? extends R> success);
+
+	/**
+	 * Filter the value of this Promise.
+	 * 
+	 * <p>
+	 * If this Promise is successfully resolved, the returned Promise will
+	 * either be resolved with the value of this Promise if the specified
+	 * Predicate accepts that value or failed with a
+	 * {@code NoSuchElementException} if the specified Predicate does not accept
+	 * that value. If the specified Predicate throws an exception, the returned
+	 * Promise will be failed with the exception.
+	 * 
+	 * <p>
+	 * If this Promise is resolved with a failure, the returned Promise will be
+	 * failed with that failure.
+	 * 
+	 * <p>
+	 * This method may be called at any time including before and after this
+	 * Promise has been resolved.
+	 * 
+	 * @param predicate The Predicate to evaluate the value of this Promise.
+	 *        Must not be {@code null}.
+	 * @return A Promise that filters the value of this Promise.
+	 */
+	Promise<T> filter(Predicate<? super T> predicate);
+
+	/**
+	 * Map the value of this Promise.
+	 * 
+	 * <p>
+	 * If this Promise is successfully resolved, the returned Promise will be
+	 * resolved with the value of specified Function as applied to the value of
+	 * this Promise. If the specified Function throws an exception, the returned
+	 * Promise will be failed with the exception.
+	 * 
+	 * <p>
+	 * If this Promise is resolved with a failure, the returned Promise will be
+	 * failed with that failure.
+	 * 
+	 * <p>
+	 * This method may be called at any time including before and after this
+	 * Promise has been resolved.
+	 * 
+	 * @param <R> The value type associated with the returned Promise.
+	 * @param mapper The Function that will map the value of this Promise to the
+	 *        value that will be used to resolve the returned Promise. Must not
+	 *        be {@code null}.
+	 * @return A Promise that returns the value of this Promise as mapped by the
+	 *         specified Function.
+	 */
+	<R> Promise<R> map(Function<? super T, ? extends R> mapper);
+
+	/**
+	 * FlatMap the value of this Promise.
+	 * 
+	 * <p>
+	 * If this Promise is successfully resolved, the returned Promise will be
+	 * resolved with the Promise from the specified Function as applied to the
+	 * value of this Promise. If the specified Function throws an exception, the
+	 * returned Promise will be failed with the exception.
+	 * 
+	 * <p>
+	 * If this Promise is resolved with a failure, the returned Promise will be
+	 * failed with that failure.
+	 * 
+	 * <p>
+	 * This method may be called at any time including before and after this
+	 * Promise has been resolved.
+	 * 
+	 * @param <R> The value type associated with the returned Promise.
+	 * @param mapper The Function that will flatMap the value of this Promise to
+	 *        a Promise that will be used to resolve the returned Promise. Must
+	 *        not be {@code null}.
+	 * @return A Promise that returns the value of this Promise as mapped by the
+	 *         specified Function.
+	 */
+	<R> Promise<R> flatMap(Function<? super T, Promise<? extends R>> mapper);
+
+	/**
+	 * Recover from a failure of this Promise with a recovery value.
+	 * 
+	 * <p>
+	 * If this Promise is successfully resolved, the returned Promise will be
+	 * resolved with the value of this Promise.
+	 * 
+	 * <p>
+	 * If this Promise is resolved with a failure, the specified Function is
+	 * applied to this Promise to produce a recovery value.
+	 * <ul>
+	 * <li>If the recovery value is not {@code null}, the returned Promise will
+	 * be resolved with the recovery value.</li>
+	 * <li>If the recovery value is {@code null}, the returned Promise will be
+	 * failed with the failure of this Promise.</li>
+	 * <li>If the specified Function throws an exception, the returned Promise
+	 * will be failed with that exception.</li>
+	 * </ul>
+	 * 
+	 * <p>
+	 * To recover from a failure of this Promise with a recovery value of
+	 * {@code null}, the {@link #recoverWith(Function)} method must be used. The
+	 * specified Function for {@link #recoverWith(Function)} can return
+	 * {@code Promises.resolved(null)} to supply the desired {@code null} value.
+	 * 
+	 * <p>
+	 * This method may be called at any time including before and after this
+	 * Promise has been resolved.
+	 * 
+	 * @param recovery If this Promise resolves with a failure, the specified
+	 *        Function is called to produce a recovery value to be used to
+	 *        resolve the returned Promise. Must not be {@code null}.
+	 * @return A Promise that resolves with the value of this Promise or
+	 *         recovers from the failure of this Promise.
+	 */
+	Promise<T> recover(Function<Promise<?>, ? extends T> recovery);
+
+	/**
+	 * Recover from a failure of this Promise with a recovery Promise.
+	 * 
+	 * <p>
+	 * If this Promise is successfully resolved, the returned Promise will be
+	 * resolved with the value of this Promise.
+	 * 
+	 * <p>
+	 * If this Promise is resolved with a failure, the specified Function is
+	 * applied to this Promise to produce a recovery Promise.
+	 * <ul>
+	 * <li>If the recovery Promise is not {@code null}, the returned Promise
+	 * will be resolved with the recovery Promise.</li>
+	 * <li>If the recovery Promise is {@code null}, the returned Promise will be
+	 * failed with the failure of this Promise.</li>
+	 * <li>If the specified Function throws an exception, the returned Promise
+	 * will be failed with that exception.</li>
+	 * </ul>
+	 * 
+	 * <p>
+	 * This method may be called at any time including before and after this
+	 * Promise has been resolved.
+	 * 
+	 * @param recovery If this Promise resolves with a failure, the specified
+	 *        Function is called to produce a recovery Promise to be used to
+	 *        resolve the returned Promise. Must not be {@code null}.
+	 * @return A Promise that resolves with the value of this Promise or
+	 *         recovers from the failure of this Promise.
+	 */
+	Promise<T> recoverWith(Function<Promise<?>, Promise<? extends T>> recovery);
+
+	/**
+	 * Fall back to the value of the specified Promise if this Promise fails.
+	 * 
+	 * <p>
+	 * If this Promise is successfully resolved, the returned Promise will be
+	 * resolved with the value of this Promise.
+	 * 
+	 * <p>
+	 * If this Promise is resolved with a failure, the successful result of the
+	 * specified Promise is used to resolve the returned Promise. If the
+	 * specified Promise is resolved with a failure, the returned Promise will
+	 * be failed with the failure of this Promise rather than the failure of the
+	 * specified Promise.
+	 * 
+	 * <p>
+	 * This method may be called at any time including before and after this
+	 * Promise has been resolved.
+	 * 
+	 * @param fallback The Promise whose value will be used to resolve the
+	 *        returned Promise if this Promise resolves with a failure. Must not
+	 *        be {@code null}.
+	 * @return A Promise that returns the value of this Promise or falls back to
+	 *         the value of the specified Promise.
+	 */
+	Promise<T> fallbackTo(Promise<? extends T> fallback);
+}
diff --git a/scr/src/main/java/org/osgi/util/promise/PromiseImpl.java b/scr/src/main/java/org/osgi/util/promise/PromiseImpl.java
new file mode 100644
index 0000000..1b01472
--- /dev/null
+++ b/scr/src/main/java/org/osgi/util/promise/PromiseImpl.java
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) OSGi Alliance (2014). 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.promise;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
+import org.osgi.util.function.Function;
+import org.osgi.util.function.Predicate;
+
+/**
+ * Promise implementation.
+ * 
+ * <p>
+ * This class is not used directly by clients. Clients should use
+ * {@link Deferred} to create a resolvable {@link Promise}.
+ * 
+ * @param <T> The result type associated with the Promise.
+ * 
+ * @ThreadSafe
+ * @author $Id: d8b44a36f3eb797316b213118192fac213fa0c59 $
+ */
+final class PromiseImpl<T> implements Promise<T> {
+	/**
+	 * A ConcurrentLinkedQueue to hold the callbacks for this Promise, so no
+	 * additional synchronization is required to write to or read from the
+	 * queue.
+	 */
+	private final ConcurrentLinkedQueue<Runnable>	callbacks;
+	/**
+	 * A CountDownLatch to manage the resolved state of this Promise.
+	 * 
+	 * <p>
+	 * This object is used as the synchronizing object to provide a critical
+	 * section in {@link #resolve(Object, Throwable)} so that only a single
+	 * thread can write the resolved state variables and open the latch.
+	 * 
+	 * <p>
+	 * The resolved state variables, {@link #value} and {@link #fail}, must only
+	 * be written when the latch is closed (getCount() != 0) and must only be
+	 * read when the latch is open (getCount() == 0). The latch state must
+	 * always be checked before writing or reading since the resolved state
+	 * variables' memory consistency is guarded by the latch.
+	 */
+	private final CountDownLatch					resolved;
+	/**
+	 * The value of this Promise if successfully resolved.
+	 * 
+	 * @GuardedBy("resolved")
+	 * @see #resolved
+	 */
+	private T										value;
+	/**
+	 * The failure of this Promise if resolved with a failure or {@code null} if
+	 * successfully resolved.
+	 * 
+	 * @GuardedBy("resolved")
+	 * @see #resolved
+	 */
+	private Throwable								fail;
+
+	/**
+	 * Initialize this Promise.
+	 */
+	PromiseImpl() {
+		callbacks = new ConcurrentLinkedQueue<Runnable>();
+		resolved = new CountDownLatch(1);
+	}
+
+	/**
+	 * Initialize and resolve this Promise.
+	 * 
+	 * @param v The value of this resolved Promise.
+	 * @param f The failure of this resolved Promise.
+	 */
+	PromiseImpl(T v, Throwable f) {
+		value = v;
+		fail = f;
+		callbacks = new ConcurrentLinkedQueue<Runnable>();
+		resolved = new CountDownLatch(0);
+	}
+
+	/**
+	 * Resolve this Promise.
+	 * 
+	 * @param v The value of this Promise.
+	 * @param f The failure of this Promise.
+	 */
+	void resolve(T v, Throwable f) {
+		// critical section: only one resolver at a time
+		synchronized (resolved) {
+			if (resolved.getCount() == 0) {
+				throw new IllegalStateException("Already resolved");
+			}
+			/*
+			 * The resolved state variables must be set before opening the
+			 * latch. This safely publishes them to be read by other threads
+			 * that must verify the latch is open before reading.
+			 */
+			value = v;
+			fail = f;
+			resolved.countDown();
+		}
+		notifyCallbacks(); // call any registered callbacks
+	}
+
+	/**
+	 * Call any registered callbacks if this Promise is resolved.
+	 */
+	private void notifyCallbacks() {
+		if (resolved.getCount() != 0) {
+			return; // return if not resolved
+		}
+
+		/*
+		 * Note: multiple threads can be in this method removing callbacks from
+		 * the queue and calling them, so the order in which callbacks are
+		 * called cannot be specified.
+		 */
+		for (Runnable callback = callbacks.poll(); callback != null; callback = callbacks.poll()) {
+			try {
+				callback.run();
+			} catch (Throwable t) {
+				Logger.logCallbackException(t);
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean isDone() {
+		return resolved.getCount() == 0;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public T getValue() throws InvocationTargetException, InterruptedException {
+		resolved.await();
+		if (fail == null) {
+			return value;
+		}
+		throw new InvocationTargetException(fail);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Throwable getFailure() throws InterruptedException {
+		resolved.await();
+		return fail;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Promise<T> onResolve(Runnable callback) {
+		callbacks.offer(callback);
+		notifyCallbacks(); // call any registered callbacks
+		return this;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public <R> Promise<R> then(Success<? super T, ? extends R> success, Failure failure) {
+		PromiseImpl<R> chained = new PromiseImpl<R>();
+		onResolve(new Then<R>(chained, success, failure));
+		return chained;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public <R> Promise<R> then(Success<? super T, ? extends R> success) {
+		return then(success, null);
+	}
+
+	/**
+	 * A callback used to chain promises for the {@link #then(Success, Failure)}
+	 * method.
+	 * 
+	 * @Immutable
+	 */
+	private final class Then<R> implements Runnable {
+		private final PromiseImpl<R>			chained;
+		private final Success<T, ? extends R>	success;
+		private final Failure					failure;
+
+		@SuppressWarnings("unchecked")
+		Then(PromiseImpl<R> chained, Success<? super T, ? extends R> success, Failure failure) {
+			this.chained = chained;
+			this.success = (Success<T, ? extends R>) success;
+			this.failure = failure;
+		}
+
+		public void run() {
+			Throwable f;
+			final boolean interrupted = Thread.interrupted();
+			try {
+				f = getFailure();
+			} catch (Throwable e) {
+				f = e; // propagate new exception
+			} finally {
+				if (interrupted) { // restore interrupt status
+					Thread.currentThread().interrupt();
+				}
+			}
+			if (f != null) {
+				if (failure != null) {
+					try {
+						failure.fail(PromiseImpl.this);
+					} catch (Throwable e) {
+						f = e; // propagate new exception
+					}
+				}
+				// fail chained
+				chained.resolve(null, f);
+				return;
+			}
+			Promise<? extends R> returned = null;
+			if (success != null) {
+				try {
+					returned = success.call(PromiseImpl.this);
+				} catch (Throwable e) {
+					chained.resolve(null, e);
+					return;
+				}
+			}
+			if (returned == null) {
+				// resolve chained with null value
+				chained.resolve(null, null);
+			} else {
+				// resolve chained when returned promise is resolved
+				returned.onResolve(new Chain<R>(chained, returned));
+			}
+		}
+	}
+
+	/**
+	 * A callback used to resolve the chained Promise when the Promise promise
+	 * is resolved.
+	 * 
+	 * @Immutable
+	 */
+	private final static class Chain<R> implements Runnable {
+		private final PromiseImpl<R>		chained;
+		private final Promise<? extends R>	promise;
+		private final Throwable				failure;
+
+		Chain(PromiseImpl<R> chained, Promise<? extends R> promise) {
+			this.chained = chained;
+			this.promise = promise;
+			this.failure = null;
+		}
+
+		Chain(PromiseImpl<R> chained, Promise<? extends R> promise, Throwable failure) {
+			this.chained = chained;
+			this.promise = promise;
+			this.failure = failure;
+		}
+
+		public void run() {
+			R value = null;
+			Throwable f;
+			final boolean interrupted = Thread.interrupted();
+			try {
+				f = promise.getFailure();
+				if (f == null) {
+					value = promise.getValue();
+				} else if (failure != null) {
+					f = failure;
+				}
+			} catch (Throwable e) {
+				f = e; // propagate new exception
+			} finally {
+				if (interrupted) { // restore interrupt status
+					Thread.currentThread().interrupt();
+				}
+			}
+			chained.resolve(value, f);
+		}
+	}
+
+	/**
+	 * Resolve this Promise with the specified Promise.
+	 * 
+	 * <p>
+	 * If the specified Promise is successfully resolved, this Promise is
+	 * resolved with the value of the specified Promise. If the specified
+	 * Promise is resolved with a failure, this Promise is resolved with the
+	 * failure of the specified Promise.
+	 * 
+	 * @param with A Promise whose value or failure will be used to resolve this
+	 *        Promise. Must not be {@code null}.
+	 * @return A Promise that is resolved only when this Promise is resolved by
+	 *         the specified Promise. The returned Promise will be successfully
+	 *         resolved, with the value {@code null}, if this Promise was
+	 *         resolved by the specified Promise. The returned Promise will be
+	 *         resolved with a failure of {@link IllegalStateException} if this
+	 *         Promise was already resolved when the specified Promise was
+	 *         resolved.
+	 */
+	Promise<Void> resolveWith(Promise<? extends T> with) {
+		PromiseImpl<Void> chained = new PromiseImpl<Void>();
+		ResolveWith resolveWith = new ResolveWith(chained);
+		with.then(resolveWith, resolveWith);
+		return chained;
+	}
+
+	/**
+	 * A callback used to resolve this Promise with another Promise for the
+	 * {@link PromiseImpl#resolveWith(Promise)} method.
+	 * 
+	 * @Immutable
+	 */
+	private final class ResolveWith implements Success<T, Void>, Failure {
+		private final PromiseImpl<Void>	chained;
+
+		ResolveWith(PromiseImpl<Void> chained) {
+			this.chained = chained;
+		}
+
+		public Promise<Void> call(Promise<T> with) throws Exception {
+			try {
+				resolve(with.getValue(), null);
+			} catch (Throwable e) {
+				chained.resolve(null, e);
+				return null;
+			}
+			chained.resolve(null, null);
+			return null;
+		}
+
+		public void fail(Promise<?> with) throws Exception {
+			try {
+				resolve(null, with.getFailure());
+			} catch (Throwable e) {
+				chained.resolve(null, e);
+				return;
+			}
+			chained.resolve(null, null);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Promise<T> filter(Predicate<? super T> predicate) {
+		return then(new Filter<T>(predicate));
+	}
+
+	/**
+	 * A callback used by the {@link PromiseImpl#filter(Predicate)} method.
+	 * 
+	 * @Immutable
+	 */
+	private static final class Filter<T> implements Success<T, T> {
+		private final Predicate<? super T>	predicate;
+
+		Filter(Predicate<? super T> predicate) {
+			this.predicate = requireNonNull(predicate);
+		}
+
+		public Promise<T> call(Promise<T> resolved) throws Exception {
+			if (predicate.test(resolved.getValue())) {
+				return resolved;
+			}
+			throw new NoSuchElementException();
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public <R> Promise<R> map(Function<? super T, ? extends R> mapper) {
+		return then(new Map<T, R>(mapper));
+	}
+
+	/**
+	 * A callback used by the {@link PromiseImpl#map(Function)} method.
+	 * 
+	 * @Immutable
+	 */
+	private static final class Map<T, R> implements Success<T, R> {
+		private final Function<? super T, ? extends R>	mapper;
+
+		Map(Function<? super T, ? extends R> mapper) {
+			this.mapper = requireNonNull(mapper);
+		}
+
+		public Promise<R> call(Promise<T> resolved) throws Exception {
+			return new PromiseImpl<R>(mapper.apply(resolved.getValue()), null);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public <R> Promise<R> flatMap(Function<? super T, Promise<? extends R>> mapper) {
+		return then(new FlatMap<T, R>(mapper));
+	}
+
+	/**
+	 * A callback used by the {@link PromiseImpl#flatMap(Function)} method.
+	 * 
+	 * @Immutable
+	 */
+	private static final class FlatMap<T, R> implements Success<T, R> {
+		private final Function<? super T, Promise<? extends R>>	mapper;
+
+		FlatMap(Function<? super T, Promise<? extends R>> mapper) {
+			this.mapper = requireNonNull(mapper);
+		}
+
+		@SuppressWarnings("unchecked")
+		public Promise<R> call(Promise<T> resolved) throws Exception {
+			return (Promise<R>) mapper.apply(resolved.getValue());
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Promise<T> recover(Function<Promise<?>, ? extends T> recovery) {
+		PromiseImpl<T> chained = new PromiseImpl<T>();
+		Recover<T> recover = new Recover<T>(chained, recovery);
+		then(recover, recover);
+		return chained;
+	}
+
+	/**
+	 * A callback used by the {@link PromiseImpl#recover(Function)} method.
+	 * 
+	 * @Immutable
+	 */
+	private static final class Recover<T> implements Success<T, Void>, Failure {
+		private final PromiseImpl<T>					chained;
+		private final Function<Promise<?>, ? extends T>	recovery;
+
+		Recover(PromiseImpl<T> chained, Function<Promise<?>, ? extends T> recovery) {
+			this.chained = chained;
+			this.recovery = requireNonNull(recovery);
+		}
+
+		public Promise<Void> call(Promise<T> resolved) throws Exception {
+			T value;
+			try {
+				value = resolved.getValue();
+			} catch (Throwable e) {
+				chained.resolve(null, e);
+				return null;
+			}
+			chained.resolve(value, null);
+			return null;
+		}
+
+		public void fail(Promise<?> resolved) throws Exception {
+			T recovered;
+			Throwable failure;
+			try {
+				recovered = recovery.apply(resolved);
+				failure = resolved.getFailure();
+			} catch (Throwable e) {
+				chained.resolve(null, e);
+				return;
+			}
+			if (recovered == null) {
+				chained.resolve(null, failure);
+			} else {
+				chained.resolve(recovered, null);
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Promise<T> recoverWith(Function<Promise<?>, Promise<? extends T>> recovery) {
+		PromiseImpl<T> chained = new PromiseImpl<T>();
+		RecoverWith<T> recoverWith = new RecoverWith<T>(chained, recovery);
+		then(recoverWith, recoverWith);
+		return chained;
+	}
+
+	/**
+	 * A callback used by the {@link PromiseImpl#recoverWith(Function)} method.
+	 * 
+	 * @Immutable
+	 */
+	private static final class RecoverWith<T> implements Success<T, Void>, Failure {
+		private final PromiseImpl<T>								chained;
+		private final Function<Promise<?>, Promise<? extends T>>	recovery;
+
+		RecoverWith(PromiseImpl<T> chained, Function<Promise<?>, Promise<? extends T>> recovery) {
+			this.chained = chained;
+			this.recovery = requireNonNull(recovery);
+		}
+
+		public Promise<Void> call(Promise<T> resolved) throws Exception {
+			T value;
+			try {
+				value = resolved.getValue();
+			} catch (Throwable e) {
+				chained.resolve(null, e);
+				return null;
+			}
+			chained.resolve(value, null);
+			return null;
+		}
+
+		public void fail(Promise<?> resolved) throws Exception {
+			Promise<? extends T> recovered;
+			Throwable failure;
+			try {
+				recovered = recovery.apply(resolved);
+				failure = resolved.getFailure();
+			} catch (Throwable e) {
+				chained.resolve(null, e);
+				return;
+			}
+			if (recovered == null) {
+				chained.resolve(null, failure);
+			} else {
+				recovered.onResolve(new Chain<T>(chained, recovered));
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Promise<T> fallbackTo(Promise<? extends T> fallback) {
+		PromiseImpl<T> chained = new PromiseImpl<T>();
+		FallbackTo<T> fallbackTo = new FallbackTo<T>(chained, fallback);
+		then(fallbackTo, fallbackTo);
+		return chained;
+	}
+
+	/**
+	 * A callback used by the {@link PromiseImpl#fallbackTo(Promise)} method.
+	 * 
+	 * @Immutable
+	 */
+	private static final class FallbackTo<T> implements Success<T, Void>, Failure {
+		private final PromiseImpl<T>		chained;
+		private final Promise<? extends T>	fallback;
+
+		FallbackTo(PromiseImpl<T> chained, Promise<? extends T> fallback) {
+			this.chained = chained;
+			this.fallback = requireNonNull(fallback);
+		}
+
+		public Promise<Void> call(Promise<T> resolved) throws Exception {
+			T value;
+			try {
+				value = resolved.getValue();
+			} catch (Throwable e) {
+				chained.resolve(null, e);
+				return null;
+			}
+			chained.resolve(value, null);
+			return null;
+		}
+
+		public void fail(Promise<?> resolved) throws Exception {
+			Throwable failure;
+			try {
+				failure = resolved.getFailure();
+			} catch (Throwable e) {
+				chained.resolve(null, e);
+				return;
+			}
+			fallback.onResolve(new Chain<T>(chained, fallback, failure));
+		}
+	}
+
+	static <V> V requireNonNull(V value) {
+		if (value != null) {
+			return value;
+		}
+		throw new NullPointerException();
+	}
+
+	/**
+	 * Use the lazy initialization holder class idiom to delay creating a Logger
+	 * until we actually need it.
+	 */
+	private static final class Logger {
+		private final static java.util.logging.Logger	LOGGER;
+		static {
+			LOGGER = java.util.logging.Logger.getLogger(PromiseImpl.class.getName());
+		}
+
+		static void logCallbackException(Throwable t) {
+			LOGGER.log(java.util.logging.Level.WARNING, "Exception from Promise callback", t);
+		}
+	}
+}
diff --git a/scr/src/main/java/org/osgi/util/promise/Promises.java b/scr/src/main/java/org/osgi/util/promise/Promises.java
new file mode 100644
index 0000000..4be25c0
--- /dev/null
+++ b/scr/src/main/java/org/osgi/util/promise/Promises.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) OSGi Alliance (2014). 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.promise;
+
+import static org.osgi.util.promise.PromiseImpl.requireNonNull;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Static helper methods for {@link Promise}s.
+ * 
+ * @ThreadSafe
+ * @author $Id: 6ad9c7cca5a98dbddd87db8417df51bf6e008922 $
+ */
+public class Promises {
+	private Promises() {
+		// disallow object creation
+	}
+
+	/**
+	 * Create a new Promise that has been resolved with the specified value.
+	 * 
+	 * @param <T> The value type associated with the returned Promise.
+	 * @param value The value of the resolved Promise.
+	 * @return A new Promise that has been resolved with the specified value.
+	 */
+	public static <T> Promise<T> resolved(T value) {
+		return new PromiseImpl<T>(value, null);
+	}
+
+	/**
+	 * Create a new Promise that has been resolved with the specified failure.
+	 * 
+	 * @param <T> The value type associated with the returned Promise.
+	 * @param failure The failure of the resolved Promise. Must not be
+	 *        {@code null}.
+	 * @return A new Promise that has been resolved with the specified failure.
+	 */
+	public static <T> Promise<T> failed(Throwable failure) {
+		return new PromiseImpl<T>(null, requireNonNull(failure));
+	}
+
+	/**
+	 * Create a new Promise that is a latch on the resolution of the specified
+	 * Promises.
+	 * 
+	 * <p>
+	 * The new Promise acts as a gate and must be resolved after all of the
+	 * specified Promises are resolved.
+	 * 
+	 * @param <T> The value type of the List value associated with the returned
+	 *        Promise.
+	 * @param <S> A subtype of the value type of the List value associated with
+	 *        the returned Promise.
+	 * @param promises The Promises which must be resolved before the returned
+	 *        Promise must be resolved. Must not be {@code null} and all of the
+	 *        elements in the collection must not be {@code null}.
+	 * @return A Promise that is resolved only when all the specified Promises
+	 *         are resolved. The returned Promise will be successfully resolved,
+	 *         with a List of the values in the order of the specified Promises,
+	 *         if all the specified Promises are successfully resolved. The List
+	 *         in the returned Promise is the property of the caller and is
+	 *         modifiable. The returned Promise will be resolved with a failure
+	 *         of {@link FailedPromisesException} if any of the specified
+	 *         Promises are resolved with a failure. The failure
+	 *         {@link FailedPromisesException} must contain all of the specified
+	 *         Promises which resolved with a failure.
+	 */
+	public static <T, S extends T> Promise<List<T>> all(Collection<Promise<S>> promises) {
+		if (promises.isEmpty()) {
+			List<T> result = new ArrayList<T>();
+			return resolved(result);
+		}
+		/* make a copy and capture the ordering */
+		List<Promise<? extends T>> list = new ArrayList<Promise<? extends T>>(promises);
+		PromiseImpl<List<T>> chained = new PromiseImpl<List<T>>();
+		All<T> all = new All<T>(chained, list);
+		for (Promise<? extends T> promise : list) {
+			promise.onResolve(all);
+		}
+		return chained;
+	}
+
+	/**
+	 * Create a new Promise that is a latch on the resolution of the specified
+	 * Promises.
+	 * 
+	 * <p>
+	 * The new Promise acts as a gate and must be resolved after all of the
+	 * specified Promises are resolved.
+	 * 
+	 * @param <T> The value type associated with the specified Promises.
+	 * @param promises The Promises which must be resolved before the returned
+	 *        Promise must be resolved. Must not be {@code null} and all of the
+	 *        arguments must not be {@code null}.
+	 * @return A Promise that is resolved only when all the specified Promises
+	 *         are resolved. The returned Promise will be successfully resolved,
+	 *         with a List of the values in the order of the specified Promises,
+	 *         if all the specified Promises are successfully resolved. The List
+	 *         in the returned Promise is the property of the caller and is
+	 *         modifiable. The returned Promise will be resolved with a failure
+	 *         of {@link FailedPromisesException} if any of the specified
+	 *         Promises are resolved with a failure. The failure
+	 *         {@link FailedPromisesException} must contain all of the specified
+	 *         Promises which resolved with a failure.
+	 */
+	public static <T> Promise<List<T>> all(Promise<? extends T>... promises) {
+		@SuppressWarnings("unchecked")
+		List<Promise<T>> list = Arrays.asList((Promise<T>[]) promises);
+		return all(list);
+	}
+
+	/**
+	 * A callback used to resolve a Promise when the specified list of Promises
+	 * are resolved for the {@link Promises#all(Collection)} method.
+	 * 
+	 * @ThreadSafe
+	 */
+	private static final class All<T> implements Runnable {
+		private final PromiseImpl<List<T>>			chained;
+		private final List<Promise<? extends T>>	promises;
+		private final AtomicInteger					promiseCount;
+
+		All(PromiseImpl<List<T>> chained, List<Promise<? extends T>> promises) {
+			this.chained = chained;
+			this.promises = promises;
+			this.promiseCount = new AtomicInteger(promises.size());
+		}
+
+		public void run() {
+			if (promiseCount.decrementAndGet() != 0) {
+				return;
+			}
+			List<T> result = new ArrayList<T>(promises.size());
+			List<Promise<?>> failed = new ArrayList<Promise<?>>(promises.size());
+			Throwable cause = null;
+			for (Promise<? extends T> promise : promises) {
+				Throwable failure;
+				T value;
+				try {
+					failure = promise.getFailure();
+					value = (failure != null) ? null : promise.getValue();
+				} catch (Throwable e) {
+					chained.resolve(null, e);
+					return;
+				}
+				if (failure != null) {
+					failed.add(promise);
+					if (cause == null) {
+						cause = failure;
+					}
+				} else {
+					result.add(value);
+				}
+			}
+			if (failed.isEmpty()) {
+				chained.resolve(result, null);
+			} else {
+				chained.resolve(null, new FailedPromisesException(failed, cause));
+			}
+		}
+	}
+}
diff --git a/scr/src/main/java/org/osgi/util/promise/Success.java b/scr/src/main/java/org/osgi/util/promise/Success.java
new file mode 100644
index 0000000..7f47c4e
--- /dev/null
+++ b/scr/src/main/java/org/osgi/util/promise/Success.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) OSGi Alliance (2014). 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.promise;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * Success callback for a Promise.
+ * 
+ * <p>
+ * A Success callback is registered with a {@link Promise} using the
+ * {@link Promise#then(Success)} method and is called if the Promise is resolved
+ * successfully.
+ * 
+ * <p>
+ * This is a functional interface and can be used as the assignment target for a
+ * lambda expression or method reference.
+ * 
+ * @param <T> The value type of the resolved Promise passed as input to this
+ *        callback.
+ * @param <R> The value type of the returned Promise from this callback.
+ * 
+ * @ThreadSafe
+ * @author $Id: 58eef5ba732ef999d57a1feaaf1e5229356647e3 $
+ */
+@ConsumerType
+public interface Success<T, R> {
+	/**
+	 * Success callback for a Promise.
+	 * 
+	 * <p>
+	 * This method is called if the Promise with which it is registered resolves
+	 * successfully.
+	 * 
+	 * <p>
+	 * In the remainder of this description we will refer to the Promise
+	 * returned by this method as the returned Promise and the Promise returned
+	 * by {@link Promise#then(Success)} when this Success callback was
+	 * registered as the chained Promise.
+	 * 
+	 * <p>
+	 * If the returned Promise is {@code null} then the chained Promise will
+	 * resolve immediately with a successful value of {@code null}. If the
+	 * returned Promise is not {@code null} then the chained Promise will be
+	 * resolved when the returned Promise is resolved.
+	 * 
+	 * @param resolved The successfully resolved {@link Promise}.
+	 * @return The Promise to use to resolve the chained Promise, or
+	 *         {@code null} if the chained Promise is to be resolved immediately
+	 *         with the value {@code null}.
+	 * @throws Exception The chained Promise will be failed with the thrown
+	 *         exception.
+	 */
+	Promise<R> call(Promise<T> resolved) throws Exception;
+}
diff --git a/scr/src/main/java/org/osgi/util/promise/package-info.java b/scr/src/main/java/org/osgi/util/promise/package-info.java
new file mode 100644
index 0000000..054282c
--- /dev/null
+++ b/scr/src/main/java/org/osgi/util/promise/package-info.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) OSGi Alliance (2014). 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.
+ */
+
+/**
+ * Promise Package Version 1.0.
+ * 
+ * <p>
+ * Bundles wishing to use this package must list the package in the
+ * Import-Package header of the bundle's manifest.
+ * 
+ * <p>
+ * Example import for consumers using the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.util.promise; version="[1.0,2.0)"}
+ * <p>
+ * Example import for providers implementing the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.util.promise; version="[1.0,1.1)"}
+ * 
+ * @author $Id: 5a3ec65d3b7e7ebdd2278d75675b8a808e6cb2bf $
+ */
+
+@Version("1.0")
+package org.osgi.util.promise;
+
+import org.osgi.annotation.versioning.Version;
+
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/CircularReferenceTest.java b/scr/src/test/java/org/apache/felix/scr/integration/CircularReferenceTest.java
index c046817..cc776c8 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/CircularReferenceTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/CircularReferenceTest.java
@@ -121,7 +121,7 @@
      * A > 1.1 > B > 0..n > A Both should start, but B should not have an A reference.
      */
     @Test
-    public void test_A11_B0n_delayed_B_first() throws InvalidSyntaxException
+    public void test_A11_B0n_delayed_B_first() throws Exception
     {
         String componentNameA = "4.A.1.1.dynamic";
         ComponentConfigurationDTO componentA = findComponentConfigurationByName( componentNameA, ComponentConfigurationDTO.SATISFIED );
@@ -225,7 +225,7 @@
      * A > 1.1 > B > 0..1 > A Both should start, but B should not have an A reference.
      */
     @Test
-    public void test_A11_B01_delayed_B_first() throws InvalidSyntaxException
+    public void test_A11_B01_delayed_B_first() throws Exception
     {
         String componentNameA = "7.A.1.1.dynamic";
         ComponentConfigurationDTO componentA = findComponentConfigurationByName( componentNameA, ComponentConfigurationDTO.SATISFIED );
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentActivationTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentActivationTest.java
index 7123198..4f296fe 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentActivationTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentActivationTest.java
@@ -45,7 +45,7 @@
 
 
     @Test
-    public void test_activator_not_declared()
+    public void test_activator_not_declared() throws Exception
     {
         final String componentname = "ActivatorComponent.no.decl";
 
@@ -56,7 +56,7 @@
 
 
     @Test //Changed to expect SATISFIED rather than unsatisfied
-    public void test_activate_missing()
+    public void test_activate_missing() throws Exception
     {
         final String componentname = "ActivatorComponent.activate.missing";
 
@@ -68,7 +68,7 @@
 
 
     @Test
-    public void test_deactivate_missing()
+    public void test_deactivate_missing() throws Exception
     {
         final String componentname = "ActivatorComponent.deactivate.missing";
 
@@ -79,7 +79,7 @@
 
 
     @Test
-    public void test_activator_declared()
+    public void test_activator_declared() throws Exception
     {
         final String componentname = "ActivatorComponent.decl";
 
@@ -90,7 +90,7 @@
 
 
     @Test // Failure to activate does not mean the state should change to unsatisfied.
-    public void test_activate_fail()
+    public void test_activate_fail() throws Exception
     {
         final String componentname = "ActivatorComponent.activate.fail";
 
@@ -102,7 +102,7 @@
 
 
     @Test
-    public void test_deactivate_fail()
+    public void test_deactivate_fail() throws Exception
     {
         final String componentname = "ActivatorComponent.deactivate.fail";
 
@@ -113,7 +113,7 @@
 
 
     @Test
-    public void test_activate_register_service()
+    public void test_activate_register_service() throws Exception
     {
         final String componentname = "ActivatorComponent.activate.with.bind";
 
@@ -129,7 +129,7 @@
 
 
     @Test
-    public void test_activate_register_service_delayed()
+    public void test_activate_register_service_delayed() throws Exception
     {
         final String componentname = "ActivatorComponent.activate.delayed.with.bind";
 
@@ -143,7 +143,7 @@
     }
     
     @Test
-    public void test_activate_service_factory_register_service()
+    public void test_activate_service_factory_register_service() throws Exception
     {
         final String componentname = "ActivatorComponent.activate.service.factory.with.bind";
 
@@ -157,7 +157,7 @@
     }
     
     @Test
-    public void test_activate_register_service_single_static_dependency()
+    public void test_activate_register_service_single_static_dependency() throws Exception
     {
         final String componentname = "ActivatorComponent.bind.single.static";
 
@@ -165,7 +165,7 @@
     }
 
     @Test
-    public void test_activate_register_service_multiple_static_reluctant_dependency()
+    public void test_activate_register_service_multiple_static_reluctant_dependency() throws Exception
     {
         final String componentname = "ActivatorComponent.bind.multiple.static.reluctant";
 
@@ -173,7 +173,7 @@
     }
 
     @Test
-    public void test_activate_register_service_multiple_static_greedy_dependency()
+    public void test_activate_register_service_multiple_static_greedy_dependency() throws Exception
     {
         final String componentname = "ActivatorComponent.bind.multiple.static.greedy";
 
@@ -181,7 +181,7 @@
     }
 
     @Test
-    public void test_activate_register_service_single_dynamic_dependency()
+    public void test_activate_register_service_single_dynamic_dependency() throws Exception
     {
         final String componentname = "ActivatorComponent.bind.single.dynamic";
 
@@ -189,7 +189,7 @@
     }
 
     @Test
-    public void test_activate_register_service_multiple_dynamic_dependency()
+    public void test_activate_register_service_multiple_dynamic_dependency() throws Exception
     {
         final String componentname = "ActivatorComponent.bind.multiple.dynamic";
 
@@ -197,7 +197,7 @@
     }
 
 
-    private void testRequiredDependency(final String componentname)
+    private void testRequiredDependency(final String componentname) throws Exception
     {
         ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(componentname, ComponentConfigurationDTO.UNSATISFIED);
 
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConcurrencyTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConcurrencyTest.java
index 9e1bf32..9c407bd 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConcurrencyTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConcurrencyTest.java
@@ -52,7 +52,7 @@
     }
 
     @Test
-    public void test_concurrent_component_activation_using_componentFactories()
+    public void test_concurrent_component_activation_using_componentFactories() throws Exception
     {
 
 
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationPidTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationPidTest.java
index 98653d8..8a904d3 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationPidTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationPidTest.java
@@ -40,7 +40,7 @@
     }
 
     @Test
-    public void test_configurationpid_use_other_pid()
+    public void test_configurationpid_use_other_pid() throws Exception
     {
         final String pid = "ConfigurationPid.otherPid";
         final String name = "ConfigurationPid.componentName";
@@ -70,7 +70,7 @@
     }
     
     @Test
-    public void test_configurationpid_must_not_use_name_as_pid()
+    public void test_configurationpid_must_not_use_name_as_pid() throws Exception
     {
         final String name = "ConfigurationPid.componentName";
         final String pid = name;
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java
index c767a80..813267d 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java
@@ -46,7 +46,7 @@
 
 
     @Test
-    public void test_SimpleComponent_configuration_ignore()
+    public void test_SimpleComponent_configuration_ignore() throws Exception
     {
         final String pid = "SimpleComponent.configuration.ignore";
         TestCase.assertNull( SimpleComponent.INSTANCE );
@@ -79,7 +79,7 @@
 
 
     @Test
-    public void test_SimpleComponent_configuration_optional()
+    public void test_SimpleComponent_configuration_optional() throws Exception
     {
         final String pid = "SimpleComponent.configuration.optional";
         ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(pid, ComponentConfigurationDTO.ACTIVE);
@@ -116,7 +116,7 @@
 
 
     @Test
-    public void test_SimpleComponent_configuration_require()
+    public void test_SimpleComponent_configuration_require() throws Exception
     {
         final String pid = "SimpleComponent.configuration.require";
 
@@ -149,7 +149,7 @@
      * same as test_SimpleComponent_configuration_require except configuration is present when component is enabled.
      */
     @Test
-    public void test_SimpleComponent_configuration_require_initialize()
+    public void test_SimpleComponent_configuration_require_initialize() throws Exception
     {
         final String pid = "SimpleComponent.configuration.require";
 
@@ -176,7 +176,7 @@
 
 
     @Test
-    public void test_SimpleComponent_dynamic_configuration()
+    public void test_SimpleComponent_dynamic_configuration() throws Exception
     {
         final String pid = "DynamicConfigurationComponent";
         boolean pre13 = true;
@@ -185,7 +185,7 @@
     }
 
     @Test
-    public void test_SimpleComponent_dynamic_configuration_13()
+    public void test_SimpleComponent_dynamic_configuration_13() throws Exception
     {
         final String pid = "DynamicConfigurationComponent13";
         boolean pre13 = false;
@@ -194,7 +194,7 @@
     }
     
     @Test
-    public void test_SimpleComponent_dynamic_configuration_flag()
+    public void test_SimpleComponent_dynamic_configuration_flag() throws Exception
     {
         final String pid = "DynamicConfigurationComponentFlag";
         boolean pre13 = true;
@@ -203,7 +203,8 @@
     }
 
 
-	private void dynamicConfigTest(final String pid, boolean pre13, boolean recreateOnDelete) {
+	private void dynamicConfigTest(final String pid, boolean pre13, boolean recreateOnDelete)  throws Exception
+	{
 	    Object pidWithout;
 	    Object pidWith;
 	    if (pre13)
@@ -256,7 +257,7 @@
 
 
     @Test
-    public void test_SimpleComponent_dynamic_optional_configuration_with_required_service()
+    public void test_SimpleComponent_dynamic_optional_configuration_with_required_service() throws Exception
     {
         final String targetProp = "ref.target";
         final String filterProp = "required";
@@ -331,7 +332,7 @@
      * to (still) match the other one.  2nd service should remain bound.
      */
     @Test
-    public void test_SimpleComponent_dynamic_optional_configuration_with_required_service2()
+    public void test_SimpleComponent_dynamic_optional_configuration_with_required_service2() throws Exception
     {
         final String targetProp = "ref.target";
         final String filterProp1 = "one";
@@ -494,7 +495,7 @@
 
 
     @Test
-    public void test_SimpleComponent_factory_configuration()
+    public void test_SimpleComponent_factory_configuration() throws Exception
     {
         final String factoryPid = "FactoryConfigurationComponent";
 
@@ -530,7 +531,7 @@
      * component is enabled to test initialization.
      */
     @Test
-    public void test_SimpleComponent_factory_configuration_initialize()
+    public void test_SimpleComponent_factory_configuration_initialize() throws Exception
     {
         final String factoryPid = "FactoryConfigurationComponent";
 
@@ -558,7 +559,7 @@
     }
 
     @Test
-    public void test_SimpleComponent_factory_configuration_enabled()
+    public void test_SimpleComponent_factory_configuration_enabled() throws Exception
     {
         final String factoryPid = "FactoryConfigurationComponent_enabled";
 
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentDisposeTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentDisposeTest.java
index cc808e5..527db36 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentDisposeTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentDisposeTest.java
@@ -45,7 +45,7 @@
 
 
     @Test
-    public void test_SimpleComponent_factory_configuration()
+    public void test_SimpleComponent_factory_configuration() throws Exception
     {
         final String factoryPid = "FactoryConfigurationComponent";
 
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java
index 249de17..76d540b 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java
@@ -52,7 +52,7 @@
     }
 
     @Test
-    public void test_component_factory() throws InvalidSyntaxException
+    public void test_component_factory() throws Exception
     {
         final String componentname = "factory.component";
         final String componentfactory = "factory.component.factory";
@@ -76,7 +76,7 @@
 
 
     @Test
-    public void test_component_factory_disable_factory() throws InvalidSyntaxException
+    public void test_component_factory_disable_factory() throws Exception
     {
         // tests components remain alive after factory has been disabled
 
@@ -106,7 +106,7 @@
 
 
     @Test
-    public void test_component_factory_newInstance_failure() throws InvalidSyntaxException
+    public void test_component_factory_newInstance_failure() throws Exception
     {
         final String componentname = "factory.component";
         final String componentfactory = "factory.component.factory";
@@ -132,7 +132,7 @@
 
 
     @Test
-    public void test_component_factory_require_configuration() throws InvalidSyntaxException
+    public void test_component_factory_require_configuration() throws Exception
     {
         final String componentname = "factory.component.configuration";
         final String componentfactory = "factory.component.factory.configuration";
@@ -188,7 +188,7 @@
 
 
     @Test
-    public void test_component_factory_reference() throws InvalidSyntaxException
+    public void test_component_factory_reference() throws Exception
     {
         final String componentname = "factory.component.reference";
         final String componentfactory = "factory.component.factory.reference";
@@ -274,7 +274,7 @@
     }
 
     @Test
-    public void test_component_factory_referredTo() throws InvalidSyntaxException
+    public void test_component_factory_referredTo() throws Exception
     {
         //set up the component that refers to the service the factory will create.
         final String referringComponentName = "ComponentReferringToFactoryObject";
@@ -306,7 +306,7 @@
     }
 
     @Test
-    public void test_component_factory_with_target_filters() throws InvalidSyntaxException
+    public void test_component_factory_with_target_filters() throws Exception
     {
         final String componentfactory = "factory.component.reference.targetfilter";
         getConfigurationsDisabledThenEnable(componentfactory, 0, -1);
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
index 64b5b0c..7a03baf 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
@@ -39,6 +39,7 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -297,7 +298,7 @@
     	STATES.put(ComponentConfigurationDTO.ACTIVE, "Active (" + ComponentConfigurationDTO.ACTIVE + ")" );
     }
     
-    protected ComponentConfigurationDTO getDisabledConfigurationAndEnable( Bundle b, String name, int initialState )
+    protected ComponentConfigurationDTO getDisabledConfigurationAndEnable( Bundle b, String name, int initialState ) throws InvocationTargetException, InterruptedException
     {
     	int count = 1;
         Collection<ComponentConfigurationDTO> ccs = getConfigurationsDisabledThenEnable(
@@ -306,12 +307,12 @@
     	return cc;
     }
     
-    protected ComponentConfigurationDTO getDisabledConfigurationAndEnable( String name, int initialState )
+    protected ComponentConfigurationDTO getDisabledConfigurationAndEnable( String name, int initialState ) throws InvocationTargetException, InterruptedException
     {
     	return getDisabledConfigurationAndEnable( bundle, name, initialState );
     }
 
-    protected Collection<ComponentConfigurationDTO> getConfigurationsDisabledThenEnable( Bundle b, String name, int count, int initialState) 
+    protected Collection<ComponentConfigurationDTO> getConfigurationsDisabledThenEnable( Bundle b, String name, int count, int initialState) throws InvocationTargetException, InterruptedException 
     {
 		ServiceComponentRuntime scr = scrTracker.getService();
         if ( scr == null )
@@ -320,8 +321,7 @@
         }
     	ComponentDescriptionDTO cd = scr.getComponentDescriptionDTO(b, name);
     	Assert.assertFalse("Expected component disabled", scr.isComponentEnabled(cd));
-    	scr.enableComponent(cd);
-    	delay();//??
+    	scr.enableComponent(cd).getValue();
     	Assert.assertTrue("Expected component enabled", scr.isComponentEnabled(cd));
     	
     	Collection<ComponentConfigurationDTO> ccs = scr.getComponentConfigurationDTOs(cd);
@@ -334,7 +334,7 @@
 		return ccs;
 	}
     
-    protected Collection<ComponentConfigurationDTO> getConfigurationsDisabledThenEnable( String name, int count, int initialState) 
+    protected Collection<ComponentConfigurationDTO> getConfigurationsDisabledThenEnable( String name, int count, int initialState) throws InvocationTargetException, InterruptedException 
     {
     	return getConfigurationsDisabledThenEnable(bundle, name, count, initialState);
     }
@@ -386,12 +386,12 @@
 		}
     }
     
-    protected void enableAndCheck( ComponentDescriptionDTO cd )
+    protected void enableAndCheck( ComponentDescriptionDTO cd ) throws InvocationTargetException, InterruptedException
     {
         ServiceComponentRuntime scr = scrTracker.getService();
         if ( scr != null )
         {
-        	scr.enableComponent(cd);
+            scr.enableComponent(cd).getValue();
         	Assert.assertTrue("Expected component enabled", scr.isComponentEnabled(cd));
         }
         else 
@@ -401,17 +401,17 @@
     	
     }
 
-    protected void disableAndCheck( ComponentConfigurationDTO cc )
+    protected void disableAndCheck( ComponentConfigurationDTO cc ) throws InvocationTargetException, InterruptedException
     {
     	ComponentDescriptionDTO cd = cc.description;
         disableAndCheck(cd);
     }
 
-	protected void disableAndCheck(ComponentDescriptionDTO cd) {
+	protected void disableAndCheck(ComponentDescriptionDTO cd) throws InvocationTargetException, InterruptedException {
 		ServiceComponentRuntime scr = scrTracker.getService();
         if ( scr != null )
         {
-        	scr.disableComponent(cd);
+        	scr.disableComponent(cd).getValue();
         	Assert.assertFalse("Expected component disabled", scr.isComponentEnabled(cd));
         }
         else 
@@ -420,7 +420,7 @@
         }
 	}
 
-	protected void disableAndCheck(String name) {
+	protected void disableAndCheck(String name) throws InvocationTargetException, InterruptedException {
 		ComponentDescriptionDTO cd = findComponentDescriptorByName(name);
 		disableAndCheck(cd);		
 	}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ConfigurationChangeTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ConfigurationChangeTest.java
index a868d93..89d6639 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ConfigurationChangeTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ConfigurationChangeTest.java
@@ -48,62 +48,62 @@
     }
 
     @Test
-    public void test_optional_single_dynamic()
+    public void test_optional_single_dynamic() throws Exception
     {
         String pid = "test_optional_single_dynamic";
         singleTest( pid, true );
     }
 
     @Test
-    public void test_required_single_dynamic()
+    public void test_required_single_dynamic() throws Exception
     {
         String pid = "test_required_single_dynamic";
         singleTest( pid, true );
     }
 
     @Test
-    public void test_optional_single_static()
+    public void test_optional_single_static() throws Exception
     {
         String pid = "test_optional_single_static";
         singleTest( pid, false );
     }
 
     @Test
-    public void test_required_single_static()
+    public void test_required_single_static() throws Exception
     {
         String pid = "test_required_single_static";
         singleTest( pid, false );
     }
 
     @Test
-    public void test_optional_single_dynamic_greedy()
+    public void test_optional_single_dynamic_greedy() throws Exception
     {
         String pid = "test_optional_single_dynamic_greedy";
         singleTest( pid, true );
     }
 
     @Test
-    public void test_required_single_dynamic_greedy()
+    public void test_required_single_dynamic_greedy() throws Exception
     {
         String pid = "test_required_single_dynamic_greedy";
         singleTest( pid, true );
     }
 
     @Test
-    public void test_optional_single_static_greedy()
+    public void test_optional_single_static_greedy() throws Exception
     {
         String pid = "test_optional_single_static_greedy";
         singleTest( pid, false );
     }
 
     @Test
-    public void test_required_single_static_greedy()
+    public void test_required_single_static_greedy() throws Exception
     {
         String pid = "test_required_single_static_greedy";
         singleTest( pid, false );
     }
 
-    private void singleTest(String pid, boolean dynamic)
+    private void singleTest(String pid, boolean dynamic) throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2" );
@@ -150,7 +150,7 @@
     }
 
     @Test
-    public void test_optional_multiple_dynamic()
+    public void test_optional_multiple_dynamic() throws Exception
     {
         String pid = "test_optional_multiple_dynamic";
         multipleTest( pid, true );
@@ -158,55 +158,55 @@
 
 
     @Test
-    public void test_required_multiple_dynamic()
+    public void test_required_multiple_dynamic() throws Exception
     {
         String pid = "test_required_multiple_dynamic";
         multipleTest( pid, true );
     }
 
     @Test
-    public void test_optional_multiple_static()
+    public void test_optional_multiple_static() throws Exception
     {
         String pid = "test_optional_multiple_static";
         multipleTest( pid, false );
     }
 
     @Test
-    public void test_required_multiple_static()
+    public void test_required_multiple_static() throws Exception
     {
         String pid = "test_required_multiple_static";
         multipleTest( pid, false );
     }
 
     @Test
-    public void test_optional_multiple_dynamic_greedy()
+    public void test_optional_multiple_dynamic_greedy() throws Exception
     {
         String pid = "test_optional_multiple_dynamic_greedy";
         multipleTest( pid, true );
     }
 
     @Test
-    public void test_required_multiple_dynamic_greedy()
+    public void test_required_multiple_dynamic_greedy() throws Exception
     {
         String pid = "test_required_multiple_dynamic_greedy";
         multipleTest( pid, true );
     }
 
     @Test
-    public void test_optional_multiple_static_greedy()
+    public void test_optional_multiple_static_greedy() throws Exception
     {
         String pid = "test_optional_multiple_static_greedy";
         multipleTest( pid, false );
     }
 
     @Test
-    public void test_required_multiple_static_greedy()
+    public void test_required_multiple_static_greedy() throws Exception
     {
         String pid = "test_required_multiple_static_greedy";
         multipleTest( pid, false );
     }
 
-    private void multipleTest(String pid, boolean dynamic)
+    private void multipleTest(String pid, boolean dynamic) throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2" );
@@ -255,7 +255,7 @@
  
     //I'm not sure what should happen in this case, asking on dev list.
 //    @Test
-    public void testSingleDynamicRequiredFactory() throws InvalidSyntaxException
+    public void testSingleDynamicRequiredFactory() throws Exception
     {
         String pid = "test_required_single_dynamic_factory";
         final String factoryPid = "factory_" + pid;
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ConfigurationComponentFactoryTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ConfigurationComponentFactoryTest.java
index 4564bcb..4d14a32 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ConfigurationComponentFactoryTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ConfigurationComponentFactoryTest.java
@@ -58,7 +58,7 @@
 
 
     @Test
-    public void test_non_spec_component_factory_with_factory_configuration() throws InvalidSyntaxException, IOException
+    public void test_non_spec_component_factory_with_factory_configuration() throws Exception
     {
         // this test is about non-standard behaviour of ComponentFactory services
 
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/Felix3680Test.java b/scr/src/test/java/org/apache/felix/scr/integration/Felix3680Test.java
index 55dec63..3882526 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/Felix3680Test.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/Felix3680Test.java
@@ -62,7 +62,7 @@
     }
 
     @Test
-    public void test_concurrent_reference_bindings()
+    public void test_concurrent_reference_bindings() throws Exception
     {
         final ComponentDescriptionDTO main = findComponentDescriptorByName( "org.apache.felix.scr.integration.components.felix3680.Main" );
         enableAndCheck(main);
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/Felix4350Test.java b/scr/src/test/java/org/apache/felix/scr/integration/Felix4350Test.java
index afa3d85..07f6a75 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/Felix4350Test.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/Felix4350Test.java
@@ -18,6 +18,8 @@
  */
 package org.apache.felix.scr.integration;
 
+import java.lang.reflect.InvocationTargetException;
+
 import junit.framework.TestCase;
 import org.apache.felix.scr.integration.components.Felix4350Component;
 import org.apache.felix.scr.integration.components.SimpleComponent;
@@ -47,36 +49,36 @@
     }
 
     @Test
-    public void test_unbind_while_activating_single_static()
+    public void test_unbind_while_activating_single_static() throws Exception
     {
         doTest("SingleStatic");
     }
 
     @Test
-    public void test_unbind_while_activating_single_dynamic()
+    public void test_unbind_while_activating_single_dynamic() throws Exception
     {
         doTest("SingleDynamic");
     }
 
     @Test
-    public void test_unbind_while_activating_multiple_dynamic()
+    public void test_unbind_while_activating_multiple_dynamic() throws Exception
     {
         doTest("MultipleDynamic");
     }
 
     @Test
-    public void test_unbind_while_activating_multiple_static_greedy()
+    public void test_unbind_while_activating_multiple_static_greedy() throws Exception
     {
         doTest("MultipleStaticGreedy");
     }
 
     @Test
-    public void test_unbind_while_activating_multiple_static_reluctant()
+    public void test_unbind_while_activating_multiple_static_reluctant() throws Exception
     {
         doTest("MultipleStaticReluctant");
     }
 
-    protected void doTest(String componentName)
+    protected void doTest(String componentName) throws Exception
     {
         ServiceRegistration dep1Reg = register(new SimpleComponent(), 0);
         ServiceRegistration dep2Reg = register(new SimpleComponent2(), 1000);
@@ -115,12 +117,21 @@
         Felix4350Component.check(2, 1, true); //n.b. counts are cumulative
     }
     
-    protected void asyncEnable( final ComponentDescriptionDTO cd )
+    protected void asyncEnable( final ComponentDescriptionDTO cd ) throws Exception
     {
     	new Thread( new Runnable() {
 
 			public void run() {
-				enableAndCheck( cd );
+				try
+                {
+                    enableAndCheck( cd );
+                }
+                catch (InvocationTargetException e)
+                {
+                }
+                catch (InterruptedException e)
+                {
+                }
 			}}).start();
     }
 
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/PersistentComponentFactoryTest.java b/scr/src/test/java/org/apache/felix/scr/integration/PersistentComponentFactoryTest.java
index b0eb3b8..e435e57 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/PersistentComponentFactoryTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/PersistentComponentFactoryTest.java
@@ -52,7 +52,7 @@
     }
 
     @Test
-    public void test_component_factory() throws InvalidSyntaxException
+    public void test_component_factory() throws Exception
     {
         final String componentname = "factory.component";
         final String componentfactory = "factory.component.factory";
@@ -76,7 +76,7 @@
 
 
     @Test
-    public void test_component_factory_disable_factory() throws InvalidSyntaxException
+    public void test_component_factory_disable_factory() throws Exception
     {
         // tests components remain alive after factory has been disabled
 
@@ -106,7 +106,7 @@
 
 
     @Test
-    public void test_component_factory_newInstance_failure() throws InvalidSyntaxException
+    public void test_component_factory_newInstance_failure() throws Exception
     {
         final String componentname = "factory.component";
         final String componentfactory = "factory.component.factory";
@@ -128,7 +128,7 @@
 
 
     @Test
-    public void test_component_factory_require_configuration() throws InvalidSyntaxException
+    public void test_component_factory_require_configuration() throws Exception
     {
         final String componentname = "factory.component.configuration";
         final String componentfactory = "factory.component.factory.configuration";
@@ -184,7 +184,7 @@
 
 
     @Test
-    public void test_component_factory_reference() throws InvalidSyntaxException
+    public void test_component_factory_reference() throws Exception
     {
         final String componentname = "factory.component.reference";
         final String componentfactory = "factory.component.factory.reference";
@@ -260,7 +260,7 @@
     }
 
     @Test
-    public void test_component_factory_referredTo() throws InvalidSyntaxException
+    public void test_component_factory_referredTo() throws Exception
     {
         //set up the component that refers to the service the factory will create.
         final String referringComponentName = "ComponentReferringToFactoryObject";
@@ -292,7 +292,7 @@
     }
 
     @Test
-    public void test_component_factory_with_target_filters() throws InvalidSyntaxException
+    public void test_component_factory_with_target_filters() throws Exception
     {
         final String componentfactory = "factory.component.reference.targetfilter";
         getConfigurationsDisabledThenEnable(componentfactory, 0, -1);
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java
index 2546f04..61809b5 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java
@@ -53,7 +53,7 @@
 
 
     @Test
-    public void test_optional_single_dynamic()
+    public void test_optional_single_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -167,7 +167,7 @@
 
 
     @Test
-    public void test_required_single_dynamic()
+    public void test_required_single_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1", 1 );
 
@@ -282,7 +282,7 @@
 
 
     @Test
-    public void test_optional_multiple_dynamic()
+    public void test_optional_multiple_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -411,7 +411,7 @@
 
 
     @Test
-    public void test_required_multiple_dynamic()
+    public void test_required_multiple_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -544,7 +544,7 @@
 
 
     @Test
-    public void test_required_multiple_dynamic_factory() throws InvalidSyntaxException
+    public void test_required_multiple_dynamic_factory() throws Exception
     {
         String name ="test_required_multiple_dynamic_factory"; //also pid
         final String factoryPid = "factory_" + name;
@@ -685,7 +685,7 @@
 
 
     @Test
-    public void test_optional_single_static()
+    public void test_optional_single_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -817,7 +817,7 @@
 
 
     @Test
-    public void test_required_single_static()
+    public void test_required_single_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -945,7 +945,7 @@
 
 
     @Test
-    public void test_optional_multiple_static()
+    public void test_optional_multiple_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -1089,7 +1089,7 @@
 
 
     @Test
-    public void test_required_multiple_static()
+    public void test_required_multiple_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -1227,7 +1227,7 @@
     }
 
     @Test
-    public void test_multi_service_bind_unbind_order()
+    public void test_multi_service_bind_unbind_order() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         final SimpleService2Impl srv2 = SimpleService2Impl.create( bundleContext, "srv2" );
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindTest.java
index 2be9ade..b944e64 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindTest.java
@@ -53,7 +53,7 @@
 
 
     @Test
-    public void test_optional_single_dynamic()
+    public void test_optional_single_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -167,7 +167,7 @@
 
 
     @Test
-    public void test_required_single_dynamic()
+    public void test_required_single_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -282,7 +282,7 @@
 
 
     @Test
-    public void test_optional_multiple_dynamic()
+    public void test_optional_multiple_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -411,7 +411,7 @@
 
 
     @Test
-    public void test_required_multiple_dynamic()
+    public void test_required_multiple_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -544,7 +544,7 @@
 
 
     @Test
-    public void test_required_multiple_dynamic_factory() throws InvalidSyntaxException
+    public void test_required_multiple_dynamic_factory() throws Exception
     {
         String name ="test_required_multiple_dynamic_factory"; //also pid
         final String factoryPid = "factory_" + name;
@@ -685,7 +685,7 @@
 
 
     @Test
-    public void test_optional_single_static()
+    public void test_optional_single_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -818,7 +818,7 @@
 
 
     @Test
-    public void test_required_single_static()
+    public void test_required_single_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -946,7 +946,7 @@
 
 
     @Test
-    public void test_optional_multiple_static()
+    public void test_optional_multiple_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -1090,7 +1090,7 @@
 
 
     @Test
-    public void test_required_multiple_static()
+    public void test_required_multiple_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
 
@@ -1228,7 +1228,7 @@
     }
 
     @Test
-    public void test_multi_service_bind_unbind_order()
+    public void test_multi_service_bind_unbind_order() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         final SimpleService2Impl srv2 = SimpleService2Impl.create( bundleContext, "srv2" );
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ServiceChangedTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ServiceChangedTest.java
index 52fd68f..08bfc9e 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ServiceChangedTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ServiceChangedTest.java
@@ -42,7 +42,7 @@
 
 
     @Test
-    public void test_optional_single_dynamic()
+    public void test_optional_single_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         String name = "test_optional_single_dynamic_target";
@@ -103,7 +103,7 @@
 
 
     @Test
-    public void test_required_single_dynamic()
+    public void test_required_single_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         String name = "test_required_single_dynamic_target";
@@ -162,7 +162,7 @@
 
 
     @Test
-    public void test_optional_multiple_dynamic()
+    public void test_optional_multiple_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         String name = "test_optional_multiple_dynamic_target";
@@ -225,7 +225,7 @@
 
 
     @Test
-    public void test_required_multiple_dynamic()
+    public void test_required_multiple_dynamic() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         String name = "test_required_multiple_dynamic_target";
@@ -288,7 +288,7 @@
 
 
     @Test
-    public void test_optional_single_static()
+    public void test_optional_single_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         String name = "test_optional_single_static_target";
@@ -359,7 +359,7 @@
 
 
     @Test
-    public void test_required_single_static()
+    public void test_required_single_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         String name = "test_required_single_static_target";
@@ -425,7 +425,7 @@
 
 
     @Test
-    public void test_optional_multiple_static()
+    public void test_optional_multiple_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         String name = "test_optional_multiple_static_target";
@@ -501,7 +501,7 @@
 
 
     @Test
-    public void test_required_multiple_static()
+    public void test_required_multiple_static() throws Exception
     {
         final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
         String name = "test_required_multiple_static_target";
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
index 5c4e6ba..9f542c3 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
@@ -43,7 +43,7 @@
 
 
     @Test
-    public void test_SimpleComponent_service()
+    public void test_SimpleComponent_service() throws Exception
     {
         final String pid = "ServiceComponent";
 
@@ -83,7 +83,7 @@
 
 
     @Test
-    public void test_DelayedSimpleComponent_service_single_use()
+    public void test_DelayedSimpleComponent_service_single_use() throws Exception
     {
         final String pid = "DelayedServiceComponent";
 
@@ -116,7 +116,7 @@
 
 
     @Test
-    public void test_DelayedSimpleComponent_service_multi_use()
+    public void test_DelayedSimpleComponent_service_multi_use() throws Exception
     {
         final String pid = "DelayedServiceComponent";
 
@@ -152,7 +152,7 @@
     }
 
     @Test
-    public void test_DelayedSimpleComponent_service_keep_instance() throws IOException
+    public void test_DelayedSimpleComponent_service_keep_instance() throws Exception
     {
         // configure SCR to keep instances